Skip to content
This repository has been archived by the owner on Jun 24, 2024. It is now read-only.

Commit

Permalink
Merge branch 'release/3.6.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandreJunod committed Apr 22, 2024
2 parents 1081757 + 7674a57 commit 9560557
Show file tree
Hide file tree
Showing 42 changed files with 574 additions and 239 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
1 change: 1 addition & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -47,6 +48,7 @@ services:
WMTS_GETCAP_ALTERNATIVE:
WMTS_LAYER_ALTERNATIVE:
PRIVATE_DOCUMENTS_DIR:
PUBLIC_DOCUMENTS_DIR:
ALLOWED_HOSTS:
ALLOWED_CORS:
ENABLE_2FA:
Expand Down
10 changes: 9 additions & 1 deletion geocity/apps/accounts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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)
Expand Down Expand Up @@ -774,6 +781,7 @@ class AdministrativeEntityAdmin(IntegratorFilterMixin, admin.ModelAdmin):
{
"fields": (
"name",
"agenda_name",
"tags",
"ofs_id",
"is_single_form_submissions",
Expand Down
28 changes: 27 additions & 1 deletion geocity/apps/accounts/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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)
Original file line number Diff line number Diff line change
@@ -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",
),
),
]
12 changes: 9 additions & 3 deletions geocity/apps/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
(
Expand Down Expand Up @@ -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"])
],
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
{% block object-tools-items %}
{% if original.anonymous_user %}
<div class="form-group">
<a class="btn btn-dark form-control" href="{% url "admin:auth_user_change" object_id=original.anonymous_user.user_id %}">
{% translate "Voir l'utilisateur anonyme" %}
</a>
<span class="btn btn-dark form-control" href="{% url "admin:auth_user_change" object_id=original.anonymous_user.user_id %}">
{% translate "Utilisateur anonyme déjà existant" %}
</span>
</div>
{% else %}
<div class="form-group">
Expand Down
5 changes: 5 additions & 0 deletions geocity/apps/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,9 @@
views.administrative_entity_file_download,
name="administrative_entity_file_download",
),
path(
"custom-site-image/<path:path>",
views.site_profile_custom_image,
name="site_profile_custom_image",
),
]
90 changes: 35 additions & 55 deletions geocity/apps/accounts/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,67 +52,47 @@ def get_integrator_permissions():


def get_users_list_for_integrator_admin(user, remove_anonymous=False):
# Integrators can only view users for restricted email domains.
if user.is_superuser:
qs = User.objects.select_related("userprofile")

# Used to remove anonymous users from the list
anonymous_users = []
if remove_anonymous:
for user in qs:
if user.userprofile.is_anonymous:
anonymous_users.append(user.pk)
qs = qs.exclude(pk__in=anonymous_users)

return qs

user_integrator_group = user.groups.get(permit_department__is_integrator_admin=True)

email_domains = [
domain.strip()
for domain in user_integrator_group.permit_department.integrator_email_domains.split(
","
)
]
emails = [
email.strip()
for email in user_integrator_group.permit_department.integrator_emails_exceptions.split(
","
else:
user_integrator_group = user.groups.get(
permit_department__is_integrator_admin=True
)
]

qs = (
User.objects.annotate(
email_domain=Substr("email", StrIndex("email", Value("@")) + 1),
email_domains = [
domain.strip()
for domain in user_integrator_group.permit_department.integrator_email_domains.split(
","
)
]

emails = [
email.strip()
for email in user_integrator_group.permit_department.integrator_emails_exceptions.split(
","
)
]

qs = (
User.objects.annotate(
email_domain=Substr("email", StrIndex("email", Value("@")) + 1),
)
# hide users not belonging to the actual integrator
.filter(
Q(is_superuser=False),
Q(email_domain__in=email_domains) | Q(email__in=emails),
Q(groups__permit_department__integrator=user_integrator_group.pk)
| Q(groups__isnull=True)
| Q(groups__permit_department__is_integrator_admin=True),
).distinct()
)
# hide anynomous user not belonging to the actual integrator
.filter(
Q(is_superuser=False),
Q(email_domain__in=email_domains) | Q(email__in=emails),
Q(groups__permit_department__integrator=user_integrator_group.pk)
| Q(groups__isnull=True)
| Q(groups__permit_department__is_integrator_admin=True),
)
.exclude()
.distinct()
)
integrator_administrative_entities_list = (
models.AdministrativeEntity.objects.associated_to_user(user).values_list(
"pk", flat=True
)
)

# Used to remove anonymous users from the list
# Remove anonymous users if flag at true or user is not a superuser
anonymous_users = []
for user in qs:
if remove_anonymous and user.userprofile.is_anonymous:
anonymous_users.append(user.pk)
elif (
user.userprofile.is_anonymous
and user.userprofile.administrative_entity.pk
not in integrator_administrative_entities_list
):
anonymous_users.append(user.pk)
qs = qs.exclude(pk__in=anonymous_users)
if remove_anonymous or not user.is_superuser:
for qs_user in qs:
if qs_user.userprofile.is_anonymous:
anonymous_users.append(qs_user.pk)
qs = qs.exclude(pk__in=anonymous_users)

return qs
16 changes: 15 additions & 1 deletion geocity/apps/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
check_mandatory_2FA,
permanent_user_required,
)
from geocity.fields import PrivateFileSystemStorage
from geocity.fields import PrivateFileSystemStorage, PublicFileSystemStorage

from . import forms, models
from .users import is_2FA_mandatory
Expand Down Expand Up @@ -403,3 +403,17 @@ def administrative_entity_file_download(request, path):
return StreamingHttpResponse(storage.open(path), content_type=mime_type)
except IOError:
raise Http404


def site_profile_custom_image(request, path):
"""
Serve public image for template customization
"""

mime_type, encoding = mimetypes.guess_type(path)
storage = PublicFileSystemStorage()

try:
return StreamingHttpResponse(storage.open(path), content_type=mime_type)
except IOError:
raise Http404
5 changes: 3 additions & 2 deletions geocity/apps/api/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ class AgendaResultsSetPagination(PageNumberPagination):
max_page_size = 100

def get_paginated_response(self, data):
domain = self.request.GET.get("domain")
agenda_filters = get_available_filters_for_agenda_as_json(domain)
domains = self.request.GET.get("domain")
domains = domains.split(",") if domains else None
agenda_filters = get_available_filters_for_agenda_as_json(domains)
return Response(
{
"type": "FeatureCollection",
Expand Down
Loading

0 comments on commit 9560557

Please sign in to comment.