PnX-SI / GeoNature

Application de saisie et de synthèse des observations faune et flore
GNU General Public License v3.0
97 stars 99 forks source link

Permissions : filtre géographique #3098

Open bouttier opened 2 weeks ago

bouttier commented 2 weeks ago

Il est souhaité de rajouter aux permissions un filtre géographique permettant de restreindre une permission à zone géographique donnée (https://github.com/PnX-SI/GeoNature/issues/3097).

Le filtrage géographique des observations repose sur la géométrie précise et n’a pas besoin de tenir compte du floutage, contrairement à la recherche géographique de la synthèse. On considère que l’accès à une observation est acquis dès lors que sa géométrie intersecte la zone géographique autorisées (l’observation n’a pas besoin d’être totalement inclus dans le périmètre géographique autorisé), ce qui est le comportement du trigger de peuplement de la table cor_area_synthese qui pourra donc être utilisé pour le filtrage.

L’utilisation de cor_area_synthese suppose donc que les filtres géographiques portent uniquement sur des zones du référentiels. Cette hypothèse a pour gros avantage de ne pas nécessiter d’intersection dynamique.

Il peut être nécessaire de donner accès aux données sur plusieurs zones, par exemple plusieurs communes. Les permissions étant cumulatives, il est possible de créer plusieurs permissions chacune portant sur une unique zone. Cependant, la gestion des permissions apparaît alors compliquée. On souhaite plutôt pouvoir préciser plusieurs zones directement sur une seule permission.

Pour cela, il faut :

        elif self.name == "AREA":
            if self.value:
                areas_names = ','.join([a.area_name for a in self.value])
                return f"""<i class="fa fa-map-marker" aria-hidden="true"></i>  {areas_names}"""
            else:
                return """<i class="fa fa-globe" aria-hidden="true"></i>  partout"""

Vient ensuite l’implémentation dans la synthèse ! Pour le moment, le filtre n’est pas connue par la synthèse, ainsi toute permission contenant un filtre géographique sera ignoré.

Pour en prendre compte dans la synthèse, il faut implémenter le filtre géographique deux fois :

Pour la vérification unitaire, à implémenter dans Synthese._has_permission_grant :

Pour le filtrage d’une liste d’observation, à implémenter dans SyntheseQuery.build_permissions_filter :

Lorsqu’un utilisateur possède une permission via un groupe sur un territoire donnée, mais possède également une permission personnelle sans restriction géographique, il est intéressant de simplifier le jeu de permissions de l’utilisateur pour ne garder que la permission la plus permissive. La comparaison des permissions est faite par la méthode Permission.__le__, qui compare chaque filtre. La comparaison par défaut (__default_le__) ne fonctionne pas vraiment pour les filtres géographiques (liste de zone), on rajoutera donc une comparaison spécifique :

    class Permission:
        @staticmethod
        def __AREA_le__(a, b):
            return set(a) == set(b) or not b

Cette implémentation est naïve, elle permet uniquement d’identifier les permissions dont la liste des zones géographique est identique, ou les permissions sans restriction géographique.

Il serait intéressant d’identifier les inclusions de territoire, c’est-à-dire quelque chose comme ST_Contains(ST_Union(a), ST_Union(b)). Cependant, cela alourdirait probablement beaucoup les performances puisque la simplification des permissions a lieu à chaque récupération des permissions, c’est-à-dire à chaque requête.

On pourrait toutefois pré-calculer certaines inclusions dans une table dédiée, notamment les communes dans les départements, les départements dans les régions, etc. Cela permettrait déjà d’effectuer de manière efficace quelques simplifications de permissions. Dans tous les cas, il parait judicieux d’étudier des jeux de permissions réels afin de déterminer s’il a lieu de chercher à les simplifier.