diff --git a/VERSION b/VERSION
index 7243b12cf4..68e69e405e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.14.2
+2.15.0
diff --git a/backend/dependencies/TaxHub b/backend/dependencies/TaxHub
index 7d3808839c..9a51db8068 160000
--- a/backend/dependencies/TaxHub
+++ b/backend/dependencies/TaxHub
@@ -1 +1 @@
-Subproject commit 7d3808839c4ff0ef27fa0a19fa785a2a63ac4358
+Subproject commit 9a51db8068d8327e05a6f3cd8ae6733575b2825d
diff --git a/backend/geonature/core/gn_synthese/routes.py b/backend/geonature/core/gn_synthese/routes.py
index f9880af195..c5717a1498 100644
--- a/backend/geonature/core/gn_synthese/routes.py
+++ b/backend/geonature/core/gn_synthese/routes.py
@@ -21,7 +21,7 @@
from pypnnomenclature.models import BibNomenclaturesTypes, TNomenclatures
from werkzeug.exceptions import Forbidden, NotFound, BadRequest, Conflict
from werkzeug.datastructures import MultiDict
-from sqlalchemy import distinct, func, desc, asc, select, case
+from sqlalchemy import distinct, func, desc, asc, select, case, or_
from sqlalchemy.orm import joinedload, lazyload, selectinload, contains_eager
from geojson import FeatureCollection, Feature
import sqlalchemy as sa
@@ -1529,7 +1529,18 @@ def list_all_reports(permissions):
# Filter by id_role for 'pin' type only or if my_reports is true
if type_name == "pin" or my_reports:
- query = query.where(TReport.id_role == g.current_user.id_role)
+ query = query.where(
+ or_(
+ TReport.id_role == g.current_user.id_role,
+ TReport.id_synthese.in_(
+ select(TReport.id_synthese).where(TReport.id_role == g.current_user.id_role)
+ ),
+ TReport.synthese.has(Synthese.id_digitiser == g.current_user.id_role),
+ TReport.synthese.has(
+ Synthese.cor_observers.any(User.id_role == g.current_user.id_role)
+ ),
+ )
+ )
# On vérifie les permissions en lecture sur la synthese
synthese_query = select(Synthese.id_synthese).select_from(Synthese)
diff --git a/backend/geonature/tests/fixtures.py b/backend/geonature/tests/fixtures.py
index faab8949ab..c1972a1b22 100644
--- a/backend/geonature/tests/fixtures.py
+++ b/backend/geonature/tests/fixtures.py
@@ -989,8 +989,9 @@ def reports_data(users, synthese_data):
data = []
# do not commit directly on current transaction, as we want to rollback all changes at the end of tests
- def create_report(id_synthese, id_role, content, id_type, deleted):
+ def create_report(id_synthese, id_report, id_role, content, id_type, deleted):
new_report = TReport(
+ id_report=id_report,
id_synthese=id_synthese,
id_role=id_role,
content=content,
@@ -1015,10 +1016,10 @@ def create_report(id_synthese, id_role, content, id_type, deleted):
)
with db.session.begin_nested():
reports = [
- (ids[0], users["admin_user"].id_role, "comment1", discussionId, False),
- (ids[1], users["admin_user"].id_role, "comment1", alertId, False),
- (ids[2], users["user"].id_role, "a_comment1", discussionId, True),
- (ids[3], users["user"].id_role, "b_comment1", discussionId, True),
+ (ids[0], 10001, users["admin_user"].id_role, "comment1", discussionId, False),
+ (ids[1], 10002, users["admin_user"].id_role, "comment1", alertId, False),
+ (ids[2], 10003, users["user"].id_role, "a_comment1", discussionId, True),
+ (ids[3], 10004, users["user"].id_role, "b_comment1", discussionId, True),
]
for id_synthese, *args in reports:
data.append(create_report(id_synthese, *args))
diff --git a/backend/geonature/tests/test_reports.py b/backend/geonature/tests/test_reports.py
index 408e8560e3..d577693357 100644
--- a/backend/geonature/tests/test_reports.py
+++ b/backend/geonature/tests/test_reports.py
@@ -219,19 +219,23 @@ def test_list_all_reports(
assert isinstance(response.json["items"], list)
assert len(response.json["items"]) >= 0
- ids = [s.id_synthese for s in synthese_data.values()]
# TEST WITH MY_REPORTS TRUE
set_logged_user(self.client, users["user"])
response = self.client.get(url_for(url, type="discussion", my_reports="true"))
assert response.status_code == 200
items = response.json["items"]
- # Check that all items belong to the current user
- id_role = users["user"].id_role
- nom_complet = users["user"].nom_complet
- assert all(
- item["id_role"] == id_role and item["user"]["nom_complet"] == nom_complet
- for item in items
- )
+ expected_ids = [
+ 10001, # User is observer
+ 10003, # User is report owner
+ 10004, # User is report owner
+ ]
+ # Missing cases:
+ # - User is digitiser
+ # - User has post a report in the same synthese
+ # They involve adding data to the `synthese_data` fixture, which could cause other tests to fail.
+ item_ids = [item["id_report"] for item in items]
+ item_ids.sort()
+ assert expected_ids == item_ids
# Test undefined type
response = self.client.get(url_for(url, type="UNKNOW-REPORT-TYPE", my_reports="true"))
diff --git a/backend/geonature/utils/config_schema.py b/backend/geonature/utils/config_schema.py
index 1e83119c8e..4d21312bba 100644
--- a/backend/geonature/utils/config_schema.py
+++ b/backend/geonature/utils/config_schema.py
@@ -280,6 +280,7 @@ class TaxonSheet(Schema):
# --------------------------------------------------------------------
# SYNTHESE - TAXON_SHEET
ENABLE_PROFILE = fields.Boolean(load_default=True)
+ ENABLE_TAXONOMY = fields.Boolean(load_default=True)
class Synthese(Schema):
diff --git a/backend/requirements-dependencies.in b/backend/requirements-dependencies.in
index 9af911e5c6..56c86a235c 100644
--- a/backend/requirements-dependencies.in
+++ b/backend/requirements-dependencies.in
@@ -3,5 +3,5 @@ pypnnomenclature>=1.6.4,<2
pypn_habref_api>=0.4.1,<1
utils-flask-sqlalchemy-geo>=0.3.2,<1
utils-flask-sqlalchemy>=0.4.1,<1
-taxhub==2.0.0rc1
+taxhub==2.0.0
pypn-ref-geo>=1.5.3,<2
diff --git a/backend/requirements.txt b/backend/requirements.txt
index ea19f6831d..a59f9d0beb 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -31,6 +31,12 @@ bokeh==3.4.1
# via -r requirements-common.in
brotli==1.1.0
# via fonttools
+cairocffi==1.7.0
+ # via
+ # cairosvg
+ # weasyprint
+cairosvg==2.7.1
+ # via weasyprint
celery[redis]==5.4.0
# via -r requirements-common.in
certifi==2024.8.30
@@ -301,7 +307,7 @@ sqlalchemy==1.4.54
# utils-flask-sqlalchemy
# utils-flask-sqlalchemy-geo
# wtforms-sqlalchemy
-taxhub==2.0.0rc1
+taxhub==2.0.0
# via
# -r requirements-dependencies.in
# pypnnomenclature
diff --git a/config/default_config.toml.example b/config/default_config.toml.example
index 3e3418b622..012c784109 100644
--- a/config/default_config.toml.example
+++ b/config/default_config.toml.example
@@ -445,6 +445,8 @@ MEDIA_CLEAN_CRONTAB = "0 1 * * *"
# Options dédiées à la fiche taxon
# Permet d'activer ou non la section "Profile"
ENABLE_PROFILE = true
+ # Permet d'activer ou non la section "Taxonomy"
+ ENABLE_TAXONOMY = true
# Gestion des demandes d'inscription
[ACCOUNT_MANAGEMENT]
diff --git a/contrib/gn_module_validation/frontend/app/components/validation-modal-info-obs/validation-modal-info-obs.component.html b/contrib/gn_module_validation/frontend/app/components/validation-modal-info-obs/validation-modal-info-obs.component.html
index 4d3086f59c..f39a1dc292 100644
--- a/contrib/gn_module_validation/frontend/app/components/validation-modal-info-obs/validation-modal-info-obs.component.html
+++ b/contrib/gn_module_validation/frontend/app/components/validation-modal-info-obs/validation-modal-info-obs.component.html
@@ -97,6 +97,7 @@
[mailCustomSubject]="config.VALIDATION.MAIL_SUBJECT"
[mailCustomBody]="config.VALIDATION.MAIL_BODY"
useFrom="validation"
+ [selectedTab]="tab"
>