diff --git a/geocity/admin_jazzmin_settings.py b/geocity/admin_jazzmin_settings.py index f54bc9bb6..2ef7a55b1 100644 --- a/geocity/admin_jazzmin_settings.py +++ b/geocity/admin_jazzmin_settings.py @@ -89,7 +89,8 @@ "constance.Config": "fas fa-cogs", "django_cron.CronJobLog": "fas fa-tasks", "forms.AdministrativeEntityForAdminSite": "fas fa-landmark", - "forms.ContactTypeForAdminSite": "fas fa-address-card", + "forms.ContactFormForAdminSite": "fas fa-address-card", + "forms.ContactTypeForAdminSite": "fas fa-hard-hat", "forms.PaymentSettings": "fas fa-shopping-cart", "forms.Price": "fas fa-coins", "forms.Field": "fas fa-list-ol", diff --git a/geocity/apps/accounts/admin.py b/geocity/apps/accounts/admin.py index 02ba9c403..f366d8388 100644 --- a/geocity/apps/accounts/admin.py +++ b/geocity/apps/accounts/admin.py @@ -317,6 +317,7 @@ class DepartmentAdminForm(forms.ModelForm): class Meta: model = models.PermitDepartment fields = [ + "shortname", "description", "administrative_entity", "is_validator", diff --git a/geocity/apps/accounts/migrations/0014_alter_administrativeentity_is_single_form_submissions_and_permitdepartment_shortname.py b/geocity/apps/accounts/migrations/0014_alter_administrativeentity_is_single_form_submissions_and_permitdepartment_shortname.py new file mode 100644 index 000000000..44952bf7f --- /dev/null +++ b/geocity/apps/accounts/migrations/0014_alter_administrativeentity_is_single_form_submissions_and_permitdepartment_shortname.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.4 on 2023-08-28 08:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0013_permitdepartment_generic_email_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="administrativeentity", + name="is_single_form_submissions", + field=models.BooleanField( + default=True, + help_text="Nécessaire pour l'utilisation du système de paiement en ligne", + verbose_name="Autoriser uniquement un objet par demande", + ), + ), + migrations.AlterField( + model_name="permitdepartment", + name="shortname", + field=models.CharField( + blank=True, + help_text="Nom affiché par défaut dans les différentes étapes du formulaire, ne s'affiche pas dans l'admin (max. 100 caractères)", + max_length=100, + verbose_name="nom court", + ), + ), + ] diff --git a/geocity/apps/accounts/models.py b/geocity/apps/accounts/models.py index 8d9221a1e..0ce0deac4 100644 --- a/geocity/apps/accounts/models.py +++ b/geocity/apps/accounts/models.py @@ -119,9 +119,9 @@ class PermitDepartment(models.Model): description = models.CharField(_("description"), max_length=100, default="Service") shortname = models.CharField( _("nom court"), - max_length=32, + max_length=100, help_text=_( - "Nom affiché par défaut dans les différentes étapes du formulaire, ne s'affiche pas dans l'admin (max. 32 caractères)" + "Nom affiché par défaut dans les différentes étapes du formulaire, ne s'affiche pas dans l'admin (max. 100 caractères)" ), blank=True, ) @@ -202,7 +202,7 @@ class Meta: ) def __str__(self): - return str(self.group) + return self.shortname if self.shortname else self.group.name class AdministrativeEntityQuerySet(models.QuerySet): @@ -295,7 +295,7 @@ class AdministrativeEntity(models.Model): ) is_single_form_submissions = models.BooleanField( _("Autoriser uniquement un objet par demande"), - default=False, + default=True, help_text=_("Nécessaire pour l'utilisation du système de paiement en ligne"), ) diff --git a/geocity/apps/accounts/permissions_groups.py b/geocity/apps/accounts/permissions_groups.py index f37247824..f62c1c4cf 100644 --- a/geocity/apps/accounts/permissions_groups.py +++ b/geocity/apps/accounts/permissions_groups.py @@ -11,7 +11,7 @@ "form", "field", "formfield", - "contacttypeforadminsite", + "contactformforadminsite", "paymentsettings", "price", "formprice", diff --git a/geocity/apps/accounts/templates/accounts/user_profile_edit.html b/geocity/apps/accounts/templates/accounts/user_profile_edit.html index 60ea359d9..4dc233b67 100644 --- a/geocity/apps/accounts/templates/accounts/user_profile_edit.html +++ b/geocity/apps/accounts/templates/accounts/user_profile_edit.html @@ -31,7 +31,7 @@

