diff options
author | Andrea Lepori <alepori@student.ethz.ch> | 2021-07-23 18:07:47 +0200 |
---|---|---|
committer | Andrea Lepori <alepori@student.ethz.ch> | 2021-07-23 18:07:59 +0200 |
commit | c5789583a04c435acb460bae050f9387e67527cb (patch) | |
tree | eaa73777353a9669be5c57269cee67e1e35bdf07 | |
parent | export csv of users or document types (diff) | |
parent | add notification if user of group capi views document (diff) | |
download | scout-subs-0.3.tar.gz scout-subs-0.3.zip |
Merge branch 'dev'0.3
Diffstat (limited to '')
-rw-r--r-- | client/migrations/0007_groupsettings.py | 23 | ||||
-rw-r--r-- | client/migrations/0009_merge_20210723_1805.py | 14 | ||||
-rw-r--r-- | client/models.py | 234 | ||||
-rw-r--r-- | client/templates/client/index.html | 12 | ||||
-rw-r--r-- | client/views.py | 17 | ||||
-rw-r--r-- | server/templates/server/doc_list_readonly.html | 618 | ||||
-rw-r--r-- | server/templates/server/index.html | 31 | ||||
-rw-r--r-- | server/urls.py | 1 | ||||
-rw-r--r-- | server/views.py | 3195 | ||||
-rw-r--r-- | templates/registration/base_client.html | 6 | ||||
-rw-r--r-- | version.txt | 4 |
11 files changed, 2583 insertions, 1572 deletions
diff --git a/client/migrations/0007_groupsettings.py b/client/migrations/0007_groupsettings.py new file mode 100644 index 0000000..b5a23fa --- /dev/null +++ b/client/migrations/0007_groupsettings.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.2 on 2021-03-17 20:06 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('client', '0006_documenttype_max_instances'), + ] + + operations = [ + migrations.CreateModel( + name='GroupSettings', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('view_documents', models.BooleanField(default=False)), + ('group', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='auth.group')), + ], + ), + ] diff --git a/client/migrations/0009_merge_20210723_1805.py b/client/migrations/0009_merge_20210723_1805.py new file mode 100644 index 0000000..014ac28 --- /dev/null +++ b/client/migrations/0009_merge_20210723_1805.py @@ -0,0 +1,14 @@ +# Generated by Django 3.1.4 on 2021-07-23 16:05 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('client', '0007_groupsettings'), + ('client', '0008_usercode_avs_number'), + ] + + operations = [ + ] diff --git a/client/models.py b/client/models.py index 3d4e63d..db31194 100644 --- a/client/models.py +++ b/client/models.py @@ -1,115 +1,119 @@ -from django.db import models -from django.contrib.auth.models import User, Group -from datetime import datetime - -# Create your models here. - - -class DocumentType(models.Model): - enabled = models.BooleanField(default=False) - auto_sign = models.BooleanField(default=False) - group_private = models.BooleanField(default=False) - group = models.ForeignKey(Group, default=None, on_delete=models.CASCADE) - custom_group = models.BooleanField(default=False) - personal_data = models.BooleanField(default=False) - medical_data = models.BooleanField(default=False) - custom_data = models.BooleanField(default=False) - custom_message = models.BooleanField(default=False) - custom_message_text = models.CharField(default="", max_length=250) - staff_only = models.BooleanField(default=False) - max_instances = models.IntegerField(default=0) - name = models.CharField(default="", max_length=250) - - -class PersonalData(models.Model): - parent_name = models.CharField(default="", max_length=250) - via = models.CharField(default="", max_length=250) - cap = models.CharField(default="", max_length=250) - country = models.CharField(default="", max_length=250) - nationality = models.CharField(default="", max_length=250) - born_date = models.DateField(null=True, default=datetime.fromtimestamp(0)) - home_phone = models.CharField(default="", max_length=250) - phone = models.CharField(default="", max_length=250) - email = models.CharField(default="", max_length=250) - school = models.CharField(default="", max_length=250) - year = models.IntegerField(default=0) - avs_number = models.CharField(default="", max_length=250) - - -class MedicalData(models.Model): - emer_name = models.CharField(default="", max_length=250) - emer_relative = models.CharField(default="", max_length=250) - cell_phone = models.CharField(default="", max_length=250) - address = models.CharField(default="", max_length=250) - emer_phone = models.CharField(default="", max_length=250) - health_care = models.CharField(default="", max_length=250) - injuries = models.CharField(default="", max_length=250) - rc = models.CharField(default="", max_length=250) - rega = models.BooleanField(default=False) - medic_name = models.CharField(default="", max_length=250) - medic_phone = models.CharField(default="", max_length=250) - medic_address = models.CharField(default="", max_length=250) - sickness = models.CharField(default="", max_length=250) - vaccine = models.CharField(default="", max_length=250) - tetanus_date = models.DateField(null=True, default=datetime.fromtimestamp(0)) - allergy = models.CharField(default="", max_length=250) - drugs_bool = models.BooleanField(default=False) - drugs = models.CharField(default="", max_length=250) - misc_bool = models.BooleanField(default=False) - misc = models.CharField(default="", max_length=250) - vac_certificate = models.FileField(upload_to='documents/', null=True) - health_care_certificate = models.FileField(default=None, upload_to='documents/', null=True) - - -class Document(models.Model): - user = models.ForeignKey(User, default=None, on_delete=models.CASCADE) - group = models.ForeignKey(Group, default=None, on_delete=models.CASCADE) - code = models.IntegerField(default=0) - compilation_date = models.DateTimeField(auto_now_add=True) - status = models.CharField(default="", max_length=50) - document_type = models.ForeignKey( - DocumentType, default=None, on_delete=models.PROTECT) - - personal_data = models.ForeignKey( - PersonalData, default=None, on_delete=models.PROTECT, null=True) - - medical_data = models.ForeignKey( - MedicalData, default=None, on_delete=models.SET_NULL, null=True) - - signed_doc = models.FileField(default=None, upload_to='documents/', null=True) - - class Meta: - permissions = [ - ("approved", "The user is approved"), - ("staff", "The user is staff of the non primary group") - ] - - -class KeyVal(models.Model): - container = models.ForeignKey( - Document, db_index=True, on_delete=models.CASCADE) - key = models.CharField(max_length=240, db_index=True) - value = models.CharField(max_length=240, db_index=True) - - -class Keys(models.Model): - container = models.ForeignKey( - DocumentType, db_index=True, on_delete=models.CASCADE) - key = models.CharField(max_length=240, db_index=True) - - -class UserCode(models.Model): - user = models.ForeignKey(User, default=None, on_delete=models.CASCADE) - medic = models.ForeignKey(MedicalData, default=None, on_delete=models.PROTECT) - code = models.IntegerField(default=0) - parent_name = models.CharField(default="", max_length=250) - via = models.CharField(default="", max_length=250) - cap = models.CharField(default="", max_length=250) - country = models.CharField(default="", max_length=250) - nationality = models.CharField(default="", max_length=250) - born_date = models.DateField(null=True, default=datetime.fromtimestamp(0)) - home_phone = models.CharField(default="", max_length=250) - phone = models.CharField(default="", max_length=250) - school = models.CharField(default="", max_length=250) - year = models.IntegerField(default=0) - avs_number = models.CharField(default="", max_length=250)
\ No newline at end of file +from django.db import models
+from django.contrib.auth.models import User, Group
+from datetime import datetime
+
+# Create your models here.
+
+
+class DocumentType(models.Model):
+ enabled = models.BooleanField(default=False)
+ auto_sign = models.BooleanField(default=False)
+ group_private = models.BooleanField(default=False)
+ group = models.ForeignKey(Group, default=None, on_delete=models.CASCADE)
+ custom_group = models.BooleanField(default=False)
+ personal_data = models.BooleanField(default=False)
+ medical_data = models.BooleanField(default=False)
+ custom_data = models.BooleanField(default=False)
+ custom_message = models.BooleanField(default=False)
+ custom_message_text = models.CharField(default="", max_length=250)
+ staff_only = models.BooleanField(default=False)
+ max_instances = models.IntegerField(default=0)
+ name = models.CharField(default="", max_length=250)
+
+
+class PersonalData(models.Model):
+ parent_name = models.CharField(default="", max_length=250)
+ via = models.CharField(default="", max_length=250)
+ cap = models.CharField(default="", max_length=250)
+ country = models.CharField(default="", max_length=250)
+ nationality = models.CharField(default="", max_length=250)
+ born_date = models.DateField(null=True, default=datetime.fromtimestamp(0))
+ home_phone = models.CharField(default="", max_length=250)
+ phone = models.CharField(default="", max_length=250)
+ email = models.CharField(default="", max_length=250)
+ school = models.CharField(default="", max_length=250)
+ year = models.IntegerField(default=0)
+ avs_number = models.CharField(default="", max_length=250)
+
+
+class MedicalData(models.Model):
+ emer_name = models.CharField(default="", max_length=250)
+ emer_relative = models.CharField(default="", max_length=250)
+ cell_phone = models.CharField(default="", max_length=250)
+ address = models.CharField(default="", max_length=250)
+ emer_phone = models.CharField(default="", max_length=250)
+ health_care = models.CharField(default="", max_length=250)
+ injuries = models.CharField(default="", max_length=250)
+ rc = models.CharField(default="", max_length=250)
+ rega = models.BooleanField(default=False)
+ medic_name = models.CharField(default="", max_length=250)
+ medic_phone = models.CharField(default="", max_length=250)
+ medic_address = models.CharField(default="", max_length=250)
+ sickness = models.CharField(default="", max_length=250)
+ vaccine = models.CharField(default="", max_length=250)
+ tetanus_date = models.DateField(null=True, default=datetime.fromtimestamp(0))
+ allergy = models.CharField(default="", max_length=250)
+ drugs_bool = models.BooleanField(default=False)
+ drugs = models.CharField(default="", max_length=250)
+ misc_bool = models.BooleanField(default=False)
+ misc = models.CharField(default="", max_length=250)
+ vac_certificate = models.FileField(upload_to='documents/', null=True)
+ health_care_certificate = models.FileField(default=None, upload_to='documents/', null=True)
+
+
+class Document(models.Model):
+ user = models.ForeignKey(User, default=None, on_delete=models.CASCADE)
+ group = models.ForeignKey(Group, default=None, on_delete=models.CASCADE)
+ code = models.IntegerField(default=0)
+ compilation_date = models.DateTimeField(auto_now_add=True)
+ status = models.CharField(default="", max_length=50)
+ document_type = models.ForeignKey(
+ DocumentType, default=None, on_delete=models.PROTECT)
+
+ personal_data = models.ForeignKey(
+ PersonalData, default=None, on_delete=models.PROTECT, null=True)
+
+ medical_data = models.ForeignKey(
+ MedicalData, default=None, on_delete=models.SET_NULL, null=True)
+
+ signed_doc = models.FileField(default=None, upload_to='documents/', null=True)
+
+ class Meta:
+ permissions = [
+ ("approved", "The user is approved"),
+ ("staff", "The user is staff of the non primary group")
+ ]
+
+
+class KeyVal(models.Model):
+ container = models.ForeignKey(
+ Document, db_index=True, on_delete=models.CASCADE)
+ key = models.CharField(max_length=240, db_index=True)
+ value = models.CharField(max_length=240, db_index=True)
+
+
+class Keys(models.Model):
+ container = models.ForeignKey(
+ DocumentType, db_index=True, on_delete=models.CASCADE)
+ key = models.CharField(max_length=240, db_index=True)
+
+
+class UserCode(models.Model):
+ user = models.ForeignKey(User, default=None, on_delete=models.CASCADE)
+ medic = models.ForeignKey(MedicalData, default=None, on_delete=models.PROTECT)
+ code = models.IntegerField(default=0)
+ parent_name = models.CharField(default="", max_length=250)
+ via = models.CharField(default="", max_length=250)
+ cap = models.CharField(default="", max_length=250)
+ country = models.CharField(default="", max_length=250)
+ nationality = models.CharField(default="", max_length=250)
+ born_date = models.DateField(null=True, default=datetime.fromtimestamp(0))
+ home_phone = models.CharField(default="", max_length=250)
+ phone = models.CharField(default="", max_length=250)
+ school = models.CharField(default="", max_length=250)
+ year = models.IntegerField(default=0)
+ avs_number = models.CharField(default="", max_length=250)
+
+class GroupSettings(models.Model):
+ group = models.ForeignKey(Group, default=None, on_delete=models.CASCADE)
+ view_documents = models.BooleanField(default=False)
diff --git a/client/templates/client/index.html b/client/templates/client/index.html index 7f0edec..1fc6c73 100644 --- a/client/templates/client/index.html +++ b/client/templates/client/index.html @@ -17,6 +17,18 @@ {% if user.is_authenticated %} {% if user.is_staff or perms.client.approved %} + <div id="modal_capi" class="modal"> + <div class="modal-content"> + <h4>Attenzione</h4> + <p>Il tuo capo branca verrà notificato dell'accesso alla pagina dei documenti.<br> + Sei sicuro di voler continuare? + </p> + </div> + <div class="modal-footer"> + <a style="color:red" href="#!" class="modal-close waves-effect waves-green btn-flat">Annulla</a> + <a href="{% url 'doclistro' %}" class="modal-close waves-effect waves-green btn-flat">Continua</a> + </div> + </div> {% if not empty %} <ul class="collapsible"> {% for doc in docs %} diff --git a/client/views.py b/client/views.py index 6f8efb3..73a252a 100644 --- a/client/views.py +++ b/client/views.py @@ -1,6 +1,6 @@ from random import randint from django.contrib.auth.models import Group, Permission, User -from client.models import UserCode, Keys, DocumentType, Document, PersonalData, KeyVal, MedicalData +from client.models import GroupSettings, UserCode, Keys, DocumentType, Document, PersonalData, KeyVal, MedicalData from django.db.models import Q from django.http import HttpResponseRedirect, FileResponse, HttpResponse from django.contrib.auth.decorators import login_required @@ -17,6 +17,7 @@ import pytz def index(request): context = {} + group_view = False # check if user is logged if (request.user.is_authenticated): if not (request.user.is_staff or request.user.has_perm("client.approved")): @@ -39,6 +40,19 @@ def index(request): user_code = "U" + str(usercode.code) context = {"user_code": user_code} else: + # get user group + group = request.user.groups.values_list('name', flat=True)[0] + + # get group settings + settings = GroupSettings.objects.filter(group__name=group) + + # check if settings exists + if len(settings) == 0: + group_view = False + else: + # set settings value + group_view = settings[0].view_documents + # user action if request.method == "POST": # get document id @@ -123,6 +137,7 @@ def index(request): context = { "docs": out, "empty": len(out) == 0, + "group_view": group_view, } return render(request, 'client/index.html', context) diff --git a/server/templates/server/doc_list_readonly.html b/server/templates/server/doc_list_readonly.html new file mode 100644 index 0000000..42a52e8 --- /dev/null +++ b/server/templates/server/doc_list_readonly.html @@ -0,0 +1,618 @@ +{% extends 'registration/base_admin.html' %} + +{% block title %}Admin - Documenti{% endblock %} + +{% block breadcrumb %} + <a href="{% url 'server'%}" class="breadcrumb hide-on-med-and-down">Admin</a> + <a class="breadcrumb hide-on-med-and-down">Documenti</a> +{% endblock %} +{% block toolbar %} + <div class="nav-wrapper {{color}}"> + <ul> + <li> + <input id="select-all" type="checkbox" class="filled-in"/> + <label for="select-all"> + <a class="tooltipped" data-position="top" data-tooltip="(De)Seleziona tutti" onclick=""><i class="material-icons">select_all</i> + </label> + </a> + </li> + <li><a class="tooltipped modal-trigger" href="#modal3" data-position="top" data-tooltip="Scarica selezionati" Onclick="send('download')"><i class="material-icons">file_download</i></a></li> + </ul> + <ul class="right"> + <li><a class="tooltipped" data-position="top" data-tooltip="Pulisci filtri" Onclick="send('clear')"><i class="material-icons">clear</i></a></li> + <li><a href="#modal1" data-target="modal1" class="modal-trigger tooltipped" data-position="top" data-tooltip="Filtri"><i class="material-icons">filter_list</i></a></li> + </ul> + </div> +{% endblock %} + +{% block content %} + +<div id="modal3" class="modal"> + <div class="modal-content"> + <h5>Preparazione dei documenti</h5> + <div class="progress"> + <div id="progress_bar" class="indeterminate"></div> + <div class="determinate" style="width: 0%"></div> + </div> + <p id="progress_text"></p> + <div id="modal_close_button" class="modal-footer" hidden> + <a onclick="resetModal()" class="modal-close waves-effect waves-green btn-flat">Chiudi</a> + </div> + </div> +</div> + +<form id="selection" action="{% url 'doclistro' %}" method="post"> +{% csrf_token %} +<div id="modal1" class="modal"> + <div class="modal-content"> + <h5>Filtri</h5> + <div class="row"> + <div class="input-field col l3 s12"> + <label> + <input name="filter_hidden" type="checkbox" class="filled-in" {{hidden_check}}/> + <span style="color:black"><i class="material-icons left">archive</i>Archiviati</span> + </label> + </div> + <div class="input-field col l3 s12"> + <label> + <input name="filter_wait" type="checkbox" class="filled-in" {{wait_check}}/> + <span style="color:black"><i class="material-icons left">timelapse</i>In Attesa</span> + </label> + </div> + <div class="input-field col l3 s12"> + <label> + <input name="filter_selfsign" type="checkbox" class="filled-in" {{selfsign_check}}/> + <span style="color:black"><i class="material-icons left">assignment_turned_in</i>No firma</span> + </label> + </div> + <div class="input-field col l3 s12"> + <label> + <input name="filter_ok" type="checkbox" class="filled-in" {{ok_check}}/> + <span style="color:black"><i class="material-icons left">check</i>Approvati</span> + </label> + </div> + </div> + <br> + <div class="row"> + <ul class="collapsible"><li> + <div class="collapsible-header">Avanzati</div> + <div class="collapsible-body"><span> + <div class="row"> + <div class="input-field col s12"> + <label> + <input name="filter_signdoc" type="checkbox" class="filled-in" {{signdoc_check}}/> + <span style="color:black"><i class="material-icons left">check_circle</i>Visualizza solo approvati con firma allegata</span> + </label> + </div> + </div> + <br> + <br> + <div class = "row"> + <div class="input-field col l6 s12"> + <label for="newer">Più recenti di</label> + <input value="{{newer}}" name="newer" id="newer" type="text" class="datepicker"> + </div> + <div class="input-field col l6 s12"> + <label for="older">Più vecchi di</label> + <input value="{{older}}" name="older" id="older" type="text" class="datepicker"> + </div> + </div> + <div class = "row"> + <div class="col s12"> + <div id="chips_type" class="chips chips-placeholder chips-autocomplete"></div> + </div> + <div class="col s12"> + <div id="chips_owner" class="chips chips-placeholder chips-autocomplete "></div> + </div> + <div class="col s12"> + <div id="chips_groups" class="chips chips-placeholder chips-autocomplete "></div> + </div> + </div> + </span></div> + </li></ul> + </div> + </div> + <div class="modal-footer"> + <a href="#!" onclick="send('filter')" class="modal-close waves-effect waves-green btn-flat">Applica</a> + </div> +</div> +<input type="hidden" name="action" id="action"> +<input type="hidden" name="owner" id="owner"> +<input type="hidden" name="type" id="type"> +<input type="hidden" name="groups" id="groups"> +<ul class="collapsible"> + {% for doc in docs %} + <li> + <div class="collapsible-header"> + <label> + <input name={{doc.0.id}} type="checkbox" class="filled-in allselect"/> + <span></span> + </label> + {% if doc.0.status == "wait" %} + <i class="material-icons">timelapse</i> + {% elif doc.0.status == "ok" %} + {% if doc.0.signed_doc %} + <i class="material-icons">check_circle</i> + {% else %} + <i class="material-icons">check</i> + {% endif %} + {% elif doc.0.status == "archive" %} + <i class="material-icons">archive</i> + {% elif doc.0.status == "autosign" %} + <i class="material-icons">assignment_turned_in</i> + {% endif %} + {% if settings.DEBUG %} + {{doc.0.id}}: + {% endif %} + {{doc.0.document_type.name}} + <span class="badge" data-badge-caption="">{{doc.0.user.first_name}} {{doc.0.user.last_name}}</span> + </div> + <div class="collapsible-body"><span> + {% if doc.0.status == "ok" or doc.0.status == 'archive' %} + <a class="waves-effect waves-light btn {{color}}" onclick="send('k{{doc.0.id}}')"><i class="material-icons left">file_download</i> Scarica documento</a> + <br> + <br> + {% endif %} + <ul class="collection"> + {% if doc.0.status == 'ok' or doc.0.status == 'archive' %} + <li class="collection-item"> + <i class="material-icons left">confirmation_number</i>{{doc.0.code}} + </li> + {% endif %} + {% if doc.0.document_type.custom_group %} + <li class="collection-item"> + <i class="material-icons left">group_work</i>{{doc.0.group.name}} + </li> + {% endif %} + <li class="collection-item"> + <i class="material-icons left">send</i>{{doc.0.compilation_date}} + </li> + </ul> + <ul class="collapsible"> + {% if doc.0.document_type.personal_data %} + <li> + <div class="collapsible-header"> + <i class="material-icons">person</i>Dati personali + </div> + <div class="collapsible-body"><span> + <div class="row"> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.0.user.first_name}}" id="first_name" type="text" > + <label for="first_name">Nome</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.0.user.last_name}}" id="last_name" type="text" > + <label for="last_name">Cognome</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.born_date}}" id="birth_date" type="text"> + <label for="birth_date">Data di nascita</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.4}}" id="branca" type="text"> + <label for="branca">Branca</label> + </div> + <div class="input-field col l8 s12"> + <input disabled value="{{doc.2.parent_name}}" id="parent_name" type="text" > + <label for="parent_name">Nome dei genitori</label> + </div> + <div class="input-field col l12 s12"> + <input value="{{doc.2.via}}" disabled id="via" type="text" > + <label for="via">Via e numero</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.cap}}" name="cap" id="cap" type="text" > + <label for="cap">CAP</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.country}}" name="country" id="country" type="text" > + <label for="country">Paese</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.nationality}}" name="nationality" id="nationality" type="text" > + <label for="nationality">Nazionalità</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.phone}}" name="phone" id="phone" type="text" > + <label for="phone">Cellulare</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.home_phone}}" name="home_phone" id="home_phone" type="text" > + <label for="home_phone">Telefono di casa</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.email}}" name="email" id="email" type="text" > + <label for="email">Email</label> + </div> + <div class="input-field col l8 s12"> + <input disabled value="{{doc.2.school}}" name="school" id="school" type="text" > + <label for="school">Scuola frequentata</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.2.year}}" name="year" id="year" type="text" > + <label for="year">Classe</label> + </div> + </div> + </span></div> + </li> + {% endif %} + {% if doc.0.document_type.medical_data %} + <li> + <div class="collapsible-header"> + {% if doc.0.medical_data %} + <i class="material-icons">healing</i>Dati medici + {% else %} + <i class="material-icons">healing</i><del>Dati medici</del> + {% endif %} + </div> + {% if doc.0.medical_data %} + <div class="collapsible-body"><span> + <div class="row"> + <div class="col s12"> + <h6>Persona di contatto in caso di necessità</h6> + </div> + </div> + <div class="row"> + <div class="input-field col l6 s12"> + <input disabled name="emer_name" value="{{doc.3.emer_name}}" id="emer_name" type="text" > + <label for="emer_name">Nome e cognome</label> + </div> + <div class="input-field col l3 s12"> + <input disabled name="emer_relative" value="{{doc.3.emer_relative}}" id="emer_relative" type="text" > + <label for="emer_releative">Parentela</label> + </div> + <div class="input-field col l3 s12"> + <input disabled name="cell_phone" value="{{doc.3.cell_phone}}" id="cellphone" type="text" > + <label for="cell_phone">Cellulare</label> + </div> + <div class="input-field col l9 s12"> + <input disabled value="{{doc.3.address}}" name="address" id="address" type="text" > + <label for="address">Indirizzo completo</label> + </div> + <div class="input-field col l3 s12"> + <input disabled value="{{doc.3.emer_phone}}" name="emer_phone" id="emer_phone" type="text" > + <label for="emer_phone">Telefono di casa</label> + </div> + </div> + <div class="row"> + <div class="col s12"> + <h6>Assicurazione</h6> + </div> + </div> + <div class="row"> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.3.health_care}}" name="health_care" id="health_care" type="text" > + <label for="health_care">Cassa Malati</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.3.injuries}}" name="injuries" id="injuries" type="text" > + <label for="injuries">Infortuni</label> + </div> + <div class="input-field col l4 s12"> + <input disabled value="{{doc.3.rc}}" name="rc" id="rc" type="text" > + <label for="rc">Responsabilità civile</label> + </div> + </div> + <div class="row"> + <div class="switch col s12"> + È sostenitore REGA + <label> + No + <input disabled name="rega" type="checkbox" {% if doc.3.rega %}checked="checked"{%endif%}> + <span class="lever"></span> + Si + </label> + </div> + </div> + <div class="row"> + <div class="col s12"> + <h6>Medico di famiglia</h6> + </div> + <div class="input-field col l6 s12"> + <input disabled value="{{doc.3.medic_name}}" name="medic_name" id="medic_name" type="text" > + <label for="medic_name">Nome e cognome</label> + </div> + <div class="input-field col l6 s12"> + <input disabled value="{{doc.3.medic_phone}}" name="medic_phone" id="medic_phone" type="text" > + <label for="medic_phone">Telefono studio</label> + </div> + <div class="input-field col l12 s12"> + <input disabled value="{{doc.3.medic_address}}" name="medic_address" id="medic_address" type="text" > + <label for="medic_address">Indirizzo completo</label> + </div> + </div> + <div class="row"> + <div class="col s12"> + <h6>Scheda medica personale</h6> + </div> + <div class="input-field col s12"> + <input disabled value="{{doc.3.sickness}}" name="sickness" id="sickness" type="text"> + <label for="sickness">Principali malattie avute</label> + </div> + <div class="input-field col l8 s12"> + <input disabled value="{{doc.3.vaccine}}" name="vaccine" id="vaccine" type="text"> + <label for="vaccine">Vacinazioni fatte</label> + </div> + <div class="input-field col l4 s12"> + <label for="tetanus_date">Ultima vacinazione contro il tetano</label> + <input disabled value="{{doc.3.tetanus_date}}" name="tetanus_date" id="tetanus_date" type="text"> + </div> + <div class="input-field col s12"> + <input disabled value="{{doc.3.allergy}}" name="allergy" id="allergy" type="text"> + <label for="allergy">Allergie particolari/Intolleraze alimentari</label> + </div> + <div class="switch col s12"> + Deve assumere regolarmente medicamenti + <label> + No + <input disabled name="drugs_bool" type="checkbox" {% if doc.3.drugs_bool %}checked="checked"{%endif%}> + <span class="lever"></span> + Si + </label> + </div> + <div class="input-field col s12"> + <input disabled value="{{doc.3.drugs}}" name="drugs" id="drugs" type="text"> + <label for="drugs">Se sì quali, in che dosi e prescrizioni</label> + </div> + <div class="switch col s12"> + Informazioni particolari sullo stato di salute: (postumi di operazioni, incidenti, malattie, disturbi fisici) + <label> + No + <input disabled name="misc_bool" type="checkbox" {% if doc.3.misc_bool %}checked="checked"{%endif%}> + <span class="lever"></span> + Si + </label> + </div> + <div class="input-field col s12"> + <input disabled value="{{doc.3.misc}}" name="misc" id="misc" type="text"> + <label for="misc">Se sì quali</label> + </div> + </span></div> + {% endif %} + </li> + {% endif %} + {% if doc.0.document_type.custom_data %} + <li> + <div class="collapsible-header"> + <i class="material-icons">add_circle_outline</i>Dati aggiuntivi + </div> + <div class="collapsible-body"><span> + <table class="striped"> + <tbody> + {% for key in doc.1 %} + <tr> + <td>{{key.key}}</td> + <td>{{key.value}}</td> + </tr> + {% endfor %} + </tbody> + </table> + </span></div> + </li> + {% endif %} + {% if doc.0.document_type.medical_data %} + <li> + <div class="collapsible-header"> + <i class="material-icons">attach_file</i>Allegati + </div> + <div class="collapsible-body"><span> + <div class="row"> + <div class="col s12"> + <div class="card"> + <div class="card-image"> + {% if doc.5 %}<img class="lazyload" data-src="{{ doc.5 }}">{% endif %} + </div> + </div> + </div> + </div> + <div class="row"> + <div class="col s12"> + <div class="card"> + <div class="card-image"> + {% if doc.6 %}<img class="lazyload" data-src="{{ doc.6 }}">{% endif %} + </div> + </div> + </div> + </div> + <div class="row"> + <div class="col s12"> + <div class="card"> + <div class="card-image"> + {% if doc.7 %}<img class="lazyload" data-src="{{ doc.7 }}">{% endif %} + </div> + </div> + </div> + </div> + </span></div> + </li> + {% endif %} + </ul> + </span></div> + </li> + {% endfor %} +</ul> +</form> +{% endblock %} + +{%block script%} +$(document).ready(function(){ + $('.collapsible').collapsible(); + $('#modal1').modal(); + $('#modal2').modal(); + $('#modal3').modal({"dismissible": false}); + $('.datepicker').datepicker(options); + {% if error %} + M.toast({html: '{{ error_text}}', classes: 'orange'}) + {% endif %} + {% if task_id %} + $('#modal3').modal('open'); + update(); + document.getElementById('progress_bar').className = "determinate"; + {% endif %} + lazyload(); +}); + +function resetModal() { + $('#modal3').modal('close'); + document.getElementById('progress_bar').className = "indeterminate"; + document.getElementById("modal_close_button").hidden = true; + document.getElementById('progress_text').innerHTML = ""; +} + +$('.chips').chips(); +$('#chips_type').chips({ + placeholder: 'Tipo', + secondaryPlaceholder: '+Altro tipo', + autocompleteOptions: { + data: { + {% for t in types %} + '{{t.name}}': null, + {% endfor %} + }, + limit: Infinity, + minLength: 0 + }, + data: [ + {% for d in chips_type %} + {tag: '{{d}}'}, + {% endfor %} + ] +}); +$('#chips_owner').chips({ + placeholder: 'Utente', + secondaryPlaceholder: '+Altro utente', + autocompleteOptions: { + data: { + {% for user in users %} + '{{user.username}} ({{user.first_name}} {{user.last_name}})': null, + {% endfor %} + }, + limit: Infinity, + minLength: 0 + }, + data: [ + {% for d in chips_owner %} + {tag: '{{d}}'}, + {% endfor %} + ] +}); +$('#chips_groups').chips({ + placeholder: 'Gruppo', + secondaryPlaceholder: '+Altro gruppo', + autocompleteOptions: { + data: { + {% for g in groups %} + '{{g}}': null, + {% endfor %} + }, + limit: Infinity, + minLength: 0 + }, + data: [ + {% for g in chips_groups %} + {tag: '{{g}}'}, + {% endfor %} + ] +}); + +function update() { + var box = document.getElementById('progress_text'); + var bar = document.getElementById('progress_bar'); + {% if task_id %} + var url = '{% url "progress" %}' + '?job=' + '{{task_id}}'; + {% else %} + var url = '{% url "progress" %}'; + {% endif %} + fetch(url).then(function(response) { + response.json().then(function(data) { + if (data[0] == data[1]) { + if (data[2]) { + bar.className = "indeterminate"; + url = '{% url "progress" %}' + '?job=' + '{{task_id}}' + '&download=true'; + box.innerHTML = "Il download dovrebbe partire automaticamente. Nel caso non succedesse cliccare il seguente <a id='downloadLink' href=" + url + ">link</a>"; + document.getElementById("modal_close_button").hidden = false; + document.getElementById('downloadLink').click(); + } else { + bar.style.width = "100%"; + box.innerHTML = "Impacchettamento documenti..."; + setTimeout(update, 500, url); + } + } else { + box.innerHTML = data[0] + "/" + data[1]; + bar.style.width = data[0]/data[1]*100 + "%"; + setTimeout(update, 500, url); + } + }); + }); +} + +function send(id) { + var form = document.getElementById('selection') + var action = document.getElementById('action') + var owner = document.getElementById('owner') + var type = document.getElementById('type') + var groups = document.getElementById('groups') + var chips_owner = M.Chips.getInstance(document.getElementById('chips_owner')); + var chips_type = M.Chips.getInstance(document.getElementById('chips_type')); + var chips_groups = M.Chips.getInstance(document.getElementById('chips_groups')); + var type_array = [] + var owner_array = [] + var groups_array = [] + + for (i=0; i < chips_owner.chipsData.length; i++) { + owner_array.push(chips_owner.chipsData[i].tag) + } + + for (i=0; i < chips_type.chipsData.length; i++) { + type_array.push(chips_type.chipsData[i].tag) + } + + for (i=0; i < chips_groups.chipsData.length; i++) { + groups_array.push(chips_groups.chipsData[i].tag) + } + + action.setAttribute('value', id); + owner.setAttribute('value', owner_array.join("^|")) + type.setAttribute('value', type_array.join("^|")) + groups.setAttribute('value', groups_array.join("^|")) + form.submit() +} + +$('#select-all').click(function(event) { + if(this.checked) { + // Iterate each checkbox + $('.allselect').each(function() { + this.checked = true; + }); + } else { + $('.allselect').each(function() { + this.checked = false; + }); + } +}); + +var options = { + showClearBtn: true, + container: document.getElementById('main'), + yearRange:100, + format:'dd mmmm yyyy', + i18n: { + months: [ 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre' ], + monthsShort: [ 'gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic' ], + weekdays: [ 'domenica', 'lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato' ], + weekdaysShort: [ 'dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab' ], + weekdaysAbbrev: [ 'D', 'L', 'M', 'M', 'G', 'V', 'S' ], + today: 'Oggi', + clear: 'Cancella', + close: 'Chiudi', + cancel: 'Annulla', + firstDay: 1, + format: 'dddd d mmmm yyyy', + formatSubmit: 'yyyy/mm/dd', + labelMonthNext: 'Mese successivo', + labelMonthPrev: 'Mese precedente', + labelMonthSelect: 'Seleziona un mese', + labelYearSelect: 'Seleziona un anno' + } +} +{% endblock %}
\ No newline at end of file diff --git a/server/templates/server/index.html b/server/templates/server/index.html index de28169..d8a13f2 100644 --- a/server/templates/server/index.html +++ b/server/templates/server/index.html @@ -56,6 +56,23 @@ {% endif %} <div class="card large"> <div class="card-content"> + <form id="form" action="{% url 'server'%}" method="post"> + {% csrf_token %} + <div class="row"> + <div class="col s12"> + <div id="select_switch" class="switch col s12"> + Documenti visibili ad aggiunti<br class="hide-on-med-and-up"> + <label> + No + <input onclick="execute_confirm()" name="doc_view" type="checkbox" {{doc_view_check}}> + <span class="lever"></span> + Si + </label> + </div> + <a style="display: none" id="send_button" class="waves-effect waves-light btn green" onclick="form.submit()"><i class="material-icons left">check</i> Applica</a> + </div> + </div> + </form> <ul class="collection"> {% for doctype in docs %} <li class="collection-item"> @@ -97,4 +114,18 @@ </div> </div> </div> +{% endblock %} + +{% block script %} +function execute_confirm() { + var selection = document.getElementById('select_switch') + var button = document.getElementById('send_button') + selection.style.display = "none" + button.style.display = "inline-block" + {% if doc_view_check == 'checked="checked"'%} + button.innerHTML = "Applica (gli aggiunti <b>NON</b> potranno vedere i documenti)" + {% else %} + button.innerHTML = "Applica (gli aggiunti <b>POTRANNO</b> vedere i documenti)" + {% endif %} +} {% endblock %}
\ No newline at end of file diff --git a/server/urls.py b/server/urls.py index 5ede527..5ff9eba 100644 --- a/server/urls.py +++ b/server/urls.py @@ -11,6 +11,7 @@ urlpatterns = [ path('doccreate', views.doccreate, name='doccreate'), path('docedit', views.docedit, name='docedit'), path('doclist', views.doclist, name='doclist'), + path('doclistro', views.doclist_readonly, name='doclistro'), path('docapprove', views.docapprove, name='docapprove'), path('docupload', views.upload_doc, name='docupload'), path('docpreview', views.docpreview, name='docpreview'), diff --git a/server/views.py b/server/views.py index 6367c0c..1cf3ac7 100644 --- a/server/views.py +++ b/server/views.py @@ -1,1454 +1,1741 @@ -from django.shortcuts import render -from client.models import MedicalData, UserCode, Keys, DocumentType, Document, KeyVal -from django.contrib.auth.models import Group, Permission, User -from django.db.models import Q -from django.http import HttpResponseRedirect, FileResponse, HttpResponse -from django.db.models.deletion import ProtectedError -from django.template.loader import get_template -from django.conf import settings -from django.contrib.admin.views.decorators import staff_member_required -from django.contrib.auth.decorators import user_passes_test -from django.contrib.contenttypes.models import ContentType -from django.contrib.sessions.backends.db import SessionStore -from django import template - -import csv -import dateparser -from datetime import datetime -from datetime import timedelta -import pytz -import pdfkit -from io import BytesIO -import os -import base64 -from PIL import Image, UnidentifiedImageError -import zipfile -import json -import threading -import random - -# custom staff check function for non primary group staff members -def isStaff(user): - if user.is_staff: - return True - if user.has_perm("client.staff"): - return True - return False - -@user_passes_test(isStaff) -def index(request): - context = {} - # primary group name + object - parent_group = request.user.groups.values_list('name', flat=True)[ - 0] - group = Group.objects.get(name=parent_group) - # users from younger to older - users = User.objects.filter(groups__name=parent_group).order_by("-id") - users_out = [] - - # only send part of the user data, only if user is approved - for user in users: - if not user.has_perm("client.approved") and not user.is_staff: - continue - - users_out.append([user.username, user.first_name, - user.last_name]) - - # if user is staff of not primary show only public types - if request.user.is_staff: - public_types = DocumentType.objects.filter( - Q(group_private=False) | Q(group=group) & Q(enabled=True)).order_by("-id") - else: - public_types = DocumentType.objects.filter( - Q(group_private=False) & Q(enabled=True)).order_by("-id") - - # count documents of that type to show statistics - docs = [] - for doc in public_types: - doc_count = str(len(Document.objects.filter(document_type=doc))) - ref_docs_archived = len(Document.objects.filter(document_type=doc, status="archive")) - if ref_docs_archived > 0: - doc_count += "-" + str(ref_docs_archived) - if doc.max_instances != 0: - doc_count += "/" + str(doc.max_instances) - docs.append([doc, doc_count]) - - # don't list users if user is staff of not primary - if request.user.is_staff: - context = { - 'docs': docs, - 'users': users_out, - } - else: - context = { - 'docs': docs, - } - return render(request, 'server/index.html', context) - - -@staff_member_required -def uapprove(request): - context = {} - data = [] - if request.method == "POST": - # get group name and obj - parent_group = request.user.groups.values_list('name', flat=True)[ - 0] - group = Group.objects.get(name=parent_group) - - # get permission object - permission = Permission.objects.get(codename='approved') - - # parse text to array - data = request.POST["codes"] - data.replace("\r", "") - data = data.split("\n") - # check if format is right - for i in range(len(data)): - if not data[i].startswith("U"): - data[i] = data[i] + " - Formato errato" - elif not data[i][1:].isdigit(): - data[i] = data[i] + " - Formato errato" - elif int(data[i][1:]) < 100000 or int(data[i][1:]) > 999999: - data[i] = data[i] + " - Formato errato" - elif len(UserCode.objects.filter(code=data[i][1:])) == 0: - data[i] = data[i] + " - Invalido" - else: - user = UserCode.objects.filter(code=data[i][1:])[0].user - user.user_permissions.add(permission) - # if user not in any group add to the same group as staff - if len(user.groups.values_list('name', flat=True)) == 0: - user.groups.add(group) - data[i] = data[i] + " - Ok" - else: - if user.groups.values_list('name', flat=True)[0] == parent_group: - # if user already in group do nothing - data[i] = data[i] + " - Ok" - else: - # if user in another group notify staff of group change - user.groups.clear() - user.groups.add(group) - data[i] = data[i] + " - Ok, cambio branca" - - context = { - 'messages': data, - 'empty': len(data) == 0, - } - - return render(request, 'server/approve_user.html', context) - - -@user_passes_test(isStaff) -def docapprove(request): - context = {} - data = [] - - # group name and obj - parent_group = request.user.groups.values_list('name', flat=True)[ - 0] - group = Group.objects.get(name=parent_group) - - # if user not staff of primary has only controll of non primary groups - if request.user.is_staff: - groups = request.user.groups.values_list('name', flat=True) - else: - groups = request.user.groups.values_list('name', flat=True)[1:] - - if request.method == "POST": - # parse text in array - data = request.POST["codes"] - data.replace("\r", "") - data = data.split("\n") - # check if code valid - for i in range(len(data)): - if not data[i].isdigit(): - data[i] = data[i] + " - Formato errato" - elif int(data[i]) < 100000 or int(data[i]) > 999999: - data[i] = data[i] + " - Formato errato" - elif len(Document.objects.filter(code=data[i])) == 0: - data[i] = data[i] + " - Invalido" - elif Document.objects.filter(code=data[i])[0].group.name not in groups: - # check if user has permission to approve document - data[i] = data[i] + " - Invalido" - else: - document = Document.objects.filter(code=data[i])[0] - if document.status == 'ok': - # do nothing document already approved - data[i] = data[i] + " - Già approvato" - else: - document.status = 'ok' - document.save() - data[i] = data[i] + " - Ok" - - context = { - 'messages': data, - 'empty': len(data) == 0, - } - - return render(request, 'server/approve_doc.html', context) - - -@staff_member_required -def ulist(request): - context = {} - # group name and obj - parent_group = request.user.groups.values_list('name', flat=True)[0] - group = Group.objects.get(name=parent_group) - - if request.method == "POST": - # request to download document - if request.POST["action"][0] == 'f': - document = Document.objects.get(id=request.POST["action"][1:]) - # check if user has permission to view document - if document.group == group: - vac_file = "" - health_file = "" - sign_doc_file = "" - - # prepare pictures in base64 - if document.medical_data: - if document.medical_data.vac_certificate.name: - with open(document.medical_data.vac_certificate.name, 'rb') as image_file: - vac_file = base64.b64encode( - image_file.read()).decode() - - if document.medical_data.health_care_certificate.name: - with open(document.medical_data.health_care_certificate.name, 'rb') as image_file: - health_file = base64.b64encode( - image_file.read()).decode() - if document.signed_doc: - with open(document.signed_doc.name, 'rb') as image_file: - sign_doc_file = base64.b64encode( - image_file.read()).decode() - - # get template and build context - template = get_template('server/download_doc.html') - doc = [document, KeyVal.objects.filter( - container=document), document.personal_data, document.medical_data, parent_group] - context = {'doc': doc, 'vac': vac_file, - 'health': health_file, 'sign_doc_file': sign_doc_file} - # render context - html = template.render(context) - # render pdf using wkhtmltopdf - pdf = pdfkit.from_string(html, False) - result = BytesIO(pdf) - result.seek(0) - return FileResponse(result, filename=document.user.username+"_"+document.document_type.name+".pdf") - - # deapprove user - elif request.POST["action"][0] == 'd': - user = User.objects.get(id=request.POST["action"][1:]) - # check if user has permission to deapprove user - if user.groups.all()[0] == group: - content_type = ContentType.objects.get_for_model(Document) - permission = Permission.objects.get( - content_type=content_type, codename="approved") - user.user_permissions.remove(permission) - return HttpResponseRedirect("ulist") - # make user "capo" - elif request.POST["action"][0] == 'c': - user = User.objects.get(id=request.POST["action"][1:]) - capi = Group.objects.get(name="capi") - # check if user has permission to modify - if user.groups.all()[0] == group: - if "capi" in user.groups.values_list('name', flat=True): - # remove group - user.groups.remove(capi) - else: - # add group - user.groups.add(capi) - return HttpResponseRedirect("ulist") - - # list users with their documents - users = list(User.objects.filter( - groups__name=parent_group).filter(groups__name="capi").order_by("first_name")) - users += list(User.objects.filter( - groups__name=parent_group).exclude(groups__name="capi").order_by("first_name")) - out = [] - for user in users: - # list only approved users - if not user.has_perm("client.approved") and not user.is_staff: - continue - - usercode = UserCode.objects.filter(user=user)[0] - # get all user documents - documents = Document.objects.filter(Q(user=user) & ~Q( - status='archive') & Q(group__name=parent_group)) - - # generate link for images - vac_file = "" - health_file = "" - sign_doc_file = "" - if usercode.medic: - if usercode.medic.vac_certificate.name: - vac_file = "/server/media/" + str(usercode.id) + "/vac_certificate/usercode" - - if usercode.medic.health_care_certificate.name: - health_file = "/server/media/" + str(usercode.id) + "/health_care_certificate/usercode" - - out.append([user, usercode, parent_group, - documents, vac_file, health_file, "capi" in user.groups.values_list('name',flat = True)]) - context = {'users': out} - return render(request, 'server/user_list.html', context) - - -@user_passes_test(isStaff) -def doctype(request): - context = {} - - # error variables to throw at user - error = False - error_text = "" - - # init checkboxes - public = True - selfsign = True - hidden = False - personal = True - medic = True - custom = True - message = True - group_bool = True - public_check = 'checked="checked"' - selfsign_check = 'checked="checked"' - hidden_check = 'checked="checked"' - personal_check = 'checked="checked"' - medic_check = 'checked="checked"' - custom_check = 'checked="checked"' - message_check = 'checked="checked"' - group_check = 'checked="checked"' - - # if user not staff of primary get only non primary groups - if request.user.is_staff: - parent_groups = request.user.groups.values_list('name', flat=True) - else: - parent_groups = request.user.groups.values_list('name', flat=True)[ - 1:] - - if request.method == "POST": - selected = [] - - # check if request to edit - if request.POST["action"][0] == 'e': - document_type = DocumentType.objects.get(id=request.POST["action"][1:]) - - # check if user has permission on the document - if document_type.group.name not in parent_groups: - return - - enabled_check = 'checked="checked"' if document_type.enabled else "" - sign_check = 'checked="checked"' if not document_type.auto_sign else "" - custom_message_check = 'checked="checked"' if document_type.custom_message else "" - staff_only_check = 'checked="checked"' if document_type.staff_only else "" - private_check = 'checked="checked"' if document_type.group_private else "" - - context = { - 'doc': document_type, - "group": document_type.group.name, - "enabled_check": enabled_check, - "private_check": private_check, - "sign_check": sign_check, - "staff_only_check": staff_only_check, - "custom_message_check": custom_message_check, - } - - return docedit_wrapper(request, context) - - # check if request to download - elif request.POST["action"][0] == 'd': - document_type = DocumentType.objects.get(id=request.POST["action"][1:]) - - # check if user has permission on the document - if document_type.group.name not in parent_groups: - return - - docs = Document.objects.filter(document_type=document_type) - - # get time for filename - current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y") - - response = HttpResponse() - response['Content-Disposition'] = 'attachment; filename="' + document_type.name.replace(' ', '_') + '_export_' + current_time + '.csv"' - - writer = csv.writer(response) - - # csv header - writer.writerow(["Nome", "Cognome", "Email", "Stato", "Data di compilazione", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS"]) - - for doc in docs: - writer.writerow([ - doc.user.first_name, - doc.user.last_name, - doc.user.email, - doc.status, - doc.compilation_date, - doc.personal_data.parent_name, - doc.personal_data.via, - doc.personal_data.cap, - doc.personal_data.country, - doc.personal_data.nationality, - doc.personal_data.born_date, - doc.personal_data.home_phone, - doc.personal_data.phone, - doc.personal_data.school, - doc.personal_data.year, - doc.personal_data.avs_number - ]) - - return response - - #check if request to download with medic data - elif request.POST["action"][0] == 'm': - document_type = DocumentType.objects.get(id=request.POST["action"][1:]) - - # check if user has permission on the document - if document_type.group.name not in parent_groups: - return - - docs = Document.objects.filter(document_type=document_type) - - # get time for filename - current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y") - - response = HttpResponse() - response['Content-Disposition'] = 'attachment; filename="' + document_type.name.replace(' ', '_') + '_export_medic_' + current_time + '.csv"' - - writer = csv.writer(response) - - # csv header - writer.writerow(["Nome", "Cognome", "Email", "Stato", "Data di compilazione", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS", "Contatto d'emergenza", "Parentela del contatto", "Telefono d'emergenza", "Cellulare emergenza", "Indirizzo completo emergenza", "Cassa malati", "Ass. Infortuni", "Ass. RC", "Socio REGA", "Nome del medico", "Telefono medico", "Indirizzo medico", "Malattie", "Vacinazioni", "Data antitetanica", "Allergie", "Assume medicamenti", "Medicamenti", "Informazioni particolari", "Informazioni"]) - - for doc in docs: - if doc.medical_data: - writer.writerow([ - doc.user.first_name, - doc.user.last_name, - doc.user.email, - doc.status, - doc.compilation_date, - doc.personal_data.parent_name, - doc.personal_data.via, - doc.personal_data.cap, - doc.personal_data.country, - doc.personal_data.nationality, - doc.personal_data.born_date, - doc.personal_data.home_phone, - doc.personal_data.phone, - doc.personal_data.school, - doc.personal_data.year, - doc.personal_data.avs_number, - doc.medical_data.emer_name, - doc.medical_data.emer_relative, - doc.medical_data.emer_phone, - doc.medical_data.cell_phone, - doc.medical_data.address, - doc.medical_data.health_care, - doc.medical_data.injuries, - doc.medical_data.rc, - doc.medical_data.rega, - doc.medical_data.medic_name, - doc.medical_data.medic_phone, - doc.medical_data.medic_address, - doc.medical_data.sickness, - doc.medical_data.vaccine, - doc.medical_data.tetanus_date, - doc.medical_data.allergy, - doc.medical_data.drugs_bool, - doc.medical_data.drugs, - doc.medical_data.misc_bool, - doc.medical_data.misc - ]) - else: - writer.writerow([ - doc.user.first_name, - doc.user.last_name, - doc.user.email, - doc.status, - doc.compilation_date, - doc.personal_data.parent_name, - doc.personal_data.via, - doc.personal_data.cap, - doc.personal_data.country, - doc.personal_data.nationality, - doc.personal_data.born_date, - doc.personal_data.home_phone, - doc.personal_data.phone, - doc.personal_data.school, - doc.personal_data.year, - doc.personal_data.avs_number, - ]) - - return response - - # list all selected types - for i in request.POST.keys(): - if i.isdigit(): - docc = DocumentType.objects.get(id=i) - # check if user has permission - if docc.group.name in parent_groups: - selected.append(docc) - else: - error = True - error_text = "Non puoi modificare un documento non del tuo gruppo" - - # execute action on selected types - for i in selected: - if request.POST["action"] == 'delete': - try: - i.delete() - except ProtectedError: - error = True - error_text = "Non puoi eliminare un tipo a cui é collegato uno o piú documenti" - elif request.POST["action"] == 'hide': - i.enabled = False - i.save() - elif request.POST["action"] == 'show': - i.enabled = True - i.save() - - # check which filters are applied - public = "filter_public" in request.POST - selfsign = "filter_selfsign" in request.POST - hidden = "filter_hidden" in request.POST - personal = "filter_personal" in request.POST - medic = "filter_medic" in request.POST - custom = "filter_custom" in request.POST - message = "filter_message" in request.POST - group_bool = "filter_group" in request.POST - - # check if request to clear filters - if request.POST["action"] == 'clear': - public = True - selfsign = True - hidden = False - personal = True - medic = True - custom = True - message = True - group_bool = True - - # group name and obj - parent_group = request.user.groups.values_list('name', flat=True)[ - 0] - group = Group.objects.get(name=parent_group) - - # get documents from the list - q_obj = Q() - for i in parent_groups: - q_obj |= Q(group__name=i) - - public_types = DocumentType.objects.filter(q_obj) - - # apply filters - if not public: - public_types = public_types.filter(group_private=True) - public_check = "" - if not selfsign: - public_types = public_types.filter(auto_sign=False) - selfsign_check = "" - if not hidden: - public_types = public_types.filter(enabled=True) - hidden_check = "" - if not personal: - public_types = public_types.filter(personal_data=False) - personal_check = "" - if not medic: - public_types = public_types.filter(medical_data=False) - medic_check = "" - if not custom: - public_types = public_types.filter(custom_data=False) - custom_check = "" - if not message: - public_types = public_types.filter(custom_message=False) - message_check = "" - if not group_bool: - public_types = public_types.filter(custom_group=False) - group_check = "" - - # get custom keys from types - out = [] - for doc in public_types: - custom_keys = Keys.objects.filter(container=doc) - doc_count = str(len(Document.objects.filter(document_type=doc))) - ref_docs_archived = len(Document.objects.filter(document_type=doc, status="archive")) - if ref_docs_archived > 0: - doc_count += "-" + str(ref_docs_archived) - if doc.max_instances != 0: - doc_count += "/" + str(doc.max_instances) - - out.append([doc, custom_keys, doc_count]) - - context = { - 'docs': out, - 'public_check': public_check, - 'selfsign_check': selfsign_check, - 'hidden_check': hidden_check, - 'personal_check': personal_check, - 'medic_check': medic_check, - 'custom_check': custom_check, - 'message_check': message_check, - 'group_check': group_check, - 'error': error, - 'error_text': error_text, - } - return render(request, 'server/doc_type.html', context) - - -@user_passes_test(isStaff) -def doccreate(request): - context = {} - - # if user is not staff of primary set default group to secondary and default public type - if request.user.is_staff: - groups = request.user.groups.values_list('name', flat=True) - parent_group = request.user.groups.values_list('name', flat=True)[ - 0] - group_private = False - private_check = 'checked="checked"' - else: - groups = request.user.groups.values_list('name', flat=True)[1:] - parent_group = request.user.groups.values_list('name', flat=True)[ - 1] - group_private = True - private_check = '' - - # get group obj - group = Group.objects.get(name=parent_group) - - # init checkboxes - enabled = False - personal_data = False - medical_data = False - custom_data = False - custom_group_bool = False - staff_only = False - name = "" - custom_group = "" - max_instances = 0 - - enabled_check = 'checked="checked"' - personal_check = 'checked="checked"' - sign_check = 'checked="checked"' - medical_check = "" - custom_check = "" - custom_message_check = "" - staff_only_check = "" - - # if type create request sent - if request.method == "POST": - # gather inserted data - enabled = "enabled" in request.POST.keys() - auto_sign = "sign" not in request.POST.keys() - group_private = "group_private" in request.POST.keys() - personal_data = "personal_data" in request.POST.keys() - medical_data = "medical_data" in request.POST.keys() - custom_data = "custom_data" in request.POST.keys() - custom_message = "custom_message" in request.POST.keys() - staff_only = "staff_only" in request.POST.keys() - custom_message_text = request.POST["custom_message_text"] - name = request.POST["name"] - custom_group = request.POST["custom_group"] - - if request.POST["max_instances"]: - max_instances = request.POST["max_instances"] - if not max_instances.isdigit(): - context["error"] = "true" - context["error_text"] = "Il numero massimo di iscritti deve essere un numero" - return render(request, 'server/doc_create.html', context) - max_instances = int(max_instances) - - # if group not primary and not public throw error - if group_private == True and not request.user.is_staff: - context["error"] = "true" - context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario" - return render(request, 'server/doc_create.html', context) - - # if already existing name throw error - if len(DocumentType.objects.filter(name=name)) > 0: - context["error"] = "true" - context["error_text"] = "Questo nome esiste già. Prego usarne un altro." - return render(request, 'server/doc_create.html', context) - - # check if custom group permissions not met or non public document - if custom_group != "": - if group_private == True: - context["error"] = "true" - context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario" - return render(request, 'server/doc_create.html', context) - if custom_group not in groups: - context["error"] = "true" - context["error_text"] = "Non puoi creare un tipo assegnato ad un gruppo di cui non fai parte" - return render(request, 'server/doc_create.html', context) - else: - group = Group.objects.filter(name=custom_group)[0] - custom_group_bool = True - - # create type - doctype = DocumentType( - custom_group=custom_group_bool, auto_sign=auto_sign, custom_message=custom_message, custom_message_text=custom_message_text, name=request.POST["name"], enabled=enabled, group_private=group_private, group=group, personal_data=personal_data, medical_data=medical_data, custom_data=custom_data, staff_only=staff_only, max_instances=max_instances) - doctype.save() - - # create custom keys - if custom_data: - custom = request.POST["custom"] - custom.replace("\r", "") - custom = custom.split("\n") - for i in custom: - key = Keys(key=i, container=doctype) - key.save() - - return HttpResponseRedirect('doctype') - - # build context - context = { - "enabled_check": enabled_check, - "private_check": private_check, - "sign_check": sign_check, - "personal_check": personal_check, - "medical_check": medical_check, - "custom_check": custom_check, - "staff_only_check": staff_only_check, - "custom_message_check": custom_message_check, - } - - return render(request, 'server/doc_create.html', context) - -@user_passes_test(isStaff) -def docedit(request): - # create an edit page with empty context - return docedit_wrapper(request, {}) - -@user_passes_test(isStaff) -def docedit_wrapper(request, context): - - if request.user.is_staff and "group" in context.keys(): - base_group = request.user.groups.values_list('name', flat=True)[0] - if context["group"] == base_group: - context["group"] = "" - - if request.method == "POST": - if "action" not in request.POST.keys(): - # get groups on which the user has control - if request.user.is_staff: - groups = request.user.groups.values_list('name', flat=True) - else: - groups = request.user.groups.values_list('name', flat=True)[1:] - - group = Group.objects.get(name=groups[0]) - - # get document - doc = DocumentType.objects.get(id=request.POST["doc"]) - - # check if user can edit type - if doc.group.name not in groups: - # user is cheating abort - return - - # init variables - custom_group_bool = False - custom_group = "" - max_instances = 0 - - enabled_check = 'checked="checked"' if doc.enabled else "" - sign_check = 'checked="checked"' if not doc.auto_sign else "" - custom_message_check = 'checked="checked"' if doc.custom_message else "" - staff_only_check = 'checked="checked"' if doc.staff_only else "" - private_check = 'checked="checked"' if doc.group_private else "" - - context = { - 'doc': doc, - "group": doc.group.name, - "enabled_check": enabled_check, - "private_check": private_check, - "sign_check": sign_check, - "staff_only_check": staff_only_check, - "custom_message_check": custom_message_check, - } - - if request.user.is_staff: - if context["group"] == group.name: - context["group"] = "" - - # gather inserted data - enabled = "enabled" in request.POST.keys() - auto_sign = "sign" not in request.POST.keys() - group_private = "group_private" in request.POST.keys() - custom_message = "custom_message" in request.POST.keys() - staff_only = "staff_only" in request.POST.keys() - custom_message_text = request.POST["custom_message_text"] - custom_group = request.POST["custom_group"] - - if request.POST["max_instances"]: - max_instances = request.POST["max_instances"] - if not max_instances.isdigit(): - context["error"] = "true" - context["error_text"] = "Il numero massimo di iscritti deve essere un numero" - return render(request, 'server/doc_edit.html', context) - max_instances = int(max_instances) - - # if group not primary and not public throw error - if group_private == True and not request.user.is_staff: - context["error"] = "true" - context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario" - return render(request, 'server/doc_edit.html', context) - - # check if custom group permissions not met or non public document - if custom_group != "": - if group_private == True: - context["error"] = "true" - context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario" - return render(request, 'server/doc_edit.html', context) - if custom_group not in groups: - context["error"] = "true" - context["error_text"] = "Non puoi creare un tipo assegnato ad un gruppo di cui non fai parte" - return render(request, 'server/doc_edit.html', context) - else: - group = Group.objects.filter(name=custom_group)[0] - custom_group_bool = True - - # edit type - doc.custom_group = custom_group_bool - doc.auto_sign = auto_sign - doc.custom_message = custom_message - doc.custom_message_text = custom_message_text - doc.enabled = enabled - doc.group_private = group_private - doc.group = group - doc.staff_only = staff_only - doc.max_instances = max_instances - - doc.save() - - return HttpResponseRedirect('doctype') - - return render(request, 'server/doc_edit.html', context) - -@user_passes_test(isStaff) -def doclist(request): - context = {} - - # group name and obj - parent_group = request.user.groups.values_list('name', flat=True)[ - 0] - group = Group.objects.get(name=parent_group) - - # if user not staff of primary get secondary groups - if request.user.is_staff: - parent_groups = request.user.groups.values_list('name', flat=True) - else: - parent_groups = request.user.groups.values_list('name', flat=True)[1:] - - # create typezone - zurich = pytz.timezone('Europe/Zurich') - - # init error variables for users - error = False - error_text = "" - - # init checkboxes for filter - hidden = False - wait = True - selfsign = True - ok = True - signdoc = False - - hidden_check = 'checked="checked"' - wait_check = 'checked="checked"' - selfsign_check = 'checked="checked"' - ok_check = 'checked="checked"' - signdoc_check = 'checked="checked"' - - # set default dates for filters - newer = zurich.localize(dateparser.parse("1970-01-01")) - older = zurich.localize(datetime.now()) - - # init chips values - owner = [] - types = [] - groups = [] - chips_owner = [] - chips_types = [] - chips_groups = [] - - if request.method == "POST": - # if download request - if request.POST["action"][0] == 'k': - document = Document.objects.get(id=request.POST["action"][1:]) - # check if user has permission to view doc - if document.group.name in parent_groups: - vac_file = "" - health_file = "" - sign_doc_file = "" - - # prepare images in base64 - if document.medical_data: - if document.medical_data.vac_certificate.name: - with open(document.medical_data.vac_certificate.name, 'rb') as image_file: - vac_file = base64.b64encode( - image_file.read()).decode() - - if document.medical_data.health_care_certificate.name: - with open(document.medical_data.health_care_certificate.name, 'rb') as image_file: - health_file = base64.b64encode( - image_file.read()).decode() - - if document.signed_doc: - with open(document.signed_doc.name, 'rb') as image_file: - sign_doc_file = base64.b64encode( - image_file.read()).decode() - - # build with template and render - template = get_template('server/download_doc.html') - doc = [document, KeyVal.objects.filter( - container=document), document.personal_data, document.medical_data, parent_group] - context = {'doc': doc, 'vac': vac_file, - 'health': health_file, 'sign_doc_file': sign_doc_file} - html = template.render(context) - pdf = pdfkit.from_string(html, False) - result = BytesIO(pdf) - result.seek(0) - return FileResponse(result, as_attachment=True, filename=document.user.username+"_"+document.document_type.name+".pdf") - - # get selected documents and check if user has permission to view - selected = [] - for i in request.POST.keys(): - if i.isdigit(): - docc = Document.objects.get(id=i) - if docc.group.name in parent_groups: - selected.append(docc) - - # execute action on selected documents - for i in selected: - if request.POST["action"] == 'delete' and settings.DEBUG: - i.delete() - elif request.POST["action"] == 'approve' and settings.DEBUG: - i.status = 'ok' - i.save() - elif request.POST["action"] == 'archive': - if i.status == 'ok': - i.status = 'archive' - if i.medical_data: - i.medical_data.delete() - i.medical_data.save() - i.medical_data = None - i.save() - else: - error = True - error_text = "Non puoi archiviare un documento non approvato" - elif request.POST["action"] == 'unarchive': - if i.status == 'archive': - i.status = 'ok' - i.save() - else: - error = True - error_text = "Non puoi dearchiviare un documento non archiviato" - - if len(selected) == 0: - error = True - error_text = "Seleziona almeno un documento" - - # get filter values - hidden = "filter_hidden" in request.POST - wait = "filter_wait" in request.POST - selfsign = "filter_selfsign" in request.POST - ok = "filter_ok" in request.POST - signdoc = "filter_signdoc" in request.POST - newer = zurich.localize(dateparser.parse(request.POST["newer"])) - older = zurich.localize(dateparser.parse( - request.POST["older"]) + timedelta(days=1)) - owner = request.POST["owner"].split("^|") - types = request.POST["type"].split("^|") - groups = request.POST["groups"].split("^|") - - # clear filters - if request.POST["action"] == 'clear': - hidden = False - wait = True - selfsign = True - ok = True - signdoc = False - newer = zurich.localize(dateparser.parse("1970-01-01")) - older = zurich.localize(datetime.now()) - owner = [] - types = [] - groups = [] - - # filter documents based on group of staff - q_obj = Q() - for i in parent_groups: - q_obj |= Q(group__name=i) - - documents = Document.objects.filter(q_obj) - - # filter documents - if not hidden: - documents = documents.filter(~Q(status="archive")) - hidden_check = "" - if not wait: - documents = documents.filter(~Q(status="wait")) - wait_check = "" - if not selfsign: - documents = documents.filter(~Q(status="autosign")) - selfsign_check = "" - if not ok: - documents = documents.filter(~Q(status="ok")) - ok_check = "" - if not signdoc: - signdoc_check = "" - - # filter date range - documents = documents.filter(compilation_date__range=[newer, older]) - - # filter types, owner, groups using chips - if len(types) > 0: - if types[0] != "": - q_obj = Q() - for t in types: - q_obj |= Q(document_type__name=t) - chips_types.append(t) - - documents = documents.filter(q_obj) - - if len(owner) > 0: - if owner[0] != "": - q_obj = Q() - for u in owner: - user = u.split("(")[0][:-1] - q_obj |= Q(user__username=user) - chips_owner.append(u) - - documents = documents.filter(q_obj) - - if len(groups) > 0: - if groups[0] != "": - q_obj = Q() - for g in groups: - q_obj |= Q(group__name=g) - chips_groups.append(g) - - documents = documents.filter(q_obj) - - out = [] - for i in documents: - # filter for confirmed with attachment documents and approved - if signdoc: - if i.status == "ok" and not i.signed_doc: - continue - - # prepare images in base64 - personal = None - medical = None - vac_file = "" - health_file = "" - sign_doc_file = "" - if i.personal_data: - personal = i.personal_data - if i.medical_data: - medical = i.medical_data - if medical.vac_certificate.name: - vac_file = "/server/media/" + str(i.id) + "/vac_certificate/doc" - - if medical.health_care_certificate.name: - health_file = "/server/media/" + str(i.id) + "/health_care_certificate/doc" - - if i.signed_doc: - sign_doc_file = "/server/media/" + str(i.id) + "/signed_doc/doc" - - doc_group = i.user.groups.values_list('name', flat=True)[0] - - out.append([i, KeyVal.objects.filter(container=i), personal, - medical, doc_group, vac_file, health_file, sign_doc_file]) - - # get types and users for chips autocompletation - auto_types = DocumentType.objects.filter( - Q(group_private=False) | Q(group=group)) - users = User.objects.filter(groups__name=parent_group) - - context = { - "types": auto_types, - "users": users, - "groups": parent_groups, - "docs": out, - "hidden_check": hidden_check, - "wait_check": wait_check, - "selfsign_check": selfsign_check, - "ok_check": ok_check, - "signdoc_check": signdoc_check, - "newer": newer, - "older": older, - "chips_owner": chips_owner, - "chips_type": chips_types, - "chips_groups": chips_groups, - 'error': error, - 'error_text': error_text, - 'settings': settings, - } - - # check if download multiple documents - if request.method == "POST": - if "status" not in request.session: - request.session['status'] = True - - if request.POST["action"] == "download" and len(selected) > 0 and request.session['status']: - # save data in session - request.session['status'] = False - request.session['progress'] = 0 - request.session['total'] = len(selected) - # run job - threading.Thread(target=zip_documents, args=(selected, request.session.session_key)).start() - # flag the client to check for updates - context["task_id"] = "0" - - return render(request, 'server/doc_list.html', context) - -def get_progress(request): - # if user wants to download result - if 'download' in request.GET: - # if job is completed - if request.session['status']: - data = BytesIO(base64.b64decode(request.session['result'])) - data.seek(0) - return FileResponse(data, as_attachment=True, filename="documents_" + datetime.now().strftime("%H_%M-%d_%m_%y") + ".zip") - - # otherwise return status - data = [request.session['progress'], request.session['total'], request.session['status']] - return HttpResponse(json.dumps(data)) - -def zip_documents(docs, session_key): - files = [] - # get session - session = SessionStore(session_key=session_key) - for i in docs: - vac_file = "" - health_file = "" - sign_doc_file = "" - - # prepare pictures in base64 - if i.medical_data: - if i.medical_data.vac_certificate.name: - with open(i.medical_data.vac_certificate.name, 'rb') as image_file: - vac_file = base64.b64encode( - image_file.read()).decode() - - if i.medical_data.health_care_certificate.name: - with open(i.medical_data.health_care_certificate.name, 'rb') as image_file: - health_file = base64.b64encode( - image_file.read()).decode() - if i.signed_doc: - with open(i.signed_doc.name, 'rb') as image_file: - sign_doc_file = base64.b64encode( - image_file.read()).decode() - - template = get_template('server/download_doc.html') - doc = [i, KeyVal.objects.filter( - container=i), i.personal_data, i.medical_data, i.user.groups.values_list('name', flat=True)[0]] - context = {'doc': doc, 'vac': vac_file, - 'health': health_file, 'sign_doc_file': sign_doc_file} - # render context - html = template.render(context) - # render pdf using wkhtmltopdf - pdf = pdfkit.from_string(html, False) - filename = i.user.username+"_"+i.document_type.name+".pdf" - # append file - files.append((filename, pdf)) - session['progress'] += 1 - session.save() - - # zip documents - mem_zip = BytesIO() - with zipfile.ZipFile(mem_zip, mode="w",compression=zipfile.ZIP_DEFLATED) as zf: - for f in files: - zf.writestr(f[0], f[1]) - - mem_zip.seek(0) - # save result - session['result'] = base64.b64encode(mem_zip.getvalue()).decode() - session['status'] = True - session.save() - - -@user_passes_test(isStaff) -def upload_doc(request): - # setup group based on staff primary or not - parent_group = request.user.groups.values_list('name', flat=True)[ - 0] - group = Group.objects.get(name=parent_group) - if request.user.is_staff: - groups = request.user.groups.values_list('name', flat=True) - else: - groups = request.user.groups.values_list('name', flat=True)[1:] - - # setup variables for error text and success text - error = False - success = False - error_text = "" - success_text = "" - - document = None - # parse document code and check for permissions - if request.method == "POST": - data = request.POST["code"] - if not data.isdigit(): - error_text = "Formato codice errato" - error = True - elif int(data) < 100000 or int(data) > 999999: - error_text = "Formato codice errato" - error = True - elif len(Document.objects.filter(code=data)) == 0: - error_text = "Codice invalido" - error = True - elif Document.objects.filter(code=data)[0].group.name not in groups: - error_text = "Codice invalido" - error = True - else: - # get document - document = Document.objects.filter(code=data)[0] - - # prepare success message - if document.status == 'ok': - success_text = "File caricato" - success = True - else: - document.status = 'ok' - document.save() - success_text = "Documento approvato e file caricato" - success = True - - # check for errors and upload files - if "doc_sign" in request.FILES and not error: - myfile = request.FILES['doc_sign'] - try: - im = Image.open(myfile) - im_io = BytesIO() - # compress image in WEBP - im.save(im_io, 'WEBP', quality=50) - document.signed_doc.save(data+"_"+myfile.name, im_io) - document.save() - except UnidentifiedImageError: - error = True - error_text = "Il file non è un immagine valida" - else: - error = True - error_text = "Prego caricare un file" - - context = { - "error": error, - "error_text": error_text, - "success": success, - "success_text": success_text, - } - - return render(request, 'server/upload_doc.html', context) - - -@user_passes_test(isStaff) -def docpreview(request): - context = {} - # check for permissions - if request.user.is_staff: - groups = request.user.groups.values_list('name', flat=True) - else: - groups = request.user.groups.values_list('name', flat=True)[1:] - - if request.method == "POST": - # get document code - code = request.POST["preview"] - - # check if code valid and user has permission - if not code.isdigit(): - return render(request, 'server/download_doc.html', context) - if len(Document.objects.filter(code=code)) == 0: - return render(request, 'server/download_doc.html', context) - if Document.objects.filter(code=code)[0].group.name not in groups: - return render(request, 'server/download_doc.html', context) - - # get document - document = Document.objects.filter(code=code)[0] - parent_group = document.user.groups.values_list('name', flat=True)[0] - - # user has not permission to view document - if parent_group not in groups: - return - - # prepare images in base64 - vac_file = "" - health_file = "" - sign_doc_file = "" - if document.medical_data: - if document.medical_data.vac_certificate.name: - with open(document.medical_data.vac_certificate.name, 'rb') as image_file: - vac_file = base64.b64encode(image_file.read()).decode() - - if document.medical_data.health_care_certificate.name: - with open(document.medical_data.health_care_certificate.name, 'rb') as image_file: - health_file = base64.b64encode(image_file.read()).decode() - if document.signed_doc: - with open(document.signed_doc.name, 'rb') as image_file: - sign_doc_file = base64.b64encode(image_file.read()).decode() - - # prepare context - doc = [document, KeyVal.objects.filter( - container=document), document.personal_data, document.medical_data, parent_group] - context = {'doc': doc, 'vac': vac_file, - 'health': health_file, 'sign_doc_file': sign_doc_file} - - return render(request, 'server/download_doc.html', context) - - -@user_passes_test(isStaff) -def data_request(request): - context = {} - parent_group = request.user.groups.values_list('name', flat=True)[0] - - if request.method == "POST": - if request.POST["request"] == "email_all": - users = User.objects.filter(groups__name=parent_group) - data = "" - for user in users: - data += user.email + ", " - data = data[:-2] - context["data"] = data - elif request.POST["request"] == "email_non_staff": - users = User.objects.filter(groups__name=parent_group).exclude(groups__name="capi") - data = "" - for user in users: - data += user.email + ", " - data = data[:-2] - context["data"] = data - elif request.POST["request"] == "data_user": - users = User.objects.filter(groups__name=parent_group) - - # get time for filename - current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y") - - response = HttpResponse() - response['Content-Disposition'] = 'attachment; filename="data_export_' + current_time + '.csv"' - - writer = csv.writer(response) - - # csv header - writer.writerow(["Nome", "Cognome", "Email", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS"]) - - for user in users: - usercode = UserCode.objects.filter(user=user)[0] - writer.writerow([ - user.first_name, - user.last_name, - user.email, - usercode.parent_name, - usercode.via, - usercode.cap, - usercode.country, - usercode.nationality, - usercode.born_date, - usercode.home_phone, - usercode.phone, - usercode.school, - usercode.year, - usercode.avs_number - ]) - - return response - - elif request.POST["request"] == "data_user_medic": - users = User.objects.filter(groups__name=parent_group) - - # get time for filename - current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y") - - response = HttpResponse() - response['Content-Disposition'] = 'attachment; filename="data_export_' + current_time + '.csv"' - - writer = csv.writer(response) - - # csv header - writer.writerow(["Nome", "Cognome", "Email", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS", "Contatto d'emergenza", "Parentela del contatto", "Telefono d'emergenza", "Cellulare emergenza", "Indirizzo completo emergenza", "Cassa malati", "Ass. Infortuni", "Ass. RC", "Socio REGA", "Nome del medico", "Telefono medico", "Indirizzo medico", "Malattie", "Vacinazioni", "Data antitetanica", "Allergie", "Assume medicamenti", "Medicamenti", "Informazioni particolari", "Informazioni"]) - - for user in users: - usercode = UserCode.objects.filter(user=user)[0] - medic = usercode.medic - writer.writerow([ - user.first_name, - user.last_name, - user.email, - usercode.parent_name, - usercode.via, - usercode.cap, - usercode.country, - usercode.nationality, - usercode.born_date, - usercode.home_phone, - usercode.phone, - usercode.school, - usercode.year, - usercode.avs_number, - medic.emer_name, - medic.emer_relative, - medic.emer_phone, - medic.cell_phone, - medic.address, - medic.health_care, - medic.injuries, - medic.rc, - medic.rega, - medic.medic_name, - medic.medic_phone, - medic.medic_address, - medic.sickness, - medic.vaccine, - medic.tetanus_date, - medic.allergy, - medic.drugs_bool, - medic.drugs, - medic.misc_bool, - medic.misc - ]) - - return response - return render(request, 'server/data_request.html', context) - -def media_request(request, id=0, t="", flag=""): - if flag == "usercode": - usercode = UserCode.objects.get(id=id) - if request.user.is_staff: - groups = request.user.groups.values_list('name', flat=True) - usercode_group = usercode.user.groups.values_list('name', flat=True)[0] - if usercode_group not in groups: - return - else: - if usercode.user != request.user: - return - - if t == "health_care_certificate": - image_file = usercode.medic.health_care_certificate - elif t == "vac_certificate": - image_file = usercode.medic.vac_certificate - - elif flag == "doc": - doc = Document.objects.get(id=id) - doc_group = doc.user.groups.values_list('name', flat=True)[0] - - # check if user can view media - if request.user.is_staff: - # user is staff - groups = request.user.groups.values_list('name', flat=True) - if doc_group not in groups: - return - elif request.user.has_perm("client.staff"): - # user is psudo-staff - groups = request.user.groups.values_list('name', flat=True)[1:] - if doc_group not in groups: - return - else: - # is normal user - if doc.user != request.user: - return - - if t == "health_care_certificate": - image_file = doc.medical_data.health_care_certificate - elif t == "vac_certificate": - image_file = doc.medical_data.vac_certificate - elif t == "signed_doc": - image_file = doc.signed_doc - - return FileResponse(image_file, filename=image_file.name)
\ No newline at end of file +from django.shortcuts import render
+from client.models import MedicalData, UserCode, Keys, DocumentType, Document, KeyVal
+from django.conf import settings
+from django.core.mail import send_mail
+from client.models import GroupSettings, UserCode, Keys, DocumentType, Document, KeyVal
+from django.contrib.auth.models import Group, Permission, User
+from django.db.models import Q
+from django.http import HttpResponseRedirect, FileResponse, HttpResponse
+from django.db.models.deletion import ProtectedError
+from django.template.loader import get_template
+from django.conf import settings
+from django.contrib.admin.views.decorators import staff_member_required
+from django.contrib.auth.decorators import user_passes_test
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.sessions.backends.db import SessionStore
+from django import template
+
+import csv
+import dateparser
+from datetime import datetime
+from datetime import timedelta
+import pytz
+import pdfkit
+from io import BytesIO
+import os
+import base64
+from PIL import Image, UnidentifiedImageError
+import zipfile
+import json
+import threading
+import random
+
+# custom staff check function for non primary group staff members
+def isStaff(user):
+ if user.is_staff:
+ return True
+ if user.has_perm("client.staff"):
+ return True
+ return False
+
+# function to check if "aggiunto" has permission to view documents
+def isCapi_enabled(user):
+ group = user.groups.values_list('name', flat=True)[0]
+ settings = GroupSettings.objects.filter(group__name=group)
+ if len(settings) == 0:
+ return False
+ return settings[0].view_documents
+
+@user_passes_test(isStaff)
+def index(request):
+ context = {}
+ # primary group name + object
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group = Group.objects.get(name=parent_group)
+
+ # check for settings
+ doc_view_check = ""
+ settings = GroupSettings.objects.filter(group__name=group)
+
+ # create settings if non existing
+ if len(settings) == 0:
+ settings = GroupSettings(group=group, view_documents=False)
+ else:
+ settings = settings[0]
+
+ if settings.view_documents:
+ doc_view_check = 'checked="checked"'
+
+ # check if changing settings
+ if request.method == "POST":
+ if "doc_view" in request.POST:
+ settings.view_documents = True
+ settings.save()
+ else:
+ settings.view_documents = False
+ settings.save()
+
+ return HttpResponseRedirect("/server")
+
+ # users from younger to older
+ users = User.objects.filter(groups__name=parent_group).order_by("-id")
+ users_out = []
+
+ # only send part of the user data, only if user is approved
+ for user in users:
+ if not user.has_perm("client.approved") and not user.is_staff:
+ continue
+
+ users_out.append([user.username, user.first_name,
+ user.last_name])
+
+ # if user is staff of not primary show only public types
+ if request.user.is_staff:
+ public_types = DocumentType.objects.filter(
+ Q(group_private=False) | Q(group=group) & Q(enabled=True)).order_by("-id")
+ else:
+ public_types = DocumentType.objects.filter(
+ Q(group_private=False) & Q(enabled=True)).order_by("-id")
+
+ # count documents of that type to show statistics
+ docs = []
+ for doc in public_types:
+ doc_count = str(len(Document.objects.filter(document_type=doc)))
+ ref_docs_archived = len(Document.objects.filter(document_type=doc, status="archive"))
+ if ref_docs_archived > 0:
+ doc_count += "-" + str(ref_docs_archived)
+ if doc.max_instances != 0:
+ doc_count += "/" + str(doc.max_instances)
+ docs.append([doc, doc_count])
+
+ # don't list users if user is staff of not primary
+ if request.user.is_staff:
+ context = {
+ 'docs': docs,
+ 'users': users_out,
+ }
+ else:
+ context = {
+ 'docs': docs,
+ }
+ context["doc_view_check"] = doc_view_check
+ return render(request, 'server/index.html', context)
+
+
+@staff_member_required
+def uapprove(request):
+ context = {}
+ data = []
+ if request.method == "POST":
+ # get group name and obj
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group = Group.objects.get(name=parent_group)
+
+ # get permission object
+ permission = Permission.objects.get(codename='approved')
+
+ # parse text to array
+ data = request.POST["codes"]
+ data.replace("\r", "")
+ data = data.split("\n")
+ # check if format is right
+ for i in range(len(data)):
+ if not data[i].startswith("U"):
+ data[i] = data[i] + " - Formato errato"
+ elif not data[i][1:].isdigit():
+ data[i] = data[i] + " - Formato errato"
+ elif int(data[i][1:]) < 100000 or int(data[i][1:]) > 999999:
+ data[i] = data[i] + " - Formato errato"
+ elif len(UserCode.objects.filter(code=data[i][1:])) == 0:
+ data[i] = data[i] + " - Invalido"
+ else:
+ user = UserCode.objects.filter(code=data[i][1:])[0].user
+ user.user_permissions.add(permission)
+ # if user not in any group add to the same group as staff
+ if len(user.groups.values_list('name', flat=True)) == 0:
+ user.groups.add(group)
+ data[i] = data[i] + " - Ok"
+ else:
+ if user.groups.values_list('name', flat=True)[0] == parent_group:
+ # if user already in group do nothing
+ data[i] = data[i] + " - Ok"
+ else:
+ # if user in another group notify staff of group change
+ user.groups.clear()
+ user.groups.add(group)
+ data[i] = data[i] + " - Ok, cambio branca"
+
+ context = {
+ 'messages': data,
+ 'empty': len(data) == 0,
+ }
+
+ return render(request, 'server/approve_user.html', context)
+
+
+@user_passes_test(isStaff)
+def docapprove(request):
+ context = {}
+ data = []
+
+ # group name and obj
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group = Group.objects.get(name=parent_group)
+
+ # if user not staff of primary has only controll of non primary groups
+ if request.user.is_staff:
+ groups = request.user.groups.values_list('name', flat=True)
+ else:
+ groups = request.user.groups.values_list('name', flat=True)[1:]
+
+ if request.method == "POST":
+ # parse text in array
+ data = request.POST["codes"]
+ data.replace("\r", "")
+ data = data.split("\n")
+ # check if code valid
+ for i in range(len(data)):
+ if not data[i].isdigit():
+ data[i] = data[i] + " - Formato errato"
+ elif int(data[i]) < 100000 or int(data[i]) > 999999:
+ data[i] = data[i] + " - Formato errato"
+ elif len(Document.objects.filter(code=data[i])) == 0:
+ data[i] = data[i] + " - Invalido"
+ elif Document.objects.filter(code=data[i])[0].group.name not in groups:
+ # check if user has permission to approve document
+ data[i] = data[i] + " - Invalido"
+ else:
+ document = Document.objects.filter(code=data[i])[0]
+ if document.status == 'ok':
+ # do nothing document already approved
+ data[i] = data[i] + " - Già approvato"
+ else:
+ document.status = 'ok'
+ document.save()
+ data[i] = data[i] + " - Ok"
+
+ context = {
+ 'messages': data,
+ 'empty': len(data) == 0,
+ }
+
+ return render(request, 'server/approve_doc.html', context)
+
+
+@staff_member_required
+def ulist(request):
+ context = {}
+ # group name and obj
+ parent_group = request.user.groups.values_list('name', flat=True)[0]
+ group = Group.objects.get(name=parent_group)
+
+ if request.method == "POST":
+ # request to download document
+ if request.POST["action"][0] == 'f':
+ document = Document.objects.get(id=request.POST["action"][1:])
+ # check if user has permission to view document
+ if document.group == group:
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+
+ # prepare pictures in base64
+ if document.medical_data:
+ if document.medical_data.vac_certificate.name:
+ with open(document.medical_data.vac_certificate.name, 'rb') as image_file:
+ vac_file = base64.b64encode(
+ image_file.read()).decode()
+
+ if document.medical_data.health_care_certificate.name:
+ with open(document.medical_data.health_care_certificate.name, 'rb') as image_file:
+ health_file = base64.b64encode(
+ image_file.read()).decode()
+ if document.signed_doc:
+ with open(document.signed_doc.name, 'rb') as image_file:
+ sign_doc_file = base64.b64encode(
+ image_file.read()).decode()
+
+ # get template and build context
+ template = get_template('server/download_doc.html')
+ doc = [document, KeyVal.objects.filter(
+ container=document), document.personal_data, document.medical_data, parent_group]
+ context = {'doc': doc, 'vac': vac_file,
+ 'health': health_file, 'sign_doc_file': sign_doc_file}
+ # render context
+ html = template.render(context)
+ # render pdf using wkhtmltopdf
+ pdf = pdfkit.from_string(html, False)
+ result = BytesIO(pdf)
+ result.seek(0)
+ return FileResponse(result, filename=document.user.username+"_"+document.document_type.name+".pdf")
+
+ # deapprove user
+ elif request.POST["action"][0] == 'd':
+ user = User.objects.get(id=request.POST["action"][1:])
+ # check if user has permission to deapprove user
+ if user.groups.all()[0] == group:
+ content_type = ContentType.objects.get_for_model(Document)
+ permission = Permission.objects.get(
+ content_type=content_type, codename="approved")
+ user.user_permissions.remove(permission)
+ return HttpResponseRedirect("ulist")
+ # make user "capo"
+ elif request.POST["action"][0] == 'c':
+ user = User.objects.get(id=request.POST["action"][1:])
+ capi = Group.objects.get(name="capi")
+ # check if user has permission to modify
+ if user.groups.all()[0] == group:
+ if "capi" in user.groups.values_list('name', flat=True):
+ # remove group
+ user.groups.remove(capi)
+ else:
+ # add group
+ user.groups.add(capi)
+ return HttpResponseRedirect("ulist")
+
+ # list users with their documents
+ users = list(User.objects.filter(
+ groups__name=parent_group).filter(groups__name="capi").order_by("first_name"))
+ users += list(User.objects.filter(
+ groups__name=parent_group).exclude(groups__name="capi").order_by("first_name"))
+ out = []
+ for user in users:
+ # list only approved users
+ if not user.has_perm("client.approved") and not user.is_staff:
+ continue
+
+ usercode = UserCode.objects.filter(user=user)[0]
+ # get all user documents
+ documents = Document.objects.filter(Q(user=user) & ~Q(
+ status='archive') & Q(group__name=parent_group))
+
+ # generate link for images
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+ if usercode.medic:
+ if usercode.medic.vac_certificate.name:
+ vac_file = "/server/media/" + str(usercode.id) + "/vac_certificate/usercode"
+
+ if usercode.medic.health_care_certificate.name:
+ health_file = "/server/media/" + str(usercode.id) + "/health_care_certificate/usercode"
+
+ out.append([user, usercode, parent_group,
+ documents, vac_file, health_file, "capi" in user.groups.values_list('name',flat = True)])
+ context = {'users': out}
+ return render(request, 'server/user_list.html', context)
+
+
+@user_passes_test(isStaff)
+def doctype(request):
+ context = {}
+
+ # error variables to throw at user
+ error = False
+ error_text = ""
+
+ # init checkboxes
+ public = True
+ selfsign = True
+ hidden = False
+ personal = True
+ medic = True
+ custom = True
+ message = True
+ group_bool = True
+ public_check = 'checked="checked"'
+ selfsign_check = 'checked="checked"'
+ hidden_check = 'checked="checked"'
+ personal_check = 'checked="checked"'
+ medic_check = 'checked="checked"'
+ custom_check = 'checked="checked"'
+ message_check = 'checked="checked"'
+ group_check = 'checked="checked"'
+
+ # if user not staff of primary get only non primary groups
+ if request.user.is_staff:
+ parent_groups = request.user.groups.values_list('name', flat=True)
+ else:
+ parent_groups = request.user.groups.values_list('name', flat=True)[
+ 1:]
+
+ if request.method == "POST":
+ selected = []
+
+ # check if request to edit
+ if request.POST["action"][0] == 'e':
+ document_type = DocumentType.objects.get(id=request.POST["action"][1:])
+
+ # check if user has permission on the document
+ if document_type.group.name not in parent_groups:
+ return
+
+ enabled_check = 'checked="checked"' if document_type.enabled else ""
+ sign_check = 'checked="checked"' if not document_type.auto_sign else ""
+ custom_message_check = 'checked="checked"' if document_type.custom_message else ""
+ staff_only_check = 'checked="checked"' if document_type.staff_only else ""
+ private_check = 'checked="checked"' if document_type.group_private else ""
+
+ context = {
+ 'doc': document_type,
+ "group": document_type.group.name,
+ "enabled_check": enabled_check,
+ "private_check": private_check,
+ "sign_check": sign_check,
+ "staff_only_check": staff_only_check,
+ "custom_message_check": custom_message_check,
+ }
+
+ return docedit_wrapper(request, context)
+
+ # check if request to download
+ elif request.POST["action"][0] == 'd':
+ document_type = DocumentType.objects.get(id=request.POST["action"][1:])
+
+ # check if user has permission on the document
+ if document_type.group.name not in parent_groups:
+ return
+
+ docs = Document.objects.filter(document_type=document_type)
+
+ # get time for filename
+ current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y")
+
+ response = HttpResponse()
+ response['Content-Disposition'] = 'attachment; filename="' + document_type.name.replace(' ', '_') + '_export_' + current_time + '.csv"'
+
+ writer = csv.writer(response)
+
+ # csv header
+ writer.writerow(["Nome", "Cognome", "Email", "Stato", "Data di compilazione", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS"])
+
+ for doc in docs:
+ writer.writerow([
+ doc.user.first_name,
+ doc.user.last_name,
+ doc.user.email,
+ doc.status,
+ doc.compilation_date,
+ doc.personal_data.parent_name,
+ doc.personal_data.via,
+ doc.personal_data.cap,
+ doc.personal_data.country,
+ doc.personal_data.nationality,
+ doc.personal_data.born_date,
+ doc.personal_data.home_phone,
+ doc.personal_data.phone,
+ doc.personal_data.school,
+ doc.personal_data.year,
+ doc.personal_data.avs_number
+ ])
+
+ return response
+
+ #check if request to download with medic data
+ elif request.POST["action"][0] == 'm':
+ document_type = DocumentType.objects.get(id=request.POST["action"][1:])
+
+ # check if user has permission on the document
+ if document_type.group.name not in parent_groups:
+ return
+
+ docs = Document.objects.filter(document_type=document_type)
+
+ # get time for filename
+ current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y")
+
+ response = HttpResponse()
+ response['Content-Disposition'] = 'attachment; filename="' + document_type.name.replace(' ', '_') + '_export_medic_' + current_time + '.csv"'
+
+ writer = csv.writer(response)
+
+ # csv header
+ writer.writerow(["Nome", "Cognome", "Email", "Stato", "Data di compilazione", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS", "Contatto d'emergenza", "Parentela del contatto", "Telefono d'emergenza", "Cellulare emergenza", "Indirizzo completo emergenza", "Cassa malati", "Ass. Infortuni", "Ass. RC", "Socio REGA", "Nome del medico", "Telefono medico", "Indirizzo medico", "Malattie", "Vacinazioni", "Data antitetanica", "Allergie", "Assume medicamenti", "Medicamenti", "Informazioni particolari", "Informazioni"])
+
+ for doc in docs:
+ if doc.medical_data:
+ writer.writerow([
+ doc.user.first_name,
+ doc.user.last_name,
+ doc.user.email,
+ doc.status,
+ doc.compilation_date,
+ doc.personal_data.parent_name,
+ doc.personal_data.via,
+ doc.personal_data.cap,
+ doc.personal_data.country,
+ doc.personal_data.nationality,
+ doc.personal_data.born_date,
+ doc.personal_data.home_phone,
+ doc.personal_data.phone,
+ doc.personal_data.school,
+ doc.personal_data.year,
+ doc.personal_data.avs_number,
+ doc.medical_data.emer_name,
+ doc.medical_data.emer_relative,
+ doc.medical_data.emer_phone,
+ doc.medical_data.cell_phone,
+ doc.medical_data.address,
+ doc.medical_data.health_care,
+ doc.medical_data.injuries,
+ doc.medical_data.rc,
+ doc.medical_data.rega,
+ doc.medical_data.medic_name,
+ doc.medical_data.medic_phone,
+ doc.medical_data.medic_address,
+ doc.medical_data.sickness,
+ doc.medical_data.vaccine,
+ doc.medical_data.tetanus_date,
+ doc.medical_data.allergy,
+ doc.medical_data.drugs_bool,
+ doc.medical_data.drugs,
+ doc.medical_data.misc_bool,
+ doc.medical_data.misc
+ ])
+ else:
+ writer.writerow([
+ doc.user.first_name,
+ doc.user.last_name,
+ doc.user.email,
+ doc.status,
+ doc.compilation_date,
+ doc.personal_data.parent_name,
+ doc.personal_data.via,
+ doc.personal_data.cap,
+ doc.personal_data.country,
+ doc.personal_data.nationality,
+ doc.personal_data.born_date,
+ doc.personal_data.home_phone,
+ doc.personal_data.phone,
+ doc.personal_data.school,
+ doc.personal_data.year,
+ doc.personal_data.avs_number,
+ ])
+
+ return response
+
+ # list all selected types
+ for i in request.POST.keys():
+ if i.isdigit():
+ docc = DocumentType.objects.get(id=i)
+ # check if user has permission
+ if docc.group.name in parent_groups:
+ selected.append(docc)
+ else:
+ error = True
+ error_text = "Non puoi modificare un documento non del tuo gruppo"
+
+ # execute action on selected types
+ for i in selected:
+ if request.POST["action"] == 'delete':
+ try:
+ i.delete()
+ except ProtectedError:
+ error = True
+ error_text = "Non puoi eliminare un tipo a cui é collegato uno o piú documenti"
+ elif request.POST["action"] == 'hide':
+ i.enabled = False
+ i.save()
+ elif request.POST["action"] == 'show':
+ i.enabled = True
+ i.save()
+
+ # check which filters are applied
+ public = "filter_public" in request.POST
+ selfsign = "filter_selfsign" in request.POST
+ hidden = "filter_hidden" in request.POST
+ personal = "filter_personal" in request.POST
+ medic = "filter_medic" in request.POST
+ custom = "filter_custom" in request.POST
+ message = "filter_message" in request.POST
+ group_bool = "filter_group" in request.POST
+
+ # check if request to clear filters
+ if request.POST["action"] == 'clear':
+ public = True
+ selfsign = True
+ hidden = False
+ personal = True
+ medic = True
+ custom = True
+ message = True
+ group_bool = True
+
+ # group name and obj
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group = Group.objects.get(name=parent_group)
+
+ # get documents from the list
+ q_obj = Q()
+ for i in parent_groups:
+ q_obj |= Q(group__name=i)
+
+ public_types = DocumentType.objects.filter(q_obj)
+
+ # apply filters
+ if not public:
+ public_types = public_types.filter(group_private=True)
+ public_check = ""
+ if not selfsign:
+ public_types = public_types.filter(auto_sign=False)
+ selfsign_check = ""
+ if not hidden:
+ public_types = public_types.filter(enabled=True)
+ hidden_check = ""
+ if not personal:
+ public_types = public_types.filter(personal_data=False)
+ personal_check = ""
+ if not medic:
+ public_types = public_types.filter(medical_data=False)
+ medic_check = ""
+ if not custom:
+ public_types = public_types.filter(custom_data=False)
+ custom_check = ""
+ if not message:
+ public_types = public_types.filter(custom_message=False)
+ message_check = ""
+ if not group_bool:
+ public_types = public_types.filter(custom_group=False)
+ group_check = ""
+
+ # get custom keys from types
+ out = []
+ for doc in public_types:
+ custom_keys = Keys.objects.filter(container=doc)
+ doc_count = str(len(Document.objects.filter(document_type=doc)))
+ ref_docs_archived = len(Document.objects.filter(document_type=doc, status="archive"))
+ if ref_docs_archived > 0:
+ doc_count += "-" + str(ref_docs_archived)
+ if doc.max_instances != 0:
+ doc_count += "/" + str(doc.max_instances)
+
+ out.append([doc, custom_keys, doc_count])
+
+ context = {
+ 'docs': out,
+ 'public_check': public_check,
+ 'selfsign_check': selfsign_check,
+ 'hidden_check': hidden_check,
+ 'personal_check': personal_check,
+ 'medic_check': medic_check,
+ 'custom_check': custom_check,
+ 'message_check': message_check,
+ 'group_check': group_check,
+ 'error': error,
+ 'error_text': error_text,
+ }
+ return render(request, 'server/doc_type.html', context)
+
+
+@user_passes_test(isStaff)
+def doccreate(request):
+ context = {}
+
+ # if user is not staff of primary set default group to secondary and default public type
+ if request.user.is_staff:
+ groups = request.user.groups.values_list('name', flat=True)
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group_private = False
+ private_check = 'checked="checked"'
+ else:
+ groups = request.user.groups.values_list('name', flat=True)[1:]
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 1]
+ group_private = True
+ private_check = ''
+
+ # get group obj
+ group = Group.objects.get(name=parent_group)
+
+ # init checkboxes
+ enabled = False
+ personal_data = False
+ medical_data = False
+ custom_data = False
+ custom_group_bool = False
+ staff_only = False
+ name = ""
+ custom_group = ""
+ max_instances = 0
+
+ enabled_check = 'checked="checked"'
+ personal_check = 'checked="checked"'
+ sign_check = 'checked="checked"'
+ medical_check = ""
+ custom_check = ""
+ custom_message_check = ""
+ staff_only_check = ""
+
+ # if type create request sent
+ if request.method == "POST":
+ # gather inserted data
+ enabled = "enabled" in request.POST.keys()
+ auto_sign = "sign" not in request.POST.keys()
+ group_private = "group_private" in request.POST.keys()
+ personal_data = "personal_data" in request.POST.keys()
+ medical_data = "medical_data" in request.POST.keys()
+ custom_data = "custom_data" in request.POST.keys()
+ custom_message = "custom_message" in request.POST.keys()
+ staff_only = "staff_only" in request.POST.keys()
+ custom_message_text = request.POST["custom_message_text"]
+ name = request.POST["name"]
+ custom_group = request.POST["custom_group"]
+
+ if request.POST["max_instances"]:
+ max_instances = request.POST["max_instances"]
+ if not max_instances.isdigit():
+ context["error"] = "true"
+ context["error_text"] = "Il numero massimo di iscritti deve essere un numero"
+ return render(request, 'server/doc_create.html', context)
+ max_instances = int(max_instances)
+
+ # if group not primary and not public throw error
+ if group_private == True and not request.user.is_staff:
+ context["error"] = "true"
+ context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario"
+ return render(request, 'server/doc_create.html', context)
+
+ # if already existing name throw error
+ if len(DocumentType.objects.filter(name=name)) > 0:
+ context["error"] = "true"
+ context["error_text"] = "Questo nome esiste già. Prego usarne un altro."
+ return render(request, 'server/doc_create.html', context)
+
+ # check if custom group permissions not met or non public document
+ if custom_group != "":
+ if group_private == True:
+ context["error"] = "true"
+ context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario"
+ return render(request, 'server/doc_create.html', context)
+ if custom_group not in groups:
+ context["error"] = "true"
+ context["error_text"] = "Non puoi creare un tipo assegnato ad un gruppo di cui non fai parte"
+ return render(request, 'server/doc_create.html', context)
+ else:
+ group = Group.objects.filter(name=custom_group)[0]
+ custom_group_bool = True
+
+ # create type
+ doctype = DocumentType(
+ custom_group=custom_group_bool, auto_sign=auto_sign, custom_message=custom_message, custom_message_text=custom_message_text, name=request.POST["name"], enabled=enabled, group_private=group_private, group=group, personal_data=personal_data, medical_data=medical_data, custom_data=custom_data, staff_only=staff_only, max_instances=max_instances)
+ doctype.save()
+
+ # create custom keys
+ if custom_data:
+ custom = request.POST["custom"]
+ custom.replace("\r", "")
+ custom = custom.split("\n")
+ for i in custom:
+ key = Keys(key=i, container=doctype)
+ key.save()
+
+ return HttpResponseRedirect('doctype')
+
+ # build context
+ context = {
+ "enabled_check": enabled_check,
+ "private_check": private_check,
+ "sign_check": sign_check,
+ "personal_check": personal_check,
+ "medical_check": medical_check,
+ "custom_check": custom_check,
+ "staff_only_check": staff_only_check,
+ "custom_message_check": custom_message_check,
+ }
+
+ return render(request, 'server/doc_create.html', context)
+
+@user_passes_test(isStaff)
+def docedit(request):
+ # create an edit page with empty context
+ return docedit_wrapper(request, {})
+
+@user_passes_test(isStaff)
+def docedit_wrapper(request, context):
+
+ if request.user.is_staff and "group" in context.keys():
+ base_group = request.user.groups.values_list('name', flat=True)[0]
+ if context["group"] == base_group:
+ context["group"] = ""
+
+ if request.method == "POST":
+ if "action" not in request.POST.keys():
+ # get groups on which the user has control
+ if request.user.is_staff:
+ groups = request.user.groups.values_list('name', flat=True)
+ else:
+ groups = request.user.groups.values_list('name', flat=True)[1:]
+
+ group = Group.objects.get(name=groups[0])
+
+ # get document
+ doc = DocumentType.objects.get(id=request.POST["doc"])
+
+ # check if user can edit type
+ if doc.group.name not in groups:
+ # user is cheating abort
+ return
+
+ # init variables
+ custom_group_bool = False
+ custom_group = ""
+ max_instances = 0
+
+ enabled_check = 'checked="checked"' if doc.enabled else ""
+ sign_check = 'checked="checked"' if not doc.auto_sign else ""
+ custom_message_check = 'checked="checked"' if doc.custom_message else ""
+ staff_only_check = 'checked="checked"' if doc.staff_only else ""
+ private_check = 'checked="checked"' if doc.group_private else ""
+
+ context = {
+ 'doc': doc,
+ "group": doc.group.name,
+ "enabled_check": enabled_check,
+ "private_check": private_check,
+ "sign_check": sign_check,
+ "staff_only_check": staff_only_check,
+ "custom_message_check": custom_message_check,
+ }
+
+ if request.user.is_staff:
+ if context["group"] == group.name:
+ context["group"] = ""
+
+ # gather inserted data
+ enabled = "enabled" in request.POST.keys()
+ auto_sign = "sign" not in request.POST.keys()
+ group_private = "group_private" in request.POST.keys()
+ custom_message = "custom_message" in request.POST.keys()
+ staff_only = "staff_only" in request.POST.keys()
+ custom_message_text = request.POST["custom_message_text"]
+ custom_group = request.POST["custom_group"]
+
+ if request.POST["max_instances"]:
+ max_instances = request.POST["max_instances"]
+ if not max_instances.isdigit():
+ context["error"] = "true"
+ context["error_text"] = "Il numero massimo di iscritti deve essere un numero"
+ return render(request, 'server/doc_edit.html', context)
+ max_instances = int(max_instances)
+
+ # if group not primary and not public throw error
+ if group_private == True and not request.user.is_staff:
+ context["error"] = "true"
+ context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario"
+ return render(request, 'server/doc_edit.html', context)
+
+ # check if custom group permissions not met or non public document
+ if custom_group != "":
+ if group_private == True:
+ context["error"] = "true"
+ context["error_text"] = "Non puoi creare un documento non pubblico per un gruppo non primario"
+ return render(request, 'server/doc_edit.html', context)
+ if custom_group not in groups:
+ context["error"] = "true"
+ context["error_text"] = "Non puoi creare un tipo assegnato ad un gruppo di cui non fai parte"
+ return render(request, 'server/doc_edit.html', context)
+ else:
+ group = Group.objects.filter(name=custom_group)[0]
+ custom_group_bool = True
+
+ # edit type
+ doc.custom_group = custom_group_bool
+ doc.auto_sign = auto_sign
+ doc.custom_message = custom_message
+ doc.custom_message_text = custom_message_text
+ doc.enabled = enabled
+ doc.group_private = group_private
+ doc.group = group
+ doc.staff_only = staff_only
+ doc.max_instances = max_instances
+
+ doc.save()
+
+ return HttpResponseRedirect('doctype')
+
+ return render(request, 'server/doc_edit.html', context)
+
+@user_passes_test(isStaff)
+def doclist(request):
+ context = {}
+
+ # group name and obj
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group = Group.objects.get(name=parent_group)
+
+ # if user not staff of primary get secondary groups
+ if request.user.is_staff:
+ parent_groups = request.user.groups.values_list('name', flat=True)
+ else:
+ parent_groups = request.user.groups.values_list('name', flat=True)[1:]
+
+ # create typezone
+ zurich = pytz.timezone('Europe/Zurich')
+
+ # init error variables for users
+ error = False
+ error_text = ""
+
+ # init checkboxes for filter
+ hidden = False
+ wait = True
+ selfsign = True
+ ok = True
+ signdoc = False
+
+ hidden_check = 'checked="checked"'
+ wait_check = 'checked="checked"'
+ selfsign_check = 'checked="checked"'
+ ok_check = 'checked="checked"'
+ signdoc_check = 'checked="checked"'
+
+ # set default dates for filters
+ newer = zurich.localize(dateparser.parse("1970-01-01"))
+ older = zurich.localize(datetime.now())
+
+ # init chips values
+ owner = []
+ types = []
+ groups = []
+ chips_owner = []
+ chips_types = []
+ chips_groups = []
+
+ if request.method == "POST":
+ # if download request
+ if request.POST["action"][0] == 'k':
+ document = Document.objects.get(id=request.POST["action"][1:])
+ # check if user has permission to view doc
+ if document.group.name in parent_groups:
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+
+ # prepare images in base64
+ if document.medical_data:
+ if document.medical_data.vac_certificate.name:
+ with open(document.medical_data.vac_certificate.name, 'rb') as image_file:
+ vac_file = base64.b64encode(
+ image_file.read()).decode()
+
+ if document.medical_data.health_care_certificate.name:
+ with open(document.medical_data.health_care_certificate.name, 'rb') as image_file:
+ health_file = base64.b64encode(
+ image_file.read()).decode()
+
+ if document.signed_doc:
+ with open(document.signed_doc.name, 'rb') as image_file:
+ sign_doc_file = base64.b64encode(
+ image_file.read()).decode()
+
+ # build with template and render
+ template = get_template('server/download_doc.html')
+ doc = [document, KeyVal.objects.filter(
+ container=document), document.personal_data, document.medical_data, parent_group]
+ context = {'doc': doc, 'vac': vac_file,
+ 'health': health_file, 'sign_doc_file': sign_doc_file}
+ html = template.render(context)
+ pdf = pdfkit.from_string(html, False)
+ result = BytesIO(pdf)
+ result.seek(0)
+ return FileResponse(result, as_attachment=True, filename=document.user.username+"_"+document.document_type.name+".pdf")
+
+ # get selected documents and check if user has permission to view
+ selected = []
+ for i in request.POST.keys():
+ if i.isdigit():
+ docc = Document.objects.get(id=i)
+ if docc.group.name in parent_groups:
+ selected.append(docc)
+
+ # execute action on selected documents
+ for i in selected:
+ if request.POST["action"] == 'delete' and settings.DEBUG:
+ i.delete()
+ elif request.POST["action"] == 'approve' and settings.DEBUG:
+ i.status = 'ok'
+ i.save()
+ elif request.POST["action"] == 'archive':
+ if i.status == 'ok':
+ i.status = 'archive'
+ if i.medical_data:
+ i.medical_data.delete()
+ i.medical_data.save()
+ i.medical_data = None
+ i.save()
+ else:
+ error = True
+ error_text = "Non puoi archiviare un documento non approvato"
+ elif request.POST["action"] == 'unarchive':
+ if i.status == 'archive':
+ i.status = 'ok'
+ i.save()
+ else:
+ error = True
+ error_text = "Non puoi dearchiviare un documento non archiviato"
+
+ # get filter values
+ hidden = "filter_hidden" in request.POST
+ wait = "filter_wait" in request.POST
+ selfsign = "filter_selfsign" in request.POST
+ ok = "filter_ok" in request.POST
+ signdoc = "filter_signdoc" in request.POST
+ newer = zurich.localize(dateparser.parse(request.POST["newer"]))
+ older = zurich.localize(dateparser.parse(
+ request.POST["older"]) + timedelta(days=1))
+ owner = request.POST["owner"].split("^|")
+ types = request.POST["type"].split("^|")
+ groups = request.POST["groups"].split("^|")
+
+ # clear filters
+ if request.POST["action"] == 'clear':
+ hidden = False
+ wait = True
+ selfsign = True
+ ok = True
+ signdoc = False
+ newer = zurich.localize(dateparser.parse("1970-01-01"))
+ older = zurich.localize(datetime.now())
+ owner = []
+ types = []
+ groups = []
+
+ # filter documents based on group of staff
+ q_obj = Q()
+ for i in parent_groups:
+ q_obj |= Q(group__name=i)
+
+ documents = Document.objects.filter(q_obj)
+
+ # filter documents
+ if not hidden:
+ documents = documents.filter(~Q(status="archive"))
+ hidden_check = ""
+ if not wait:
+ documents = documents.filter(~Q(status="wait"))
+ wait_check = ""
+ if not selfsign:
+ documents = documents.filter(~Q(status="autosign"))
+ selfsign_check = ""
+ if not ok:
+ documents = documents.filter(~Q(status="ok"))
+ ok_check = ""
+ if not signdoc:
+ signdoc_check = ""
+
+ # filter date range
+ documents = documents.filter(compilation_date__range=[newer, older])
+
+ # filter types, owner, groups using chips
+ if len(types) > 0:
+ if types[0] != "":
+ q_obj = Q()
+ for t in types:
+ q_obj |= Q(document_type__name=t)
+ chips_types.append(t)
+
+ documents = documents.filter(q_obj)
+
+ if len(owner) > 0:
+ if owner[0] != "":
+ q_obj = Q()
+ for u in owner:
+ user = u.split("(")[0][:-1]
+ q_obj |= Q(user__username=user)
+ chips_owner.append(u)
+
+ documents = documents.filter(q_obj)
+
+ if len(groups) > 0:
+ if groups[0] != "":
+ q_obj = Q()
+ for g in groups:
+ q_obj |= Q(group__name=g)
+ chips_groups.append(g)
+
+ documents = documents.filter(q_obj)
+
+ out = []
+ for i in documents:
+ # filter for confirmed with attachment documents and approved
+ if signdoc:
+ if i.status == "ok" and not i.signed_doc:
+ continue
+
+ # prepare images in base64
+ personal = None
+ medical = None
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+ if i.personal_data:
+ personal = i.personal_data
+ if i.medical_data:
+ medical = i.medical_data
+ if medical.vac_certificate.name:
+ vac_file = "/server/media/" + str(i.id) + "/vac_certificate/doc"
+
+ if medical.health_care_certificate.name:
+ health_file = "/server/media/" + str(i.id) + "/health_care_certificate/doc"
+
+ if i.signed_doc:
+ sign_doc_file = "/server/media/" + str(i.id) + "/signed_doc/doc"
+
+ doc_group = i.user.groups.values_list('name', flat=True)[0]
+
+ out.append([i, KeyVal.objects.filter(container=i), personal,
+ medical, doc_group, vac_file, health_file, sign_doc_file])
+
+ # get types and users for chips autocompletation
+ auto_types = DocumentType.objects.filter(
+ Q(group_private=False) | Q(group=group))
+ users = User.objects.filter(groups__name=parent_group)
+
+ context = {
+ "types": auto_types,
+ "users": users,
+ "groups": parent_groups,
+ "docs": out,
+ "hidden_check": hidden_check,
+ "wait_check": wait_check,
+ "selfsign_check": selfsign_check,
+ "ok_check": ok_check,
+ "signdoc_check": signdoc_check,
+ "newer": newer,
+ "older": older,
+ "chips_owner": chips_owner,
+ "chips_type": chips_types,
+ "chips_groups": chips_groups,
+ 'error': error,
+ 'error_text': error_text,
+ 'settings': settings,
+ }
+
+ # check if download multiple documents
+ if request.method == "POST":
+ if "status" not in request.session:
+ request.session['status'] = True
+
+ if request.POST["action"] == "download" and len(selected) > 0 and request.session['status']:
+ # save data in session
+ request.session['status'] = False
+ request.session['progress'] = 0
+ request.session['total'] = len(selected)
+ # run job
+ threading.Thread(target=zip_documents, args=(selected, request.session.session_key)).start()
+ # flag the client to check for updates
+ context["task_id"] = "0"
+
+ return render(request, 'server/doc_list.html', context)
+
+@user_passes_test(isCapi_enabled)
+def doclist_readonly(request):
+ context = {}
+
+ # group name and obj
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group = Group.objects.get(name=parent_group)
+
+ # send alert
+ users = User.objects.filter(groups__name=parent_group).filter(is_staff=True)
+ user_emails = []
+
+ for i in users:
+ user_emails.append(i.email)
+
+ send_mail(
+ 'Attenzione! ' + request.user.username + ' ha visionato i documenti della branca',
+ "Questo messaggio è stato inviato automaticamente dal sistema di iscrizioni digitali. Ti è arrivata questa mail perchè hai abilitato la possibilità ai tuoi aggiunti di visionare i documenti e un tuo aggiunto ha visionato dei documenti. L'utente con username " + request.user.username + " e con nome registrato " + request.user.first_name + " " + request.user.last_name + " ha visionato dei documenti.",
+ settings.DEFAULT_FROM_EMAIL,
+ user_emails,
+ fail_silently=False,
+ )
+
+
+ # create typezone
+ zurich = pytz.timezone('Europe/Zurich')
+
+ # init error variables for users
+ error = False
+ error_text = ""
+
+ # init checkboxes for filter
+ hidden = False
+ wait = True
+ selfsign = True
+ ok = True
+ signdoc = False
+
+ hidden_check = 'checked="checked"'
+ wait_check = 'checked="checked"'
+ selfsign_check = 'checked="checked"'
+ ok_check = 'checked="checked"'
+ signdoc_check = 'checked="checked"'
+
+ # set default dates for filters
+ newer = zurich.localize(dateparser.parse("1970-01-01"))
+ older = zurich.localize(datetime.now())
+
+ # init chips values
+ owner = []
+ types = []
+ groups = []
+ chips_owner = []
+ chips_types = []
+ chips_groups = []
+
+ if request.method == "POST":
+ # if download request
+ if request.POST["action"][0] == 'k':
+ document = Document.objects.get(id=request.POST["action"][1:])
+ # check if user has permission to view doc
+ if document.group.name == parent_group:
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+
+ # prepare images in base64
+ if document.medical_data:
+ if document.medical_data.vac_certificate.name:
+ with open(document.medical_data.vac_certificate.name, 'rb') as image_file:
+ vac_file = base64.b64encode(
+ image_file.read()).decode()
+
+ if document.medical_data.health_care_certificate.name:
+ with open(document.medical_data.health_care_certificate.name, 'rb') as image_file:
+ health_file = base64.b64encode(
+ image_file.read()).decode()
+
+ if document.signed_doc:
+ with open(document.signed_doc.name, 'rb') as image_file:
+ sign_doc_file = base64.b64encode(
+ image_file.read()).decode()
+
+ # build with template and render
+ template = get_template('server/download_doc.html')
+ doc = [document, KeyVal.objects.filter(
+ container=document), document.personal_data, document.medical_data, parent_group]
+ context = {'doc': doc, 'vac': vac_file,
+ 'health': health_file, 'sign_doc_file': sign_doc_file}
+ html = template.render(context)
+ pdf = pdfkit.from_string(html, False)
+ result = BytesIO(pdf)
+ result.seek(0)
+ return FileResponse(result, as_attachment=True, filename=document.user.username+"_"+document.document_type.name+".pdf")
+
+ # get selected documents and check if user has permission to view
+ selected = []
+ for i in request.POST.keys():
+ if i.isdigit():
+ docc = Document.objects.get(id=i)
+ if docc.group.name == parent_group:
+ selected.append(docc)
+
+ # get filter values
+ hidden = "filter_hidden" in request.POST
+ wait = "filter_wait" in request.POST
+ selfsign = "filter_selfsign" in request.POST
+ ok = "filter_ok" in request.POST
+ signdoc = "filter_signdoc" in request.POST
+ newer = zurich.localize(dateparser.parse(request.POST["newer"]))
+ older = zurich.localize(dateparser.parse(
+ request.POST["older"]) + timedelta(days=1))
+ owner = request.POST["owner"].split("^|")
+ types = request.POST["type"].split("^|")
+ groups = request.POST["groups"].split("^|")
+
+ # clear filters
+ if request.POST["action"] == 'clear':
+ hidden = False
+ wait = True
+ selfsign = True
+ ok = True
+ signdoc = False
+ newer = zurich.localize(dateparser.parse("1970-01-01"))
+ older = zurich.localize(datetime.now())
+ owner = []
+ types = []
+ groups = []
+
+ # filter documents based on group of staff
+ documents = Document.objects.filter(group__name=parent_group)
+
+ # filter documents
+ if not hidden:
+ documents = documents.filter(~Q(status="archive"))
+ hidden_check = ""
+ if not wait:
+ documents = documents.filter(~Q(status="wait"))
+ wait_check = ""
+ if not selfsign:
+ documents = documents.filter(~Q(status="autosign"))
+ selfsign_check = ""
+ if not ok:
+ documents = documents.filter(~Q(status="ok"))
+ ok_check = ""
+ if not signdoc:
+ signdoc_check = ""
+
+ # filter date range
+ documents = documents.filter(compilation_date__range=[newer, older])
+
+ # filter types, owner, groups using chips
+ if len(types) > 0:
+ if types[0] != "":
+ q_obj = Q()
+ for t in types:
+ q_obj |= Q(document_type__name=t)
+ chips_types.append(t)
+
+ documents = documents.filter(q_obj)
+
+ if len(owner) > 0:
+ if owner[0] != "":
+ q_obj = Q()
+ for u in owner:
+ user = u.split("(")[0][:-1]
+ q_obj |= Q(user__username=user)
+ chips_owner.append(u)
+
+ documents = documents.filter(q_obj)
+
+ if len(groups) > 0:
+ if groups[0] != "":
+ q_obj = Q()
+ for g in groups:
+ q_obj |= Q(group__name=g)
+ chips_groups.append(g)
+
+ documents = documents.filter(q_obj)
+
+ out = []
+ for i in documents:
+ # filter for confirmed with attachment documents and approved
+ if signdoc:
+ if i.status == "ok" and not i.signed_doc:
+ continue
+
+ # prepare images in base64
+ personal = None
+ medical = None
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+ if i.personal_data:
+ personal = i.personal_data
+ if i.medical_data:
+ medical = i.medical_data
+ if medical.vac_certificate.name:
+ vac_file = "/server/media/" + str(i.id) + "/vac_certificate/doc"
+
+ if medical.health_care_certificate.name:
+ health_file = "/server/media/" + str(i.id) + "/health_care_certificate/doc"
+
+ if i.signed_doc:
+ sign_doc_file = "/server/media/" + str(i.id) + "/signed_doc/doc"
+
+ doc_group = i.user.groups.values_list('name', flat=True)[0]
+
+ out.append([i, KeyVal.objects.filter(container=i), personal,
+ medical, doc_group, vac_file, health_file, sign_doc_file])
+
+ # get types and users for chips autocompletation
+ auto_types = DocumentType.objects.filter(
+ Q(group_private=False) | Q(group=group))
+ users = User.objects.filter(groups__name=parent_group)
+
+ context = {
+ "types": auto_types,
+ "users": users,
+ "groups": [parent_group],
+ "docs": out,
+ "hidden_check": hidden_check,
+ "wait_check": wait_check,
+ "selfsign_check": selfsign_check,
+ "ok_check": ok_check,
+ "signdoc_check": signdoc_check,
+ "newer": newer,
+ "older": older,
+ "chips_owner": chips_owner,
+ "chips_type": chips_types,
+ "chips_groups": chips_groups,
+ 'error': error,
+ 'error_text': error_text,
+ 'settings': settings,
+ }
+
+ # check if download multiple documents
+ if request.method == "POST":
+ if "status" not in request.session:
+ request.session['status'] = True
+
+ if request.POST["action"] == "download" and len(selected) > 0 and request.session['status']:
+ # save data in session
+ request.session['status'] = False
+ request.session['progress'] = 0
+ request.session['total'] = len(selected)
+ # run job
+ threading.Thread(target=zip_documents, args=(selected, request.session.session_key)).start()
+ # flag the client to check for updates
+ context["task_id"] = "0"
+
+ return render(request, 'server/doc_list_readonly.html', context)
+
+def get_progress(request):
+ # if user wants to download result
+ if 'download' in request.GET:
+ # if job is completed
+ if request.session['status']:
+ data = BytesIO(base64.b64decode(request.session['result']))
+ data.seek(0)
+ return FileResponse(data, as_attachment=True, filename="documents_" + datetime.now().strftime("%H_%M-%d_%m_%y") + ".zip")
+
+ # otherwise return status
+ data = [request.session['progress'], request.session['total'], request.session['status']]
+ return HttpResponse(json.dumps(data))
+
+def zip_documents(docs, session_key):
+ files = []
+ # get session
+ session = SessionStore(session_key=session_key)
+ for i in docs:
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+
+ # prepare pictures in base64
+ if i.medical_data:
+ if i.medical_data.vac_certificate.name:
+ with open(i.medical_data.vac_certificate.name, 'rb') as image_file:
+ vac_file = base64.b64encode(
+ image_file.read()).decode()
+
+ if i.medical_data.health_care_certificate.name:
+ with open(i.medical_data.health_care_certificate.name, 'rb') as image_file:
+ health_file = base64.b64encode(
+ image_file.read()).decode()
+ if i.signed_doc:
+ with open(i.signed_doc.name, 'rb') as image_file:
+ sign_doc_file = base64.b64encode(
+ image_file.read()).decode()
+
+ template = get_template('server/download_doc.html')
+ doc = [i, KeyVal.objects.filter(
+ container=i), i.personal_data, i.medical_data, i.user.groups.values_list('name', flat=True)[0]]
+ context = {'doc': doc, 'vac': vac_file,
+ 'health': health_file, 'sign_doc_file': sign_doc_file}
+ # render context
+ html = template.render(context)
+ # render pdf using wkhtmltopdf
+ pdf = pdfkit.from_string(html, False)
+ filename = i.user.username+"_"+i.document_type.name+".pdf"
+ # append file
+ files.append((filename, pdf))
+ session['progress'] += 1
+ session.save()
+
+ # zip documents
+ mem_zip = BytesIO()
+ with zipfile.ZipFile(mem_zip, mode="w",compression=zipfile.ZIP_DEFLATED) as zf:
+ for f in files:
+ zf.writestr(f[0], f[1])
+
+ mem_zip.seek(0)
+ # save result
+ session['result'] = base64.b64encode(mem_zip.getvalue()).decode()
+ session['status'] = True
+ session.save()
+
+
+@user_passes_test(isStaff)
+def upload_doc(request):
+ # setup group based on staff primary or not
+ parent_group = request.user.groups.values_list('name', flat=True)[
+ 0]
+ group = Group.objects.get(name=parent_group)
+ if request.user.is_staff:
+ groups = request.user.groups.values_list('name', flat=True)
+ else:
+ groups = request.user.groups.values_list('name', flat=True)[1:]
+
+ # setup variables for error text and success text
+ error = False
+ success = False
+ error_text = ""
+ success_text = ""
+
+ document = None
+ # parse document code and check for permissions
+ if request.method == "POST":
+ data = request.POST["code"]
+ if not data.isdigit():
+ error_text = "Formato codice errato"
+ error = True
+ elif int(data) < 100000 or int(data) > 999999:
+ error_text = "Formato codice errato"
+ error = True
+ elif len(Document.objects.filter(code=data)) == 0:
+ error_text = "Codice invalido"
+ error = True
+ elif Document.objects.filter(code=data)[0].group.name not in groups:
+ error_text = "Codice invalido"
+ error = True
+ else:
+ # get document
+ document = Document.objects.filter(code=data)[0]
+
+ # prepare success message
+ if document.status == 'ok':
+ success_text = "File caricato"
+ success = True
+ else:
+ document.status = 'ok'
+ document.save()
+ success_text = "Documento approvato e file caricato"
+ success = True
+
+ # check for errors and upload files
+ if "doc_sign" in request.FILES and not error:
+ myfile = request.FILES['doc_sign']
+ try:
+ im = Image.open(myfile)
+ im_io = BytesIO()
+ # compress image in WEBP
+ im.save(im_io, 'WEBP', quality=50)
+ document.signed_doc.save(data+"_"+myfile.name, im_io)
+ document.save()
+ except UnidentifiedImageError:
+ error = True
+ error_text = "Il file non è un immagine valida"
+ else:
+ error = True
+ error_text = "Prego caricare un file"
+
+ context = {
+ "error": error,
+ "error_text": error_text,
+ "success": success,
+ "success_text": success_text,
+ }
+
+ return render(request, 'server/upload_doc.html', context)
+
+
+@user_passes_test(isStaff)
+def docpreview(request):
+ context = {}
+ # check for permissions
+ if request.user.is_staff:
+ groups = request.user.groups.values_list('name', flat=True)
+ else:
+ groups = request.user.groups.values_list('name', flat=True)[1:]
+
+ if request.method == "POST":
+ # get document code
+ code = request.POST["preview"]
+
+ # check if code valid and user has permission
+ if not code.isdigit():
+ return render(request, 'server/download_doc.html', context)
+ if len(Document.objects.filter(code=code)) == 0:
+ return render(request, 'server/download_doc.html', context)
+ if Document.objects.filter(code=code)[0].group.name not in groups:
+ return render(request, 'server/download_doc.html', context)
+
+ # get document
+ document = Document.objects.filter(code=code)[0]
+ parent_group = document.user.groups.values_list('name', flat=True)[0]
+
+ # user has not permission to view document
+ if parent_group not in groups:
+ return
+
+ # prepare images in base64
+ vac_file = ""
+ health_file = ""
+ sign_doc_file = ""
+ if document.medical_data:
+ if document.medical_data.vac_certificate.name:
+ with open(document.medical_data.vac_certificate.name, 'rb') as image_file:
+ vac_file = base64.b64encode(image_file.read()).decode()
+
+ if document.medical_data.health_care_certificate.name:
+ with open(document.medical_data.health_care_certificate.name, 'rb') as image_file:
+ health_file = base64.b64encode(image_file.read()).decode()
+ if document.signed_doc:
+ with open(document.signed_doc.name, 'rb') as image_file:
+ sign_doc_file = base64.b64encode(image_file.read()).decode()
+
+ # prepare context
+ doc = [document, KeyVal.objects.filter(
+ container=document), document.personal_data, document.medical_data, parent_group]
+ context = {'doc': doc, 'vac': vac_file,
+ 'health': health_file, 'sign_doc_file': sign_doc_file}
+
+ return render(request, 'server/download_doc.html', context)
+
+
+@user_passes_test(isStaff)
+def data_request(request):
+ context = {}
+ parent_group = request.user.groups.values_list('name', flat=True)[0]
+
+ if request.method == "POST":
+ if request.POST["request"] == "email_all":
+ users = User.objects.filter(groups__name=parent_group)
+ data = ""
+ for user in users:
+ data += user.email + ", "
+ data = data[:-2]
+ context["data"] = data
+ elif request.POST["request"] == "email_non_staff":
+ users = User.objects.filter(groups__name=parent_group).exclude(groups__name="capi")
+ data = ""
+ for user in users:
+ data += user.email + ", "
+ data = data[:-2]
+ context["data"] = data
+ elif request.POST["request"] == "data_user":
+ users = User.objects.filter(groups__name=parent_group)
+
+ # get time for filename
+ current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y")
+
+ response = HttpResponse()
+ response['Content-Disposition'] = 'attachment; filename="data_export_' + current_time + '.csv"'
+
+ writer = csv.writer(response)
+
+ # csv header
+ writer.writerow(["Nome", "Cognome", "Email", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS"])
+
+ for user in users:
+ usercode = UserCode.objects.filter(user=user)[0]
+ writer.writerow([
+ user.first_name,
+ user.last_name,
+ user.email,
+ usercode.parent_name,
+ usercode.via,
+ usercode.cap,
+ usercode.country,
+ usercode.nationality,
+ usercode.born_date,
+ usercode.home_phone,
+ usercode.phone,
+ usercode.school,
+ usercode.year,
+ usercode.avs_number
+ ])
+
+ return response
+
+ elif request.POST["request"] == "data_user_medic":
+ users = User.objects.filter(groups__name=parent_group)
+
+ # get time for filename
+ current_time = datetime.strftime(datetime.now(), "%H_%M__%d_%m_%y")
+
+ response = HttpResponse()
+ response['Content-Disposition'] = 'attachment; filename="data_export_' + current_time + '.csv"'
+
+ writer = csv.writer(response)
+
+ # csv header
+ writer.writerow(["Nome", "Cognome", "Email", "Nome dei genitori", "Via", "CAP", "Paese", "Nazionalita", "Data di nascita", "Telefono di casa", "Telefono", "Scuola", "Anno scolastico", "Numero AVS", "Contatto d'emergenza", "Parentela del contatto", "Telefono d'emergenza", "Cellulare emergenza", "Indirizzo completo emergenza", "Cassa malati", "Ass. Infortuni", "Ass. RC", "Socio REGA", "Nome del medico", "Telefono medico", "Indirizzo medico", "Malattie", "Vacinazioni", "Data antitetanica", "Allergie", "Assume medicamenti", "Medicamenti", "Informazioni particolari", "Informazioni"])
+
+ for user in users:
+ usercode = UserCode.objects.filter(user=user)[0]
+ medic = usercode.medic
+ writer.writerow([
+ user.first_name,
+ user.last_name,
+ user.email,
+ usercode.parent_name,
+ usercode.via,
+ usercode.cap,
+ usercode.country,
+ usercode.nationality,
+ usercode.born_date,
+ usercode.home_phone,
+ usercode.phone,
+ usercode.school,
+ usercode.year,
+ usercode.avs_number,
+ medic.emer_name,
+ medic.emer_relative,
+ medic.emer_phone,
+ medic.cell_phone,
+ medic.address,
+ medic.health_care,
+ medic.injuries,
+ medic.rc,
+ medic.rega,
+ medic.medic_name,
+ medic.medic_phone,
+ medic.medic_address,
+ medic.sickness,
+ medic.vaccine,
+ medic.tetanus_date,
+ medic.allergy,
+ medic.drugs_bool,
+ medic.drugs,
+ medic.misc_bool,
+ medic.misc
+ ])
+
+ return response
+ return render(request, 'server/data_request.html', context)
+
+def media_request(request, id=0, t="", flag=""):
+ if flag == "usercode":
+ usercode = UserCode.objects.get(id=id)
+ if request.user.is_staff:
+ groups = request.user.groups.values_list('name', flat=True)
+ usercode_group = usercode.user.groups.values_list('name', flat=True)[0]
+ if usercode_group not in groups:
+ return
+ else:
+ if usercode.user != request.user:
+ return
+
+ if t == "health_care_certificate":
+ image_file = usercode.medic.health_care_certificate
+ elif t == "vac_certificate":
+ image_file = usercode.medic.vac_certificate
+
+ elif flag == "doc":
+ doc = Document.objects.get(id=id)
+ doc_group = doc.user.groups.values_list('name', flat=True)[0]
+
+ # check if user can view media
+ if request.user.is_staff:
+ # user is staff
+ groups = request.user.groups.values_list('name', flat=True)
+ if doc_group not in groups:
+ return
+ elif request.user.has_perm("client.staff"):
+ # user is psudo-staff
+ groups = request.user.groups.values_list('name', flat=True)[1:]
+ if doc_group not in groups:
+ return
+ else:
+ # is normal user
+ if doc.user != request.user:
+ return
+
+ if t == "health_care_certificate":
+ image_file = doc.medical_data.health_care_certificate
+ elif t == "vac_certificate":
+ image_file = doc.medical_data.vac_certificate
+ elif t == "signed_doc":
+ image_file = doc.signed_doc
+
+ return FileResponse(image_file, filename=image_file.name)
diff --git a/templates/registration/base_client.html b/templates/registration/base_client.html index fcef3b0..edf4d2b 100644 --- a/templates/registration/base_client.html +++ b/templates/registration/base_client.html @@ -86,6 +86,9 @@ {% endblock %} <ul class="right"> {% if user.is_authenticated %} + {% if group_view and not user.is_staff %} + <li class="hide-on-small-only"><a class="modal-trigger" href="#modal_capi">Lista documenti</a></li> + {% endif %} {% if user.is_staff or perms.client.staff %} <li class="hide-on-small-only"><a href="{% url 'server' %}">Pannello Admin</a></li> {% endif %} @@ -94,6 +97,9 @@ {% if user.is_staff or perms.client.staff %} <li class="tooltipped hide-on-med-and-up" data-position="bottom" data-tooltip="Pannello Admin" class="hide-on-med-and-up"><a href="{% url 'server' %}"><i class="material-icons">build</i></a></li> {% endif %} + {% if group_view and not user.is_staff %} + <li class="tooltipped hide-on-med-and-up" data-position="bottom" data-tooltip="Lista documenti" class="hide-on-med-and-up"><a class="modal-trigger" href="#modal_capi"><i class="material-icons">list</i></a></li> + {% endif %} <li class="tooltipped" data-position="bottom" data-tooltip="Informazioni"><a href="{% url 'about' %}"><i class="material-icons">info_outline</i></a></li> <li class="tooltipped" data-position="bottom" data-tooltip="Logout"><a href="{% url 'logout' %}"><i class="material-icons">exit_to_app</i></a></li> {% else %} diff --git a/version.txt b/version.txt index 766a5d5..152e6d1 100644 --- a/version.txt +++ b/version.txt @@ -1,2 +1,2 @@ -version=0.2 -rev=4 +version=0.3
+rev=1 |