diff options
author | Andrea Lepori <alepori@student.ethz.ch> | 2022-01-04 16:46:44 +0100 |
---|---|---|
committer | Andrea Lepori <alepori@student.ethz.ch> | 2022-01-04 16:47:06 +0100 |
commit | 3d95adfa00bfa0d9bc515d0c9c8479bccd65407b (patch) | |
tree | 1527f820304ab86200147f781f784eaa0cad1bb3 | |
parent | fix disabled fields not submitting (diff) | |
download | scout-subs-3d95adfa00bfa0d9bc515d0c9c8479bccd65407b.tar.gz scout-subs-3d95adfa00bfa0d9bc515d0c9c8479bccd65407b.zip |
logout user if token expired + set password page
Diffstat (limited to '')
-rw-r--r-- | accounts/templates/accounts/index.html | 51 | ||||
-rw-r--r-- | accounts/views.py | 357 | ||||
-rw-r--r-- | client/migrations/0012_remove_usercode_midata_code.py | 17 | ||||
-rw-r--r-- | client/models.py | 1 | ||||
-rw-r--r-- | templates/registration/base_client.html | 4 | ||||
-rw-r--r-- | templates/registration/login.html | 2 | ||||
-rw-r--r-- | version.txt | 2 |
7 files changed, 253 insertions, 181 deletions
diff --git a/accounts/templates/accounts/index.html b/accounts/templates/accounts/index.html index 341fd7d..06dcff2 100644 --- a/accounts/templates/accounts/index.html +++ b/accounts/templates/accounts/index.html @@ -313,12 +313,13 @@ </div> </div> </div> +</form> <div id="settings" class="row"> <div class="col l8 offset-l2 s12"> <div class="card-panel"> <div class="row"> <div class="col s12"> - <h6>Collegamento con MiData</h6> + <h5>Collegamento con MiData</h5> </div> </div> {% if midata_user %} @@ -354,10 +355,49 @@ </div> </div> {% endif %} + <div class="row"> + <div class="col s12"> + <h5>Cambia password</h5> + </div> + </div> + <div class="row"> + <div class="col s12"> + <form method="post"> + {% csrf_token %} + <input type="hidden" name="action" id="action" value="password"> + {% if usable_password %} + <div class="row"> + <div class="col s12"> + <input id="old_password" type="password"> + <label for="old_password">Password attuale</label> + </div> + </div> + {% else %} + <input id="old_password" type="hidden" value=""> + {% endif %} + <div class="row"> + <div class="col s12"> + <input id="new_password1" type="password"> + <label for="new_password1">Nuova password</label> + </div> + </div> + <div class="row"> + <div class="col s12"> + <input id="new_password2" type="password"> + <label for="new_password2">Conferma nuova password</label> + </div> + </div> + <div class="row"> + <div class="col s12"> + <button type="submit" class="btn waves-effect waves-light {{color}}">Salva</button> + </div> + </div> + </form> + </div> + </div> </div> </div> </div> -</form> {% endblock %} {% block script %} @@ -414,10 +454,9 @@ $(document).ready(function() { $('.datepicker').datepicker(options); $('.tabs').tabs(); $('select').formSelect(); - {% if error %} - M.toast({html: '{{ error_text}}', classes: 'orange'}) - {% endif %} - + {% for error in errors %} + M.toast({html: '{{ error }}', classes: 'orange'}) + {% endfor %} document.getElementById("vac_certificate").onchange = function() { for (i=0; i < this.files.length; i++) { if(this.files[i].size > 1048576*10) { diff --git a/accounts/views.py b/accounts/views.py index 598d300..21f33da 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,8 +1,7 @@ from django.shortcuts import render from django.urls import reverse -from django.shortcuts import redirect from django.conf import settings -from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.forms import PasswordChangeForm, UserCreationForm from django.contrib.auth.models import User from django.contrib.auth import login, authenticate, logout from django.http import FileResponse @@ -50,11 +49,16 @@ def get_oauth_data(token): # send to hitobito request to get token def oauth_login(request): redirect_uri = request.build_absolute_uri(reverse('auth')) + + if not request.GET["next"]: + redirect_uri += "?next=/" + else: + redirect_uri += "?next=" + request.GET["next"] + return hitobito.authorize_redirect(request, redirect_uri) # callback after acquiring token def auth(request): - code = request.GET["code"] token = hitobito.authorize_access_token(request) # request data from user account @@ -77,10 +81,9 @@ def auth(request): usercode[0].country = resp_data["town"] usercode[0].born_date = dateparser.parse(resp_data["birthday"]) usercode[0].midata_token = token["access_token"] - usercode[0].midata_code = code usercode[0].save() - return HttpResponseRedirect('/') + return HttpResponseRedirect(request.GET["next"]) user = User.objects.create_user(resp_data["email"], resp_data["email"]) @@ -92,7 +95,7 @@ def auth(request): medic = MedicalData() medic.save() - userCode = UserCode(user=user, code=code, medic=medic, midata_id=resp_data["id"], midata_token=token["access_token"], midata_code=code) + userCode = UserCode(user=user, code=code, medic=medic, midata_id=resp_data["id"], midata_token=token["access_token"]) user.first_name = resp_data["first_name"] user.last_name = resp_data["last_name"] user.email = resp_data["email"] @@ -106,7 +109,7 @@ def auth(request): login(request, user) - return HttpResponseRedirect('/') + return HttpResponseRedirect(request.GET["next"]) # send to hitobito request to get token @login_required @@ -116,10 +119,12 @@ def oauth_connect(request): @login_required def oauth_disconnect(request): + if not request.user.has_usable_password(): + return personal_wrapper(request, ["Il tuo utente non ha una password impostata, impostare una password prima di scollegarlo da MiData"]) + usercode = UserCode.objects.filter(user=request.user)[0] usercode.midata_id = 0 usercode.midata_token = "" - usercode.midata_code = "" usercode.save() return HttpResponseRedirect(reverse("personal") + "#settings") @@ -135,13 +140,12 @@ def auth_connect(request): # check that account is not linked to another existing_codes = UserCode.objects.filter(midata_id=resp_data["id"]) if len(existing_codes) > 0: - return personal_wrapper(request, True, "Questo utente è già collegato ad un altro") + return personal_wrapper(request, ["Questo utente è già collegato ad un altro"]) # save id to user usercode = UserCode.objects.filter(user=request.user)[0] usercode.midata_id = resp_data["id"] usercode.midata_token = token["access_token"] - usercode.midata_code = request.GET["code"] usercode.save() return HttpResponseRedirect(reverse("personal") + "#settings") @@ -199,12 +203,12 @@ def signup(request): # create wrapper to send custom error from other views (oauth connect/disconnect) @login_required def personal(request): - return personal_wrapper(request, False, "") + return personal_wrapper(request, []) @login_required -def personal_wrapper(request, error, error_text): +def personal_wrapper(request, errors): context = {} - # additional user informations + # additional user information usercode = UserCode.objects.filter(user=request.user)[0] # medical info medic = usercode.medic @@ -238,7 +242,7 @@ def personal_wrapper(request, error, error_text): im_io.seek(0) return FileResponse(im_io, as_attachment=True, filename=filename) - if request.POST['action'] == "download_health": + elif request.POST['action'] == "download_health": if medic.health_care_certificate != None: filename = os.path.basename(medic.health_care_certificate.name) filename = filename[filename.find("_")+1:] @@ -253,172 +257,186 @@ def personal_wrapper(request, error, error_text): im_io.seek(0) return FileResponse(im_io, as_attachment=True, filename=filename) - # set all attributes - request.user.first_name = request.POST["first_name"] - request.user.last_name = request.POST["last_name"] - request.user.email = request.POST["email"] - request.user.save() - usercode.parent_name = request.POST["parent_name"] - usercode.via = request.POST["via"] - usercode.cap = request.POST["cap"] - usercode.country = request.POST["country"] - usercode.nationality = request.POST["nationality"] - usercode.born_date = dateparser.parse(request.POST["birth_date"]) - usercode.home_phone = request.POST["home_phone"] - usercode.phone = request.POST["phone"] - usercode.school = request.POST["school"] - usercode.avs_number = request.POST["avs_number"] - - if request.POST["year"].isdigit(): - usercode.year = request.POST["year"] + elif request.POST['action'] == "password": + # get form object + print(request.POST) + + # if form is valid and terms were accepted save user + password_errors = [] + for err in password_errors: + if err.code == "password_mismatch": + errors.append("Le due password non sono uguali") + elif err.code == "password_too_similar": + errors.append("La password è troppo simile all'username") + elif err.code == "password_too_short": + errors.append("La password è troppo corta") + elif err.code == "password_too_common": + errors.append("La password è troppo comune") + elif err.code == "password_entirely_numeric": + errors.append("La password deve contenere lettere") + elif err.code == "password_incorrect": + errors.append("La password attuale è incorretta") + else: - error = True - error_text = "L'anno scolastico deve essere un numero" + # set all attributes + request.user.first_name = request.POST["first_name"] + request.user.last_name = request.POST["last_name"] + request.user.email = request.POST["email"] + request.user.save() + usercode.parent_name = request.POST["parent_name"] + usercode.via = request.POST["via"] + usercode.cap = request.POST["cap"] + usercode.country = request.POST["country"] + usercode.nationality = request.POST["nationality"] + usercode.born_date = dateparser.parse(request.POST["birth_date"]) + usercode.home_phone = request.POST["home_phone"] + usercode.phone = request.POST["phone"] + usercode.school = request.POST["school"] + usercode.avs_number = request.POST["avs_number"] + + if request.POST["year"].isdigit(): + usercode.year = request.POST["year"] + else: + errors.append("L'anno scolastico deve essere un numero") - usercode.save() + usercode.save() - medic.emer_name = request.POST["emer_name"] - medic.emer_relative = request.POST["emer_relative"] - medic.cell_phone = request.POST["cell_phone"] - medic.address = request.POST["address"] - medic.emer_phone = request.POST["emer_phone"] - medic.health_care = request.POST["health_care"] - medic.injuries = request.POST["injuries"] - medic.rc = request.POST["rc"] - medic.rega = "rega" in request.POST - medic.medic_name = request.POST["medic_name"] - medic.medic_phone = request.POST["medic_phone"] - medic.medic_address = request.POST["medic_address"] - medic.sickness = request.POST["sickness"] - medic.vaccine = request.POST["vaccine"] - medic.tetanus_date = dateparser.parse(request.POST["tetanus_date"]) - medic.allergy = request.POST["allergy"] - medic.drugs_bool = "drugs_bool" in request.POST - medic.drugs = request.POST["drugs"] - medic.misc_bool = "misc_bool" in request.POST - medic.misc = request.POST["misc"] - medic.save() - - if request.POST["birth_date"] == "" or request.POST["birth_date"] == "01 Gennaio 1970" or request.POST["birth_date"] == "None": - validation_dic["birth_date"] = 'class="datepicker validate invalid" required="" aria-required="true"' - error = True - error_text = "Alcuni campi richiesti non sono stati compilati" - else: - validation_dic["birth_date"] = 'class="datepicker validate" required="" aria-required="true"' + medic.emer_name = request.POST["emer_name"] + medic.emer_relative = request.POST["emer_relative"] + medic.cell_phone = request.POST["cell_phone"] + medic.address = request.POST["address"] + medic.emer_phone = request.POST["emer_phone"] + medic.health_care = request.POST["health_care"] + medic.injuries = request.POST["injuries"] + medic.rc = request.POST["rc"] + medic.rega = "rega" in request.POST + medic.medic_name = request.POST["medic_name"] + medic.medic_phone = request.POST["medic_phone"] + medic.medic_address = request.POST["medic_address"] + medic.sickness = request.POST["sickness"] + medic.vaccine = request.POST["vaccine"] + medic.tetanus_date = dateparser.parse(request.POST["tetanus_date"]) + medic.allergy = request.POST["allergy"] + medic.drugs_bool = "drugs_bool" in request.POST + medic.drugs = request.POST["drugs"] + medic.misc_bool = "misc_bool" in request.POST + medic.misc = request.POST["misc"] + medic.save() - for i in required_fields: - if request.POST[i] == "": - error = True - error_text = "Alcuni campi richiesti non sono stati compilati" - validation_dic[i] = 'class="validate invalid" required="" aria-required="true"' + missing_fields = False + if request.POST["birth_date"] == "" or request.POST["birth_date"] == "01 Gennaio 1970" or request.POST["birth_date"] == "None": + validation_dic["birth_date"] = 'class="datepicker validate invalid" required="" aria-required="true"' + missing_fields = True else: - validation_dic[i] = 'class="validate" required="" aria-required="true"' - - # if "branca" in request.POST: - # if request.POST["branca"] != "": - # request.user.groups.clear() - # request.user.groups.add( - # Group.objects.get(name=request.POST["branca"])) - - # check if user uploaded a file - if "vac_certificate" in request.FILES: - files = request.FILES.getlist('vac_certificate') - name = files[0].name - try: - # if multiple files concatenate pictures - im = Image.new("RGB", (0, 0), (255, 255, 255)) - for f in files: - if f.name.endswith(".pdf"): - images = convert_from_bytes(f.read()) - for i in images: + validation_dic["birth_date"] = 'class="datepicker validate" required="" aria-required="true"' + + for i in required_fields: + if request.POST[i] == "": + missing_fields = True + validation_dic[i] = 'class="validate invalid" required="" aria-required="true"' + else: + validation_dic[i] = 'class="validate" required="" aria-required="true"' + + if missing_fields: + errors.append("Alcuni campi richiesti non sono stati compilati") + + # if "branca" in request.POST: + # if request.POST["branca"] != "": + # request.user.groups.clear() + # request.user.groups.add( + # Group.objects.get(name=request.POST["branca"])) + + # check if user uploaded a file + if "vac_certificate" in request.FILES: + files = request.FILES.getlist('vac_certificate') + name = files[0].name + try: + # if multiple files concatenate pictures + im = Image.new("RGB", (0, 0), (255, 255, 255)) + for f in files: + if f.name.endswith(".pdf"): + images = convert_from_bytes(f.read()) + for i in images: + dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255)) + dst.paste(im, (0, 0)) + dst.paste(i, (0, im.height)) + im = dst + else: + i = Image.open(f) dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255)) dst.paste(im, (0, 0)) dst.paste(i, (0, im.height)) im = dst - else: - i = Image.open(f) - dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255)) - dst.paste(im, (0, 0)) - dst.paste(i, (0, im.height)) - im = dst - im_io = BytesIO() - # resize image if larger than max value - if im.height > 16383: - im = im.resize((round(im.width/im.height*16383), 16383)) - # compress image in WEBP - im.save(im_io, 'WEBP', quality=50, method=4) - medic.vac_certificate.save( - request.user.username+"_"+name, im_io) - medic.save() - except UnidentifiedImageError: - error = True - error_text = "Il file non è un immagine valida" - except PDFPageCountError: - error = True - error_text = "Il file non è un pdf valido" - except PDFSyntaxError: - error = True - error_text = "Il file non è un pdf valido" - except IOError: - error = True - error_text = "Il file è un immagine troppo grande" - - if "health_care_certificate" in request.FILES: - files = request.FILES.getlist('health_care_certificate') - name = files[0].name - try: - # if multiple files concatenate pictures - im = Image.new("RGB", (0, 0), (255, 255, 255)) - for f in files: - if f.name.endswith(".pdf"): - images = convert_from_bytes(f.read()) - for i in images: + im_io = BytesIO() + # resize image if larger than max value + if im.height > 16383: + im = im.resize((round(im.width/im.height*16383), 16383)) + # compress image in WEBP + im.save(im_io, 'WEBP', quality=50, method=4) + medic.vac_certificate.save( + request.user.username+"_"+name, im_io) + medic.save() + except UnidentifiedImageError: + errors.append("Il certificato delle vaccinazioni non è un immagine valida") + except PDFPageCountError: + errors.append("Il certificato delle vaccinazioni non è un pdf valido") + except PDFSyntaxError: + errors.append("Il certificato delle vaccinazioni non è un pdf valido") + except IOError: + errors.append("Il certificato delle vaccinazioni è un immagine troppo grande") + + if "health_care_certificate" in request.FILES: + files = request.FILES.getlist('health_care_certificate') + name = files[0].name + try: + # if multiple files concatenate pictures + im = Image.new("RGB", (0, 0), (255, 255, 255)) + for f in files: + if f.name.endswith(".pdf"): + images = convert_from_bytes(f.read()) + for i in images: + dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255)) + dst.paste(im, (0, 0)) + dst.paste(i, (0, im.height)) + im = dst + else: + i = Image.open(f) dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255)) dst.paste(im, (0, 0)) dst.paste(i, (0, im.height)) im = dst - else: - i = Image.open(f) - dst = Image.new('RGB', (max(im.width, i.width), im.height + i.height), (255, 255, 255)) - dst.paste(im, (0, 0)) - dst.paste(i, (0, im.height)) - im = dst - im_io = BytesIO() - # resize image if larger than max value - if im.height > 16383: - im = im.resize((round(im.width/im.height*16383), 16383)) - # compress image in WEBP - im.save(im_io, 'WEBP', quality=50, method=4) - medic.health_care_certificate.save( - request.user.username+"_"+name, im_io) + im_io = BytesIO() + # resize image if larger than max value + if im.height > 16383: + im = im.resize((round(im.width/im.height*16383), 16383)) + # compress image in WEBP + im.save(im_io, 'WEBP', quality=50, method=4) + medic.health_care_certificate.save( + request.user.username+"_"+name, im_io) + medic.save() + except UnidentifiedImageError: + errors.append("La tessera della cassa malati non è un immagine valida") + except PDFPageCountError: + errors.append("La tessera della cassa malati non è un pdf valido") + except PDFSyntaxError: + errors.append("La tessera della cassa malati non è un pdf valido") + except IOError: + errors.append("La tessera della cassa malati è un immagine troppo grande") + + # user requested file delete + if request.POST["delete_vac"] == 'vac': + medic.vac_certificate = None medic.save() - except UnidentifiedImageError: - error = True - error_text = "Il file non è un immagine valida" - except PDFPageCountError: - error = True - error_text = "Il file non è un pdf valido" - except PDFSyntaxError: - error = True - error_text = "Il file non è un pdf valido" - except IOError: - error = True - error_text = "Il file è un immagine troppo grande" - - # user requested file delete - if request.POST["delete_vac"] == 'vac': - medic.vac_certificate = None - medic.save() - if request.POST["delete_health"] == 'health': - medic.health_care_certificate = None - medic.save() + if request.POST["delete_health"] == 'health': + medic.health_care_certificate = None + medic.save() - # if there wasn't any error redirect to clear POST - if not error: - return HttpResponseRedirect("") + # if there wasn't any error redirect to clear POST + if len(errors) == 0: + return HttpResponseRedirect("") else: # no post, create empty validation @@ -476,15 +494,8 @@ def personal_wrapper(request, error, error_text): resp = get_oauth_data(usercode.midata_token) if resp.status_code != 200: - request.GET["code"] = usercode.midata_code - token = hitobito.authorize_access_token(request) - usercode.midata_token = token["access_token"] - usercode.save() - resp = get_oauth_data(usercode.midata_token) - - if resp.status_code != 200: logout(request) - return HttpResponseRedirect("/") + return HttpResponseRedirect(request.path_info) resp_data = resp.json() @@ -500,6 +511,8 @@ def personal_wrapper(request, error, error_text): usercode.born_date = dateparser.parse(resp_data["birthday"]) usercode.save() + usable_password = request.user.has_usable_password() + # fill context context = { 'validation_dic': validation_dic, @@ -545,10 +558,10 @@ def personal_wrapper(request, error, error_text): 'misc': medic.misc, 'health_care_certificate': card_name, 'vac_certificate': vac_name, - 'error': error, - 'error_text': error_text, + 'errors': errors, 'midata_user': midata_user, 'midata_disable': midata_disable, + 'usable_password': usable_password, } return render(request, 'accounts/index.html', context) diff --git a/client/migrations/0012_remove_usercode_midata_code.py b/client/migrations/0012_remove_usercode_midata_code.py new file mode 100644 index 0000000..3f3d876 --- /dev/null +++ b/client/migrations/0012_remove_usercode_midata_code.py @@ -0,0 +1,17 @@ +# Generated by Django 3.1.4 on 2022-01-04 15:09 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('client', '0011_usercode_midata_code'), + ] + + operations = [ + migrations.RemoveField( + model_name='usercode', + name='midata_code', + ), + ] diff --git a/client/models.py b/client/models.py index 5f0da0d..b94806b 100644 --- a/client/models.py +++ b/client/models.py @@ -115,7 +115,6 @@ class UserCode(models.Model): avs_number = models.CharField(default="", max_length=250)
midata_id = models.IntegerField(default=0)
midata_token = models.CharField(default="", max_length=1024)
- midata_code = models.CharField(default="", max_length=1024)
class GroupSettings(models.Model):
group = models.ForeignKey(Group, default=None, on_delete=models.CASCADE)
diff --git a/templates/registration/base_client.html b/templates/registration/base_client.html index d90462c..cfb6024 100644 --- a/templates/registration/base_client.html +++ b/templates/registration/base_client.html @@ -12,6 +12,10 @@ color: {{hexcolor}} !important; } + input[type=password]:focus + label, .materialize-textarea:focus:not([readonly]) + label { + color: {{hexcolor}} !important; + } + input[type=text]:focus, .materialize-textarea:focus:not([readonly]) { border-bottom: 1px solid {{hexcolor}} !important; box-shadow: 0 1px 0 0 {{hexcolor}} !important; diff --git a/templates/registration/login.html b/templates/registration/login.html index 8a2b258..cfa4a2b 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -19,7 +19,7 @@ <br><br><hr><br> <div class="row"> <div class="col s12"> - <a href={% url 'oauth_login' %} style="width: 100%; background-color: #99BF62" class="btn waves-effect waves-light"> + <a href="{% url 'oauth_login' %}?next={{ request.GET.next }}" style="width: 100%; background-color: #99BF62" class="btn waves-effect waves-light"> <div class="row"> <div class="col s2"> <img style="height: 30px; padding-top: 3px" src="{% static 'pbs_logo.svg' %}" alt="PBS Logo"> diff --git a/version.txt b/version.txt index 7c0c6a3..2058a6b 100644 --- a/version.txt +++ b/version.txt @@ -1,2 +1,2 @@ version=0.4
-rev=13 +rev=14 |