Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended permissions: geographic & taxonomic filters, validation, … #3217

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 113 additions & 29 deletions backend/geonature/core/gn_permissions/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from flask import url_for, has_app_context, request
from flask_admin.contrib.sqla import ModelView
from flask_admin.contrib.sqla.filters import FilterEqual
from ref_geo.models import BibAreasTypes, LAreas
from apptax.taxonomie.models import Taxref
import sqlalchemy as sa
from flask_admin.contrib.sqla.tools import get_primary_key
from flask_admin.contrib.sqla.fields import QuerySelectField
Expand Down Expand Up @@ -132,10 +134,11 @@
o += "<thead><tr>" + "".join([f"<th>{col}</th>" for col in columns]) + "</tr></thead>"
o += "<tbody>"
for ap in available_permissions:
permissions = [p for p in model.permissions if p.is_active]

Check warning on line 137 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L137

Added line #L137 was not covered by tests
own_permissions = list(
filter(
lambda p: p.module == ap.module and p.object == ap.object and p.action == ap.action,
model.permissions,
permissions,
)
)
permissions = [(own_permissions, True)]
Expand Down Expand Up @@ -188,7 +191,7 @@
o += """<ul class="list-group">"""
for flt_name in perm.availability.filters:
flt_field = Permission.filters_fields[flt_name]
flt = PermFilter(flt_name, getattr(perm, flt_field.name))
flt = PermFilter(flt_name, getattr(perm, flt_field))

Check warning on line 194 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L194

Added line #L194 was not covered by tests
o += f"""<li class="list-group-item">{flt}</li>"""
o += "</ul>"
o += """</div></div>"""
Expand Down Expand Up @@ -243,7 +246,8 @@

def permissions_count_formatter(view, context, model, name):
url = url_for("permissions/permission.index_view", flt1_rle_equals=model.id_role)
return Markup(f'<a href="{url}">{len(model.permissions)}</a>')
permissions_count = len([p for p in model.permissions if p.is_active])
return Markup(f'<a href="{url}">{permissions_count}</a>')

Check warning on line 250 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L249-L250

Added lines #L249 - L250 were not covered by tests


### Widgets
Expand Down Expand Up @@ -288,6 +292,15 @@

class UserAjaxModelLoader(QueryAjaxModelLoader):
def format(self, user):
"""
Instead of returning a list of tuple (id, label), we return a list of tuple (id, label, excluded_availabilities).
The third element of each tuple is the list of type of permissions the user already have, so it is useless
to add this permission to the user, and they will be not available in the front select.
Two remarks:
- We only consider active permissions of the user
- If the type of the permission allows two or more filters, we do not exclude it as it makes sens to add several
permissions of the same type with differents set of filters.
"""
if not user:
return None

Expand All @@ -299,13 +312,15 @@
def filter_availability(availability):
filters_count = sum(
[
getattr(availability, field.name)
getattr(availability, field)
for field in PermissionAvailable.filters_fields.values()
]
)
return filters_count < 2

availabilities = {p.availability for p in user.permissions if p.availability}
availabilities = {

Check warning on line 321 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L321

Added line #L321 was not covered by tests
p.availability for p in user.permissions if p.availability and p.is_active
}
excluded_availabilities = filter(filter_availability, availabilities)
excluded_availabilities = map(format_availability, excluded_availabilities)
return super().format(user) + (list(excluded_availabilities),)
Expand All @@ -319,6 +334,35 @@
)


class AreaAjaxModelLoader(QueryAjaxModelLoader):
def format(self, area):
return (area.id_area, f"{area.area_name} ({area.area_type.type_name})")

Check warning on line 339 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L339

Added line #L339 was not covered by tests

def get_one(self, pk):
# prevent autoflush from occuring during populate_obj
with self.session.no_autoflush:
return self.session.get(self.model, pk)

Check warning on line 344 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L343-L344

Added lines #L343 - L344 were not covered by tests

def get_query(self):
return (

Check warning on line 347 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L347

Added line #L347 was not covered by tests
super()
.get_query()
.join(LAreas.area_type)
.where(
BibAreasTypes.type_code.in_(config["PERMISSIONS"]["GEOGRAPHIC_FILTER_AREA_TYPES"])
)
.order_by(BibAreasTypes.id_type, LAreas.area_name)
)


class TaxrefAjaxModelLoader(QueryAjaxModelLoader):
def format(self, taxref):
label = f"[{taxref.cd_nom}] {taxref.nom_valide}"
if taxref.nom_vern:
label += f" ({taxref.nom_vern})"
return (taxref.cd_nom, label)

Check warning on line 363 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L360-L363

Added lines #L360 - L363 were not covered by tests


### ModelViews


