diff options
author | Andrea Lepori <alepori@student.ethz.ch> | 2021-03-17 22:20:58 +0100 |
---|---|---|
committer | Andrea Lepori <alepori@student.ethz.ch> | 2021-03-17 22:21:23 +0100 |
commit | 19d120e045991226a07bbe3929bc3ed0db818790 (patch) | |
tree | 57b2d6fb5e724b4ef1d030586676d804b273a182 | |
parent | add rev to version and create document from non primary group (diff) | |
download | scout-subs-19d120e045991226a07bbe3929bc3ed0db818790.tar.gz scout-subs-19d120e045991226a07bbe3929bc3ed0db818790.zip |
users of group capi can optionally view documents
-rw-r--r-- | client/migrations/0007_groupsettings.py | 23 | ||||
-rw-r--r-- | client/models.py | 4 | ||||
-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 | 278 | ||||
-rw-r--r-- | templates/registration/base_client.html | 6 | ||||
-rw-r--r-- | version.txt | 2 |
9 files changed, 973 insertions, 7 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/models.py b/client/models.py index d14a267..5b5db6a 100644 --- a/client/models.py +++ b/client/models.py @@ -111,3 +111,7 @@ class UserCode(models.Model): phone = models.CharField(default="", max_length=250) school = models.CharField(default="", max_length=250) year = models.IntegerField(default=0) + +class GroupSettings(models.Model): + group = models.ForeignKey(Group, default=None, on_delete=models.CASCADE) + view_documents = models.BooleanField(default=False)
\ No newline at end of file diff --git a/client/views.py b/client/views.py index 32678f5..6fdd3f2 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 7ba0173..b65b2ea 100644 --- a/server/views.py +++ b/server/views.py @@ -1,5 +1,5 @@ from django.shortcuts import render -from client.models import UserCode, Keys, DocumentType, Document, KeyVal +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 @@ -34,6 +34,14 @@ def isStaff(user): 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 = {} @@ -41,6 +49,31 @@ def index(request): 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 = [] @@ -82,6 +115,7 @@ def index(request): context = { 'docs': docs, } + context["doc_view_check"] = doc_view_check return render(request, 'server/index.html', context) @@ -811,10 +845,6 @@ def doclist(request): 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 @@ -969,6 +999,244 @@ def doclist(request): 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) + + # 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: diff --git a/templates/registration/base_client.html b/templates/registration/base_client.html index fcef3b0..945ac99 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 %} + <li class="hide-on-small-only"><a href="{% url 'doclistro' %}">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 %} + <li class="tooltipped hide-on-med-and-up" data-position="bottom" data-tooltip="Lista documenti" class="hide-on-med-and-up"><a href="{% url 'doclistro' %}"><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 c406ae0..b64ad0e 100644 --- a/version.txt +++ b/version.txt @@ -1,2 +1,2 @@ version=0.2 -rev=1 +rev=2 |