{% translate "Mon compte" %}

-
+
{% bootstrap_button "Confirmer" button_type="submit" id="user_profile_edit" button_class="btn-primary mr-3" value="Enregistrer" name="disabled"%} diff --git a/geocity/apps/accounts/templates/two_factor/login.html b/geocity/apps/accounts/templates/two_factor/login.html index 59ad040df..113abf507 100644 --- a/geocity/apps/accounts/templates/two_factor/login.html +++ b/geocity/apps/accounts/templates/two_factor/login.html @@ -67,7 +67,7 @@

{% translate "Connexion" %}

{% include "registration/_social_login.html" %} {% elif wizard.steps.current == 'token' %} -

{% translate "Veuillez entrer votre jeton (code à usage unique, code SMS)" %}

+

{% translate "Veuillez entrer votre jeton (code à usage unique), qui se trouve dans votre application d'authentification (Authenticator, Duo, LastPass, etc.) ou transmis par SMS." %}

{% csrf_token %} {% include "two_factor/_wizard_forms.html" %} diff --git a/geocity/apps/api/serializers.py b/geocity/apps/api/serializers.py index 3f62e5ea7..6054ed4dc 100644 --- a/geocity/apps/api/serializers.py +++ b/geocity/apps/api/serializers.py @@ -1,6 +1,6 @@ import json from collections import OrderedDict -from datetime import timedelta +from datetime import timedelta, timezone from django.contrib.gis.geos import GEOSGeometry from django.db.models import Max, Min @@ -305,7 +305,7 @@ def to_representation(self, instance): class Meta: model = PostFinanceTransaction fields = ( - "merchant_reference", + "transaction_id", "amount", "currency", "creation_date", @@ -392,15 +392,23 @@ def to_representation(self, value): rep = {} for submission_contact in value.submission_contacts.select_related("contact"): contact_object = { - "contact_type_display": submission_contact.get_contact_type_display() + "contact_form_display": submission_contact.contact_form.name } for field in submission_contact.contact._meta.fields: contact_object[field.name] = getattr( submission_contact.contact, field.name ) - rep[ - convert_string_to_api_key(submission_contact.get_contact_type_display()) - ] = contact_object + if ( + not convert_string_to_api_key(submission_contact.contact_form.name) + in rep + ): + rep[ + convert_string_to_api_key(submission_contact.contact_form.name) + ] = list() + + rep[convert_string_to_api_key(submission_contact.contact_form.name)].append( + contact_object + ) return rep @@ -548,18 +556,21 @@ def to_representation(self, value): GEOSGeometry(aggregated_geotime_qs["singlegeom"]).json ) + local_tz = timezone(timedelta(hours=2)) geotime_aggregated = {} geotime_aggregated["start_date"] = ( - aggregated_geotime_qs["submission_geo_time_start_date"].strftime( - "%d.%m.%Y %H:%M" - ) + aggregated_geotime_qs["submission_geo_time_start_date"] + .replace(tzinfo=timezone.utc) + .astimezone(local_tz) + .strftime("%d.%m.%Y %H:%M") if aggregated_geotime_qs["submission_geo_time_start_date"] else "" ) geotime_aggregated["end_date"] = ( - aggregated_geotime_qs["submission_geo_time_end_date"].strftime( - "%d.%m.%Y %H:%M" - ) + aggregated_geotime_qs["submission_geo_time_end_date"] + .replace(tzinfo=timezone.utc) + .astimezone(local_tz) + .strftime("%d.%m.%Y %H:%M") if aggregated_geotime_qs["submission_geo_time_end_date"] else "" ) @@ -585,7 +596,7 @@ def to_representation(self, value): # Override of real ListSerializer from django-rest-framework-gis # If you want to add a new structure with dynamic values, just add it to OrderedDict and give him a new function like "super().prefix_to_representation(data)" # Then in SubmissionPrintSerializer write this class like the existant "to_representation" -class SubmissionPrintListSerialier(gis_serializers.ListSerializer): +class SubmissionPrintListSerializer(gis_serializers.ListSerializer): @property def data(self): return super(gis_serializers.ListSerializer, self).data @@ -629,7 +640,7 @@ class SubmissionPrintSerializer(gis_serializers.GeoFeatureModelSerializer): def get_creditor_type(self, obj): if obj.creditor_type is not None: - creditor = obj.get_creditor_type_display() + creditor = obj.creditor_type.name elif obj.author: creditor = ( _("Auteur de la demande, ") @@ -678,7 +689,7 @@ def many_init(cls, *args, **kwargs): ) meta = getattr(cls, "Meta", None) list_serializer_class = getattr( - meta, "list_serializer_class", SubmissionPrintListSerialier + meta, "list_serializer_class", SubmissionPrintListSerializer ) return list_serializer_class(*args, **list_kwargs) diff --git a/geocity/apps/core/static/js/admin/form_field.js b/geocity/apps/core/static/js/admin/form_field.js index bd397e58b..f51965129 100644 --- a/geocity/apps/core/static/js/admin/form_field.js +++ b/geocity/apps/core/static/js/admin/form_field.js @@ -26,6 +26,11 @@ document.addEventListener('DOMContentLoaded', function() { const requiredClass = 'required'; const inputType = document.getElementById('id_input_type').value; + const allowedFileElement = document.getElementById('id_allowed_file_types'); + const allowedFileRowElement = allowedFileElement.closest('.form-group'); + const allowedFileLabelElement = allowedFileRowElement.querySelector('label'); + const isAllowedFileVisible = inputType === 'file'; + const choicesElement = document.getElementById('id_choices'); const choicesRowElement = choicesElement.closest('.form-group'); const choicesLabelElement = choicesRowElement.querySelector('label'); @@ -63,6 +68,10 @@ document.addEventListener('DOMContentLoaded', function() { const isFileVisible = inputType === 'file_download'; + allowedFileElement.removeAttribute('required'); + allowedFileRowElement.classList.add(hiddenClass); + allowedFileLabelElement.classList.remove(requiredClass); + choicesElement.removeAttribute('required'); choicesRowElement.classList.add(hiddenClass); choicesLabelElement.classList.remove(requiredClass); @@ -97,6 +106,11 @@ document.addEventListener('DOMContentLoaded', function() { choicesRowElement.classList.remove(hiddenClass); choicesLabelElement.classList.add(requiredClass); } + else if (isAllowedFileVisible) { + allowedFileElement.setAttribute('required', ''); + allowedFileRowElement.classList.remove(hiddenClass); + allowedFileLabelElement.classList.add(requiredClass); + } else if (isRegexPatternVisible) { regexElement.setAttribute('required', ''); regexRowElement.classList.remove(hiddenClass); diff --git a/geocity/apps/core/static/js/submission_contacts.js b/geocity/apps/core/static/js/submission_contacts.js index 40b19be17..707de4020 100644 --- a/geocity/apps/core/static/js/submission_contacts.js +++ b/geocity/apps/core/static/js/submission_contacts.js @@ -14,16 +14,33 @@ let update_form_value = function(item, userprofile) { } } -// Create a label to replace "readonly hidden select" readonly +// Create a label to replace .form-control without .extra-form in classes inside of forms-container window.addEventListener('load', function () { - var selects = document.querySelectorAll("select[readonly][hidden]"); - for (select of selects) { + var forms_control = document.querySelectorAll("[id=forms-container] select[class=form-control]"); + for (form_control of forms_control) { let elem = document.createElement('label'); - let text = select.querySelector("option[selected]").text - let div = select.closest('.col-md-9'); + let text = form_control.querySelector("option[selected]").text + let div = form_control.closest('.col-md-9'); elem.innerHTML = text; elem.classList.add('col-form-label', 'bold'); div.appendChild(elem); } + + // Hide .extra-form and show first hidden .extra-form on click of .show-extra-form + var extra_forms = document.querySelectorAll("[id=forms-container] select.form-control.extra-form"); + for (extra_form of extra_forms) { + let form = extra_form.closest("[class=contact-form]") + form.setAttribute("hidden", true) + } + + // addEventListener for button .show-extra-form + var button = document.querySelector("button.show-extra-form"); + button.addEventListener("click", (event) => { + var hidden_extra_forms = document.querySelector(".contact-form[hidden]") + if (hidden_extra_forms == null){ + document.getElementById('contact-alert').style.display = "block" + } + hidden_extra_forms.removeAttribute("hidden") + }); }); diff --git a/geocity/apps/core/templates/base_generic.html b/geocity/apps/core/templates/base_generic.html index 82b542758..4b225a015 100644 --- a/geocity/apps/core/templates/base_generic.html +++ b/geocity/apps/core/templates/base_generic.html @@ -72,7 +72,7 @@ {% if config.ENABLE_GEOCALENDAR %} @@ -113,7 +113,7 @@