Expand Down Expand Up @@ -355,11 +399,14 @@
"role.identifiant": "identifiant du rôle",
"role.nom_complet": "nom du rôle",
"availability": "Permission",
"expire_on": "Date d’expiration",
"scope": "Filtre sur l'appartenance des données",
"sensitivity_filter": (
"Flouter" if config["SYNTHESE"]["BLUR_SENSITIVE_OBSERVATIONS"] else "Exclure"
)
+ " les données sensibles",
"areas_filter": "Filtre géographique",
"taxons_filter": "Filtre taxonomique",
}
column_select_related_list = ("availability",)
column_searchable_list = ("role.identifiant", "role.nom_complet")
Expand Down Expand Up @@ -390,23 +437,35 @@
("object.code_object", False),
("id_action", False),
]
form_columns = ("role", "availability", "scope", "sensitivity_filter")
form_columns = (
"role",
"availability",
"scope",
"sensitivity_filter",
"areas_filter",
"taxons_filter",
)
form_overrides = dict(
availability=OptionQuerySelectField,
)
form_args = dict(
availability=dict(
query_factory=lambda: PermissionAvailable.nice_order(),
options_additional_values=["sensitivity_filter", "scope_filter"],
options_additional_values=[
"sensitivity_filter",
"scope_filter",
"areas_filter",
"taxons_filter",
],
),
)
create_template = "admin/hide_select2_options_create.html"
edit_template = "admin/hide_select2_options_edit.html"
form_ajax_refs = {
"role": UserAjaxModelLoader(
"role",
db.session,
User,
name="role",
session=db.session,
model=User,
fields=(
"identifiant",
"nom_role",
Expand All @@ -415,8 +474,37 @@
placeholder="Veuillez sélectionner un utilisateur ou un groupe",
minimum_input_length=0,
),
"areas_filter": AreaAjaxModelLoader(
name="areas_filter",
session=db.session,
model=LAreas,
fields=(LAreas.area_name, LAreas.area_code),
page_size=25,
placeholder="Sélectionnez une ou plusieurs zones géographiques",
minimum_input_length=1,
),
"taxons_filter": TaxrefAjaxModelLoader(
name="taxons_filter",
session=db.session,
model=Taxref,
fields=(
Taxref.cd_nom,
Taxref.nom_vern,
Taxref.nom_valide,
Taxref.nom_complet,
),
page_size=25,
placeholder="Sélectionnez un ou plusieurs taxons",
minimum_input_length=1,
),
}

def get_query(self):
return super().get_query().where(Permission.active_filter())

Check warning on line 503 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L503

Added line #L503 was not covered by tests

def get_count_query(self):
return super().get_count_query().where(Permission.active_filter())

Check warning on line 506 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L506

Added line #L506 was not covered by tests

def render(self, template, **kwargs):
self.extra_js = [url_for("static", filename="js/hide_unnecessary_filters.js")]
return super().render(template, **kwargs)
Expand Down Expand Up @@ -455,6 +543,8 @@
"object": "Objet",
"scope_filter": "Filtre appartenance",
"sensitivity_filter": "Filtre sensibilité",
"areas_filter": "Filtre géographique",
"taxons_filter": "Filtre taxonomique",
}
column_formatters = {
"module": lambda v, c, m, p: m.module.module_code,
Expand All @@ -471,7 +561,7 @@
("object.code_object", False),
("id_action", False),
]
form_columns = ("scope_filter", "sensitivity_filter")
form_columns = ("scope_filter", "sensitivity_filter", "areas_filter", "taxons_filter")


class RolePermAdmin(CruvedProtectedMixin, ModelView):
Expand Down Expand Up @@ -504,6 +594,14 @@
"permissions_count": permissions_count_formatter,
}

def get_query(self):
# TODO : change to sqla2.0 query when flask admin update to sqla2
return db.session.query(User).where(User.filter_by_app())

Check warning on line 599 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L599

Added line #L599 was not covered by tests

def get_count_query(self):
# TODO : change to sqla2.0 query when flask admin update to sqla2
return db.session.query(sa.func.count("*")).select_from(User).where(User.filter_by_app())

Check warning on line 603 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L603

Added line #L603 was not covered by tests


class GroupPermAdmin(RolePermAdmin):
column_list = (
Expand All @@ -513,17 +611,10 @@
column_details_list = ("nom_role", "permissions_count", "permissions")

def get_query(self):
# TODO : change to sqla2.0 query when flask admin update to sqla2
return db.session.query(User).filter_by(groupe=True).where(User.filter_by_app())
return super().get_query().where(User.groupe.is_(sa.true()))

Check warning on line 614 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L614

Added line #L614 was not covered by tests

def get_count_query(self):
# TODO : change to sqla2.0 query when flask admin update to sqla2
return (
db.session.query(sa.func.count("*"))
.select_from(User)
.where(User.groupe == True)
.where(User.filter_by_app())
)
return super().get_count_query().where(User.groupe.is_(sa.true()))

Check warning on line 617 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L617

Added line #L617 was not covered by tests


class UserPermAdmin(RolePermAdmin):
Expand All @@ -548,17 +639,10 @@
)

def get_query(self):
# TODO : change to sqla2.0 query when flask admin update to sqla2
return db.session.query(User).filter_by(groupe=False).where(User.filter_by_app())
return super().get_query().where(User.groupe.is_(sa.false()))

Check warning on line 642 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L642

Added line #L642 was not covered by tests

def get_count_query(self):
# TODO : change to sqla2.0 query when flask admin update to sqla2
return (
db.session.query(sa.func.count("*"))
.select_from(User)
.where(User.groupe == False)
.where(User.filter_by_app())
)
return super().get_count_query().where(User.groupe.is_(sa.false()))

Check warning on line 645 in backend/geonature/core/gn_permissions/admin.py

View check run for this annotation

Codecov / codecov/patch

backend/geonature/core/gn_permissions/admin.py#L645

Added line #L645 was not covered by tests


admin.add_view(
Expand Down
Loading
Loading