Skip to content
Snippets Groups Projects
Commit 4fca9156 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch 'merge-1.0.1' into 'master'

Merge 1.0.1

See merge request NCER-PD/scheduling-system!316
parents d15d9c8d 99f88a6c
No related branches found
No related tags found
1 merge request!316Merge 1.0.1
Pipeline #39745 passed
...@@ -6,6 +6,22 @@ smasch (1.1.0~alpha.0-1) unstable; urgency=low ...@@ -6,6 +6,22 @@ smasch (1.1.0~alpha.0-1) unstable; urgency=low
-- Piotr Gawron <piotr.gawron@uni.lu> Thu, 25 Feb 2021 17:00:00 +0200 -- Piotr Gawron <piotr.gawron@uni.lu> Thu, 25 Feb 2021 17:00:00 +0200
smasch (1.0.1-1) stable; urgency=low
* bug fix: gunicorn request length extended so dynamic table allows for more
columns (#381)
* bug fix: unfinish visit button was always disabled (#386)
* bug fix: generating documents for templates did not work for subjects
created before custom field was added to the study (#388)
* bug fix: readonly custom Date Field was improperly persisted in forms
(#383)
* bug fix: worker initials were not visible after changing appointments
calendar view from month to week (#377)
* bug fix: statics and npm files were not served properly when accessing by
docker
-- Piotr Gawron <piotr.gawron@uni.lu> Wed, 17 Mar 2021 10:00:00 +0200
smasch (1.0.0-1) stable; urgency=low smasch (1.0.0-1) stable; urgency=low
* backward incompatible: smasch is using python3 (#337) * backward incompatible: smasch is using python3 (#337)
......
...@@ -8,7 +8,18 @@ RUN pip install -r requirements.txt --default-timeout=180 -i https://pypi.lcsb.u ...@@ -8,7 +8,18 @@ RUN pip install -r requirements.txt --default-timeout=180 -i https://pypi.lcsb.u
ADD . /code/ ADD . /code/
RUN cp local_settings_ci.py smash/smash/local_settings.py RUN cp local_settings_ci.py smash/smash/local_settings.py
WORKDIR /code/smash WORKDIR /code/smash
ENV NODE_VERSION=12.6.0
RUN apt install -y curl
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
ENV NVM_DIR=/root/.nvm
RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION}
RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION}
RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION}
ENV PATH="/root/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}"
RUN node --version
RUN npm --version
RUN npm install
ENTRYPOINT [ "/bin/sh" ] ENTRYPOINT [ "/bin/sh" ]
CMD [ "manage.py runserver 0.0.0.0:8002" ] CMD [ "manage.py runserver 0.0.0.0:8888" ]
EXPOSE 8002 EXPOSE 8888
...@@ -8,7 +8,7 @@ User=smasch ...@@ -8,7 +8,7 @@ User=smasch
Group=smasch Group=smasch
WorkingDirectory=/usr/lib/smasch WorkingDirectory=/usr/lib/smasch
ExecStart=/usr/lib/smasch/env/bin/gunicorn -b :8888 --pid /run/smasch/pid smash.wsgi --error-logfile /var/log/smasch/gunicorn.log --log-level DEBUG --capture-output --limit-request-line 8192 ExecStart=/usr/lib/smasch/env/bin/gunicorn -b :8888 --pid /run/smasch/pid smash.wsgi --error-logfile /var/log/smasch/gunicorn.log --log-level DEBUG --capture-output --limit-request-line 16384
ExecReload=/bin/kill -s HUP $MAINPID ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true PrivateTmp=true
......
...@@ -13,21 +13,21 @@ services: ...@@ -13,21 +13,21 @@ services:
web: web:
build: . build: .
expose: expose:
- '8002' - '8888'
entrypoint: bash -c "sleep 5 entrypoint: bash -c "sleep 5
&& python manage.py makemigrations web && python manage.py makemigrations web
&& python manage.py migrate && python manage.py migrate
&& python manage.py migrate sessions && python manage.py migrate sessions
&& python manage.py collectstatic --noinput && python manage.py collectstatic --noinput
&& echo && echo && echo 'The server will start now...' && echo && echo && echo 'The server will start now...'
&& gunicorn -b 0.0.0.0:8002 smash.wsgi:application --access-logfile access.log --error-logfile error.log" && gunicorn -b 0.0.0.0:8888 smash.wsgi:application --access-logfile access.log --error-logfile error.log"
### To run the server through manage.py, use: ### To run the server through manage.py, use:
# && python manage.py runserver 0.0.0.0:8002" # && python manage.py runserver 0.0.0.0:8888"
### To run the verbose tests, uncomment: ### To run the verbose tests, uncomment:
# python manage.py test -v3" # python manage.py test -v3"
command: "" command: ""
ports: ports:
- "8002:8002" - "8888:8888"
volumes: volumes:
- static_files:/tmp/static/ - static_files:/tmp/static/
depends_on: depends_on:
......
...@@ -43,7 +43,7 @@ http { ...@@ -43,7 +43,7 @@ http {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_redirect off; proxy_redirect off;
proxy_pass http://web:8002; proxy_pass http://web:8888;
} }
} }
} }
...@@ -46,6 +46,6 @@ server { ...@@ -46,6 +46,6 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_redirect off; proxy_redirect off;
proxy_pass http://web:8002; proxy_pass http://web:8888;
} }
} }
...@@ -4,6 +4,8 @@ SECRET_KEY = 'Paste long random string here' # Insert long random string ...@@ -4,6 +4,8 @@ SECRET_KEY = 'Paste long random string here' # Insert long random string
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
SERVE_STATIC = True
# Database # Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
......
...@@ -26,23 +26,27 @@ def process_file(path_to_docx, path_to_new_docx, changes_to_apply): ...@@ -26,23 +26,27 @@ def process_file(path_to_docx, path_to_new_docx, changes_to_apply):
doc.save(path_to_new_docx) doc.save(path_to_new_docx)
def merge_files(files, path_to_new_docx): def merge_files(files, path_to_new_docx):
''' """
When combining templates into a new Document object, python-docx does not properly copy the information of the images, then Word is not able to locate the original content referred by the XML tag in the document. To fix this problem (see #234 ) the first file is loaded and the rest of templates are concatenated to this. This way, the original image content and rId match and the images are shown adequately. When combining templates into a new Document object, python-docx does not properly copy the information of the
images, then Word is not able to locate the original content referred by the XML tag in the document. To fix this
problem (see #234 ) the first file is loaded and the rest of templates are concatenated to this. This way, the
original image content and rId match and the images are shown adequately.
See issue #235 See issue #235
''' """
first_file = files[0] first_file = files[0]
files = files[1:] files = files[1:]
merged_document = Document(first_file) #first file merged_document = Document(first_file) # first file
if len(files) > 0: if len(files) > 0:
merged_document.add_page_break() merged_document.add_page_break()
for index, file in enumerate(files): #rest of files if any for index, file in enumerate(files): # rest of files if any
sub_doc = Document(file) sub_doc = Document(file)
if index < len(files) - 1: if index < len(files) - 1:
sub_doc.add_page_break() sub_doc.add_page_break()
for element in sub_doc.element.body: for element in sub_doc.element.body:
merged_document.element.body.append(element) merged_document.element.body.append(element)
merged_document.save(path_to_new_docx) merged_document.save(path_to_new_docx)
\ No newline at end of file
...@@ -158,8 +158,9 @@ class StudySubjectAddForm(StudySubjectForm): ...@@ -158,8 +158,9 @@ class StudySubjectAddForm(StudySubjectForm):
instance = super(StudySubjectAddForm, self).save(commit) instance = super(StudySubjectAddForm, self).save(commit)
# we can add custom values only after object exists in the database # we can add custom values only after object exists in the database
for field_type in CustomStudySubjectField.objects.filter(study=self.study): for field_type in CustomStudySubjectField.objects.filter(study=self.study):
self.instance.set_custom_data_value(field_type, get_study_subject_field_value(field_type, self[ if not field_type.readonly:
get_study_subject_field_id(field_type)])) self.instance.set_custom_data_value(field_type, get_study_subject_field_value(field_type, self[
get_study_subject_field_id(field_type)]))
return instance return instance
def build_screening_number(self, cleaned_data): def build_screening_number(self, cleaned_data):
...@@ -289,8 +290,9 @@ class StudySubjectEditForm(StudySubjectForm): ...@@ -289,8 +290,9 @@ class StudySubjectEditForm(StudySubjectForm):
def save(self, commit=True) -> StudySubject: def save(self, commit=True) -> StudySubject:
for field_type in CustomStudySubjectField.objects.filter(study=self.study): for field_type in CustomStudySubjectField.objects.filter(study=self.study):
self.instance.set_custom_data_value(field_type, get_study_subject_field_value(field_type, self[ if not field_type.readonly:
get_study_subject_field_id(field_type)])) self.instance.set_custom_data_value(field_type, get_study_subject_field_value(field_type, self[
get_study_subject_field_id(field_type)]))
return super(StudySubjectForm, self).save(commit) return super(StudySubjectForm, self).save(commit)
class Meta: class Meta:
......
...@@ -338,13 +338,13 @@ class MailTemplate(models.Model): ...@@ -338,13 +338,13 @@ class MailTemplate(models.Model):
"##S_ADDRESS##": study_subject.subject.address, "##S_ADDRESS##": study_subject.subject.address,
"##S_CITY##": study_subject.subject.city, "##S_CITY##": study_subject.subject.city,
"##S_COUNTRY##": str(study_subject.subject.country), "##S_COUNTRY##": str(study_subject.subject.country),
"##S_DIAGNOSIS_YEAR##": study_subject.get_custom_field_value('Year of diagnosis'), "##S_DIAGNOSIS_YEAR##": str(study_subject.get_custom_field_value('Year of diagnosis')),
"##S_DATE_ADDED##": date_to_str(study_subject.date_added, DATE_FORMAT_SHORT), "##S_DATE_ADDED##": date_to_str(study_subject.date_added, DATE_FORMAT_SHORT),
"##S_DATE_BORN##": date_born, "##S_DATE_BORN##": date_born,
"##S_DIAGNOSIS##": study_subject.get_custom_field_value('Diagnosis'), "##S_DIAGNOSIS##": str(study_subject.get_custom_field_value('Diagnosis')),
"##S_EMAIL##": str(study_subject.subject.email), "##S_EMAIL##": str(study_subject.subject.email),
"##S_SEX##": study_subject.subject.get_sex_display(), "##S_SEX##": study_subject.subject.get_sex_display(),
"##S_MPOWER_ID##": study_subject.get_custom_field_value('MPower ID'), "##S_MPOWER_ID##": str(study_subject.get_custom_field_value('MPower ID')),
"##S_ND_NUMBER##": study_subject.nd_number, "##S_ND_NUMBER##": study_subject.nd_number,
"##S_PHONE_NUMBER##": str(study_subject.subject.phone_number), "##S_PHONE_NUMBER##": str(study_subject.subject.phone_number),
"##S_PHONE_NUMBER_2##": str(study_subject.subject.phone_number_2), "##S_PHONE_NUMBER_2##": str(study_subject.subject.phone_number_2),
......
...@@ -117,7 +117,10 @@ ...@@ -117,7 +117,10 @@
startParam: "start_date", startParam: "start_date",
endParam: "end_date", endParam: "end_date",
dayRender: function (date, cell) { dayRender: function (date, cell) {
var element = document.createElement("div"); var element = dayHeaders[$(cell[0]).attr("data-date")];
if (element === undefined) {
element = document.createElement("div");
}
cell[0].appendChild(element); cell[0].appendChild(element);
dayHeaders[$(cell[0]).attr("data-date")] = element; dayHeaders[$(cell[0]).attr("data-date")] = element;
}, },
...@@ -146,7 +149,7 @@ ...@@ -146,7 +149,7 @@
if (event.status) { if (event.status) {
content += '<li>Status: ' + event.status + '</li>' content += '<li>Status: ' + event.status + '</li>'
} }
content += "</ul>"; content += "</ul>";
$(element).popover({ $(element).popover({
title: event.title, title: event.title,
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
<div class="col-md-6 form-group"> <div class="col-md-6 form-group">
<label class="col-sm-4 control-label"> <label class="col-sm-4 control-label">
{% if visFinished %} {% if visFinished %}
<i title="Only visits with one inmediate future visit (without appointments) can be unfinished." class="fa fa-info-circle"></i> <i title="Only visits with one immediate future visit (without appointments) can be unfinished." class="fa fa-info-circle"></i>
{% endif %} {% endif %}
Visit finished Visit finished
</label> </label>
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
{% if visFinished %} {% if visFinished %}
<div class="col-sm-1"> <div class="col-sm-1">
{% if "unfinish_visit" not in permissions %} {% if "delete_visit" not in permissions %}
<div title="You don't have permissions to unfinish visits." class="btn btn-block btn-warning disabled"> <div title="You don't have permissions to unfinish visits." class="btn btn-block btn-warning disabled">
<i class="fa fa-undo"></i> <i class="fa fa-undo"></i>
</div> </div>
......
...@@ -4,13 +4,14 @@ import io ...@@ -4,13 +4,14 @@ import io
from django.test import TestCase from django.test import TestCase
from docx import Document from docx import Document
from web.models import MailTemplate from web.models import MailTemplate, StudySubject, Language
from web.models.constants import MAIL_TEMPLATE_CONTEXT_APPOINTMENT, MAIL_TEMPLATE_CONTEXT_VISIT, \ from web.models.constants import MAIL_TEMPLATE_CONTEXT_APPOINTMENT, MAIL_TEMPLATE_CONTEXT_VISIT, \
MAIL_TEMPLATE_CONTEXT_SUBJECT, MAIL_TEMPLATE_CONTEXT_VOUCHER MAIL_TEMPLATE_CONTEXT_SUBJECT, MAIL_TEMPLATE_CONTEXT_VOUCHER, CUSTOM_FIELD_TYPE_TEXT
from web.models.custom_data import CustomStudySubjectField
from web.models.mail_template import DATE_FORMAT_SHORT from web.models.mail_template import DATE_FORMAT_SHORT
from web.tests.functions import create_language, get_resource_path, create_appointment, create_user, \ from web.tests.functions import create_language, get_resource_path, create_appointment, create_user, \
create_study_subject, \ create_study_subject, \
create_visit, create_voucher, create_worker, create_flying_team create_visit, create_voucher, create_worker, create_flying_team, get_test_study
class MailTemplateModelTests(TestCase): class MailTemplateModelTests(TestCase):
...@@ -100,19 +101,32 @@ class MailTemplateModelTests(TestCase): ...@@ -100,19 +101,32 @@ class MailTemplateModelTests(TestCase):
self.check_doc_contains(doc, [flying_team_name]) self.check_doc_contains(doc, [flying_team_name])
def test_apply_subject(self): def test_apply_subject(self):
template_name_french = "test_fr"
subject = create_study_subject() subject = create_study_subject()
subject_template_french = MailTemplate(name=template_name_french, language=self.french_language, doc = self.create_doc_for_subject(subject, self.french_language, MAIL_TEMPLATE_CONTEXT_SUBJECT)
context=MAIL_TEMPLATE_CONTEXT_SUBJECT, worker_name = str(self.user.worker)
template_file=self.template_file)
stream = io.BytesIO() self.check_doc_contains(doc, [worker_name, str(subject), str(subject.subject.country), subject.nd_number,
subject_template_french.apply(subject, self.user, stream) subject.type.name])
doc = Document(stream)
def test_apply_subject_with_non_existing_custom_field(self):
subject = create_study_subject()
field = CustomStudySubjectField.objects.create(name="Diagnosis", type=CUSTOM_FIELD_TYPE_TEXT,
study=get_test_study(), unique=True)
doc = self.create_doc_for_subject(subject, self.french_language, MAIL_TEMPLATE_CONTEXT_SUBJECT)
worker_name = str(self.user.worker) worker_name = str(self.user.worker)
self.check_doc_contains(doc, [worker_name, str(subject), str(subject.subject.country), subject.nd_number, self.check_doc_contains(doc, [worker_name, str(subject), str(subject.subject.country), subject.nd_number,
subject.type.name]) subject.type.name])
def create_doc_for_subject(self, subject: StudySubject, language: Language, context: str):
subject_template_french = MailTemplate(name="test_fr", language=language,
context=context,
template_file=self.template_file)
stream = io.BytesIO()
subject_template_french.apply(subject, self.user, stream)
doc = Document(stream)
return doc
def test_apply_voucher(self): def test_apply_voucher(self):
template_name_french = "test_without_language" template_name_french = "test_without_language"
subject = create_study_subject() subject = create_study_subject()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment