diff options
| -rw-r--r-- | ishtar_common/admin.py | 110 | ||||
| -rw-r--r-- | ishtar_common/models.py | 14 | ||||
| -rw-r--r-- | ishtar_common/models_common.py | 21 | 
3 files changed, 126 insertions, 19 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index ce66e535c..f67a99e01 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -42,7 +42,7 @@ from django.contrib.auth.models import Group, User  from django.contrib.contenttypes.models import ContentType  from django.contrib.sites.admin import SiteAdmin  from django.contrib.sites.models import Site -from django.contrib.gis.forms import PointField, OSMWidget, MultiPolygonField +from django.contrib.gis.forms import PointField, OSMWidget  from django.contrib.gis.geos import GEOSGeometry, MultiPolygon  from django.contrib.gis.gdal.error import GDALException  from django.contrib.gis.geos.error import GEOSException @@ -58,7 +58,7 @@ from django.db.models.fields import (  )  from django.db.models.fields.related import ForeignKey  from django.forms import BaseInlineFormSet -from django.http import HttpResponseRedirect, HttpResponse +from django.http import HttpResponseRedirect, HttpResponse, Http404  from django.shortcuts import render  from django.urls import reverse  from django.utils.decorators import method_decorator @@ -470,8 +470,8 @@ class ImportedObjectAdmin(admin.ModelAdmin):              return fields + ("imports", "imports_updated")          return fields -    END_FIELDS = ["data", "last_modified", "created", "need_update", "locked", "lock_user", -                  "main_geodata", "geodata", "qrcode"] +    END_FIELDS = ["data", "last_modified", "created", "need_update", "locked", +                  "lock_user", "main_geodata", "geodata", "qrcode"]      def get_fields(self, request, obj=None, **kwargs):          """ @@ -520,7 +520,19 @@ class MyGroupAdmin(GroupAdmin):          css = {"all": ("media/admin.css",)} -admin_site.register(User, UserAdmin) +class IshtarUserAdmin(UserAdmin): +    fieldsets = ( +        (None, {'fields': ('username', 'password')}), +        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}), +        (_('Permissions'), { +            'fields': ('is_active', 'is_staff', 'is_superuser') +        }), +        (_('Important dates'), {'fields': ('last_login', 'date_joined')}), +    ) +    pass + + +admin_site.register(User, IshtarUserAdmin)  admin_site.register(Group, MyGroupAdmin)  admin_site.register(Site, SiteAdmin) @@ -770,6 +782,46 @@ class PersonAdmin(HistorizedObjectAdmin):  admin_site.register(models.Person, PersonAdmin) +class PermissionRequestAdminForm(forms.ModelForm): +    class Meta: +        model = models_common.PermissionRequest +        exclude = [] + +    def __init__(self, *args, **kwargs): +        super().__init__(*args, **kwargs) +        choices = [] +        for ct in ContentType.objects.all(): +            klass = ct.model_class() +            if not klass: +                continue +            if getattr(klass, "SHOW_URL", None) and hasattr(klass, "history_creator_id"): +                choices.append((ct.pk, ct.name)) +        self.fields["model"].choices = [("", "-" * 9)] + list( +                sorted(choices, key=lambda x: x[1]) +        ) + +    def clean(self): +        limit_to_attached_areas = self.cleaned_data.get("limit_to_attached_areas", "") +        if not limit_to_attached_areas: +            return self.cleaned_data +        model = self.cleaned_data["model"] +        if model.model not in ("operation", "contextrecord", "find", +                               "archaeologicalsite", "file"): +            raise forms.ValidationError(_("This model do not accept area limitation.")) +        return self.cleaned_data + + +@admin.register(models_common.PermissionRequest, site=admin_site) +class PermissionRequestAdmin(admin.ModelAdmin): +    prepopulated_fields = {"slug": ("name",)} +    search_fields = ("model__model__unaccent", "name") +    list_display = ( +        "model", "name", "active", "include_associated_items", +        "include_upstream_items", "limit_to_attached_areas" +    ) +    form = PermissionRequestAdminForm + +  MAIN_ITEM_READONLY_FIELDS = [      "history_creator",      "history_modifier", @@ -1593,6 +1645,54 @@ admin_site.register(models.Area, AreaAdmin)  class ProfileTypeAdmin(GeneralTypeAdmin):      model = models.ProfileType      filter_vertical = ("groups",) +    autocomplete_fields = ("permission_requests",) + +    def check_permission(self, request, object_id): +        # check that all "own" permission has a request associated +        try: +            obj = models.ProfileType.objects.get(pk=int(object_id)) +        except models.ProfileType.DoesNotExist: +            return Http404() +        permissions_needed = set() +        permissions_not_needed = set() +        for group in obj.groups.all(): +            for perm in group.permissions.all(): +                sp = perm.codename.split("_") +                perm_type = (sp[0], sp[-1]) +                if sp[1] == "own": +                    permissions_needed.add(perm_type) +                else: +                    permissions_not_needed.add(perm_type) +        for permission_request in obj.permission_requests.all(): +            model = permission_request.model.model +            for perm_type, perm_model in list(permissions_needed): +                if model == perm_model: +                    permissions_needed.remove((perm_type, perm_model)) +        for permission in list(permissions_needed): +            if permission in permissions_not_needed: +                permissions_needed.remove(permission) +        if permissions_needed: +            permission_needed = ", ".join( +                sorted(set([model for __, model in permissions_needed])) +            ) +            messages.add_message( +                request, +                messages.ERROR, +                mark_safe(str(_( +                    """Permission requests are needed for theses models: +<strong>{permission_needed}.</strong><br> +Associate the profile type \"<strong>{obj}</strong>\" with correct permission request +otherwise default request will be used (Ishtar v4.4) or no permission will be +granted (Ishtar >= v5).""")).format(permission_needed=permission_needed, obj=obj)) +            ) + +    def change_view(self, request, object_id, form_url="", extra_context=None): +        returned = super().change_view( +            request, object_id, form_url=form_url, extra_context=extra_context +        ) +        if not request.POST or not request.POST.get("_continue", False): +            self.check_permission(request, object_id) +        return returned  admin_site.register(models.ProfileType, ProfileTypeAdmin) diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 148843fd4..8fcb9edbb 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -3429,7 +3429,9 @@ class GDPRLog(models.Model):              values = values[start:end]          for pk in values:              if pk: -                gdpr_persons.append(cls.persons.through(gdprperson_id=pk, gdprlog_id=log.pk)) +                gdpr_persons.append( +                    cls.persons.through(gdprperson_id=pk, gdprlog_id=log.pk) +                )          if gdpr_persons:              cls.persons.through.objects.bulk_create(gdpr_persons) @@ -3437,7 +3439,7 @@ class GDPRLog(models.Model):  class ProfileType(GeneralType):      groups = models.ManyToManyField(Group, verbose_name=_("Groups"), blank=True)      permission_requests = models.ManyToManyField( -        PermissionRequest, verbose_name=_("Permission request"), blank=True, +        PermissionRequest, verbose_name=_("Permissions requests"), blank=True,          related_name="profile_types"      ) @@ -3445,7 +3447,7 @@ class ProfileType(GeneralType):          verbose_name = _("Profile type")          verbose_name_plural = _("Profile types")          ordering = ("label",) -    ADMIN_SECTION = _("Directory") +    ADMIN_SECTION = _("Account")  post_save.connect(post_save_cache, sender=ProfileType) @@ -3457,7 +3459,7 @@ class ProfileTypeSummary(ProfileType):          proxy = True          verbose_name = _("Profile type summary")          verbose_name_plural = _("Profile types summary") -    ADMIN_SECTION = _("Directory") +    ADMIN_SECTION = _("Account")  class UserProfile(models.Model): @@ -3494,7 +3496,7 @@ class UserProfile(models.Model):          verbose_name = _("User profile")          verbose_name_plural = _("User profiles")          unique_together = (("name", "profile_type", "person"),) -    ADMIN_SECTION = _("Directory") +    ADMIN_SECTION = _("Account")      def __str__(self):          lbl = self.name or str(self.profile_type) @@ -3699,7 +3701,7 @@ class IshtarUser(FullSearch):          verbose_name = _("Ishtar user")          verbose_name_plural = _("Ishtar users")          ordering = ("person",) -    ADMIN_SECTION = _("Directory") +    ADMIN_SECTION = _("Account")      def __str__(self):          return str(self.person) diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index cd6c266ef..e92d7d55d 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -2626,7 +2626,7 @@ class GeoVectorData(Imported, OwnPerms):          if not precision and rounded:              precision = 6 -        r = re.compile(r"(\d+)\.(\d{6})(\d*)") +        # AFAC: r = re.compile(r"(\d+)\.(\d{6})(\d*)")          new_collection = []          for feat in collection:              geom_type = feat["geometry"].get("type", None) @@ -3068,18 +3068,15 @@ class GeographicItem(models.Model):  class PermissionRequest(models.Model): -    name = models.CharField(_("Name"), max_length=200) -    slug = models.SlugField(_("Slug"), unique=True)      model = models.ForeignKey(ContentType, related_name="permissions",                                verbose_name=_("Model"), on_delete=models.CASCADE) +    name = models.CharField(_("Name"), max_length=200) +    slug = models.SlugField(_("Slug"), unique=True)      request = models.TextField(          _("Request"), blank=True, null=False, default="",          help_text=_("Use 'text' request used in Ishtar search input")      ) -    limit_to_attached_areas = models.BooleanField( -        _("Limit request to attached areas"), default=False, -        help_text=_("Request is limited to areas attached to the ishtar user") -    ) +    active = models.BooleanField(_("Active"), default=True)      include_associated_items = models.BooleanField(          _("Include associated items"), default=True,          help_text=_("All items associated items match the request") @@ -3091,12 +3088,20 @@ class PermissionRequest(models.Model):              "For instance, match is done for all finds associated with own "              "context records")      ) -    active = models.BooleanField(_("Active"), default=True) +    limit_to_attached_areas = models.BooleanField( +        _("Limit request to attached areas"), default=False, +        help_text=_("Request is limited to areas attached to the ishtar user") +    ) + +    ADMIN_SECTION = _("Account")      class Meta:          verbose_name = _("Permission request")          verbose_name_plural = _("Permissions requests") +    def __str__(self): +        return f"{self.model} - {self.name}" +  class SerializeItem:      SERIALIZE_EXCLUDE = ["search_vector"]  | 
