aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrea Lepori <alepori@student.ethz.ch>2021-03-17 22:20:58 +0100
committerAndrea Lepori <alepori@student.ethz.ch>2021-03-17 22:21:23 +0100
commit19d120e045991226a07bbe3929bc3ed0db818790 (patch)
tree57b2d6fb5e724b4ef1d030586676d804b273a182
parentadd rev to version and create document from non primary group (diff)
downloadscout-subs-19d120e045991226a07bbe3929bc3ed0db818790.tar.gz
scout-subs-19d120e045991226a07bbe3929bc3ed0db818790.zip
users of group capi can optionally view documents
-rw-r--r--client/migrations/0007_groupsettings.py23
-rw-r--r--client/models.py4
-rw-r--r--client/views.py17
-rw-r--r--server/templates/server/doc_list_readonly.html618
-rw-r--r--server/templates/server/index.html31
-rw-r--r--server/urls.py1
-rw-r--r--server/views.py278
-rw-r--r--templates/registration/base_client.html6
-rw-r--r--version.txt2
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&ugrave; 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&ugrave; 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&agrave;</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&agrave;</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&agrave; civile</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="switch col s12">
+ &Egrave; sostenitore REGA&nbsp;&nbsp;
+ <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&nbsp;&nbsp;
+ <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&igrave; 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)&nbsp;&nbsp;
+ <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&igrave; 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