diff --git a/.env.example b/.env.example index fa3f8230f..3c093d69e 100644 --- a/.env.example +++ b/.env.example @@ -41,8 +41,10 @@ WMTS_GETCAP=https://wmts.asit-asso.ch/wmts?request=GetCapabilities WMTS_LAYER=asitvd.fond_cadastral WMTS_GETCAP_ALTERNATIVE=https://wmts.geo.admin.ch/EPSG/2056/1.0.0/WMTSCapabilities.xml WMTS_LAYER_ALTERNATIVE=ch.swisstopo.swissimage -PRIVATE_DOCUMENTS_DIR=/var/sig/private_geocity/geocity_demo # PRIVATE_DOCUMENTS_DIR=private_documents used to access to the private documents via a volume (check docker-compose-dev.yml) search(ctrl+f) -> #access_to_private_document_local +PRIVATE_DOCUMENTS_DIR=/var/sig/private_geocity/geocity_demo +# PUBLIC_DOCUMENTS_DIR=public_documents used to access to the public documents via a volume (check docker-compose-dev.yml) +PUBLIC_DOCUMENTS_DIR=/var/sig/public_geocity/geocity_demo ALLOWED_HOSTS=localhost,127.0.0.1,web,yverdon.localhost,vevey.localhost,lausanne.localhost,grandson.localhost,base.localhost ALLOWED_CORS=http://localhost:3000,http://127.0.0.1 # This setting will enable the factor authentification diff --git a/README.md b/README.md index 8626cbcc7..b7aa28882 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ Following variable setup in your .env file will setup the development environmen ```ini PRIVATE_DOCUMENTS_DIR=C:\some\directory\for\mounting\geocity\private_documents +PUBLIC_DOCUMENTS_DIR=C:\some\directory\for\mounting\geocity\public_documents ARCHIVE_DIR=C:\some\directory\for\mounting\geocity\archive DEFAULT_SITE=localhost ``` diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index ee5b74ea1..c847f8558 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -20,6 +20,7 @@ services: - .:/code # For dev, set the temp folder in the main code directory, for convenience - ./_dev_volumes/private_documents:/private_documents + - ./_dev_volumes/public_documents:/public_documents - ./_dev_volumes/archive:/archive depends_on: postgres: diff --git a/docker-compose.yml b/docker-compose.yml index 3389ee89e..7c0cc4ddd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: command: "gunicorn geocity.wsgi -b :9000 --error-logfile gunicorn_log.log --workers=2 --threads=4 --worker-class=gthread" volumes: - ${PRIVATE_DOCUMENTS_DIR}:/private_documents + - ${PUBLIC_DOCUMENTS_DIR}:/public_documents - ${ARCHIVE_DIR}:/archive - static_root:/external_statics # to allow to spawn new QGIS containers @@ -47,6 +48,7 @@ services: WMTS_GETCAP_ALTERNATIVE: WMTS_LAYER_ALTERNATIVE: PRIVATE_DOCUMENTS_DIR: + PUBLIC_DOCUMENTS_DIR: ALLOWED_HOSTS: ALLOWED_CORS: ENABLE_2FA: diff --git a/geocity/apps/accounts/admin.py b/geocity/apps/accounts/admin.py index 1eb9eabb6..e466f849b 100644 --- a/geocity/apps/accounts/admin.py +++ b/geocity/apps/accounts/admin.py @@ -502,7 +502,8 @@ def clean_permissions(self): class UserInline(admin.TabularInline): model = Group.user_set.through - can_delete = True + readonly_fields = ("user",) + can_delete = False extra = 0 verbose_name = _("Utilisateur membre du groupe") verbose_name_plural = _("Utilisateurs membres du groupe") @@ -515,6 +516,12 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs): return super().formfield_for_foreignkey(db_field, request, **kwargs) + def has_add_permission(self, request, obj=None): + return False + + def has_delete_permission(self, request, obj=None): + return False + class GroupAdmin(BaseGroupAdmin): inlines = (PermitDepartmentInline, UserInline) @@ -774,6 +781,7 @@ class AdministrativeEntityAdmin(IntegratorFilterMixin, admin.ModelAdmin): { "fields": ( "name", + "agenda_name", "tags", "ofs_id", "is_single_form_submissions", diff --git a/geocity/apps/accounts/fields.py b/geocity/apps/accounts/fields.py index e72d2f4ce..ef2935bb6 100644 --- a/geocity/apps/accounts/fields.py +++ b/geocity/apps/accounts/fields.py @@ -2,7 +2,7 @@ from django.db.models.fields.files import FieldFile from django.urls import reverse -from geocity.fields import PrivateFileSystemStorage +from geocity.fields import PrivateFileSystemStorage, PublicFileSystemStorage class AdministrativeEntityFieldFile(FieldFile): @@ -24,3 +24,29 @@ class AdministrativeEntityFileField(models.FileField): def __init__(self, verbose_name=None, name=None, **kwargs): kwargs["storage"] = PrivateFileSystemStorage() super().__init__(verbose_name, name, **kwargs) + + +class CustomLoginImageFieldFile(FieldFile): + """ + FieldFile for storing public image for site customization + """ + + @property + def url(self): + + return reverse( + "accounts:site_profile_custom_image", + kwargs={"path": self.name}, + ) + + +class CustomLoginImageFileField(models.FileField): + """ + FileField storing public image for site customization + """ + + attr_class = CustomLoginImageFieldFile + + def __init__(self, verbose_name=None, name=None, **kwargs): + kwargs["storage"] = PublicFileSystemStorage() + super().__init__(verbose_name, name, **kwargs) diff --git a/geocity/apps/accounts/migrations/0018_administrativeentity_agenda_name_and_more.py b/geocity/apps/accounts/migrations/0018_administrativeentity_agenda_name_and_more.py new file mode 100644 index 000000000..4083e2f81 --- /dev/null +++ b/geocity/apps/accounts/migrations/0018_administrativeentity_agenda_name_and_more.py @@ -0,0 +1,42 @@ +# Generated by Django 4.2.10 on 2024-04-18 06:19 + +import django.core.validators +from django.db import migrations, models + +import geocity.apps.accounts.fields +import geocity.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0017_service_fee"), + ] + + operations = [ + migrations.AddField( + model_name="administrativeentity", + name="agenda_name", + field=models.CharField( + blank=True, + help_text="Nom visible dans le filtre de l'agenda", + max_length=128, + verbose_name="Nom dans l'api agenda", + ), + ), + migrations.AlterField( + model_name="templatecustomization", + name="background_image", + field=geocity.apps.accounts.fields.CustomLoginImageFileField( + blank=True, + storage=geocity.fields.PublicFileSystemStorage(), + upload_to="site_profile_custom_image/", + validators=[ + django.core.validators.FileExtensionValidator( + allowed_extensions=["svg", "png", "jpg", "jpeg"] + ) + ], + verbose_name="Image de fond", + ), + ), + ] diff --git a/geocity/apps/accounts/models.py b/geocity/apps/accounts/models.py index 1296960f5..0f18c7370 100644 --- a/geocity/apps/accounts/models.py +++ b/geocity/apps/accounts/models.py @@ -18,7 +18,7 @@ from simple_history.models import HistoricalRecords from taggit.managers import TaggableManager -from .fields import AdministrativeEntityFileField +from .fields import AdministrativeEntityFileField, CustomLoginImageFileField AGENDA_PUBLIC_TYPE_CHOICES = ( ( @@ -116,10 +116,10 @@ class TemplateCustomization(models.Model): application_description = models.TextField( _("Description"), max_length=2048, blank=True ) - background_image = models.ImageField( + background_image = CustomLoginImageFileField( _("Image de fond"), blank=True, - upload_to="background_images/", + upload_to="site_profile_custom_image/", validators=[ FileExtensionValidator(allowed_extensions=["svg", "png", "jpg", "jpeg"]) ], @@ -257,6 +257,12 @@ def associated_to_user(self, user): class AdministrativeEntity(models.Model): name = models.CharField(_("name"), max_length=128) + agenda_name = models.CharField( + _("Nom dans l'api agenda"), + help_text=_("Nom visible dans le filtre de l'agenda"), + max_length=128, + blank=True, + ) ofs_id = models.PositiveIntegerField(_("Numéro OFS")) link = models.URLField(_("Lien"), max_length=200, blank=True) archive_link = models.URLField(_("Archives externes"), max_length=1024, blank=True) diff --git a/geocity/apps/accounts/templates/accounts/admin/administrative_entity_change.html b/geocity/apps/accounts/templates/accounts/admin/administrative_entity_change.html index 167fabcdf..19a55fc3b 100644 --- a/geocity/apps/accounts/templates/accounts/admin/administrative_entity_change.html +++ b/geocity/apps/accounts/templates/accounts/admin/administrative_entity_change.html @@ -4,9 +4,9 @@ {% block object-tools-items %} {% if original.anonymous_user %}