Skip to content

Commit

Permalink
Feat/site type categories and module categorie (#18)
Browse files Browse the repository at this point in the history
* feat(api): add association table with alembic

Add model in backend and alembic migration

Reviewed-by: andriac
[Refs ticket]: #3

* test: WIP add test to see new relationship

Adding test to see if categories are showing up when we call module

Reviewed-by: andriacap
[Refs ticket]: #3

* feat: add type site - categorie relation

WIP - add selectfield to get type site in admin module

Reviewed-by: andriac
[Refs ticket]: #3

* feat(api): Flask admin and routes categories

Clean code for change label list and form selectfield for
the BibCategorieView in Flask Admin

Add utils routes to get all subtable relationship in order to
get back the label type site

Review-by: andriac
[Refs ticket]: #3

* refactor: remove paginate_nested

For depth in as_dict()

* test: fix tests due to as_dict depth

* style: applied black and isort

* chore: remove unused import

Co-authored-by: Andria Capai <[email protected]>
  • Loading branch information
2 people authored and amandine-sahl committed Oct 10, 2023
1 parent 5baf4f7 commit 95c7b18
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""create_cor_module_category
Revision ID: a54bafb13ce8
Revises:
Create Date: 2022-12-06 16:18:24.512562
"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "a54bafb13ce8"
down_revision = "f24adb481f54"
branch_labels = None
depends_on = None

monitorings_schema = "gn_monitoring"
referent_schema = "gn_commons"


def upgrade():
op.create_table(
"cor_module_categorie",
sa.Column(
"id_categorie",
sa.Integer(),
sa.ForeignKey(
f"{monitorings_schema}.bib_categorie_site.id_categorie",
name="fk_cor_module_categorie_id_categorie",
ondelete="CASCADE",
onupdate="CASCADE",
),
nullable=False,
),
sa.Column("id_module", sa.Integer(),sa.ForeignKey(
f"{referent_schema}.t_modules.id_module",
name="fk_cor_module_categorie_id_module",
ondelete="CASCADE",
onupdate="CASCADE",
), nullable=False),
sa.PrimaryKeyConstraint("id_categorie", "id_module", name="pk_cor_module_categorie"),
schema=monitorings_schema,
)


def downgrade():
op.drop_table("cor_module_categorie", schema=monitorings_schema)
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""create_cor_site_type_category
Revision ID: e64bafb13ce8
Revises:
Create Date: 2022-12-06 16:18:24.512562
"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "e64bafb13ce8"
down_revision = "a54bafb13ce8"
branch_labels = None
depends_on = None

monitorings_schema = "gn_monitoring"
referent_schema = "ref_nomenclatures"


def upgrade():
op.create_table(
"cor_site_type_categorie",
sa.Column(
"id_categorie",
sa.Integer(),
sa.ForeignKey(
f"{monitorings_schema}.bib_categorie_site.id_categorie",
name="fk_cor_site_type_categorie_id_categorie",
ondelete="CASCADE",
onupdate="CASCADE",
),
nullable=False,
),
sa.Column("id_nomenclature", sa.Integer(),sa.ForeignKey(
f"{referent_schema}.t_nomenclatures.id_nomenclature",
name="fk_cor_site_type_categorie_id_type",
ondelete="CASCADE",
onupdate="CASCADE",
), nullable=False),
sa.PrimaryKeyConstraint("id_categorie", "id_nomenclature", name="pk_cor_site_type_categorie"),
schema=monitorings_schema,
)


def downgrade():
op.drop_table("cor_site_type_categorie", schema=monitorings_schema)
30 changes: 29 additions & 1 deletion backend/gn_module_monitoring/monitoring/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from flask_admin.contrib.sqla import ModelView
from geonature.core.admin.admin import CruvedProtectedMixin

from geonature.core.gn_commons.models import TNomenclatures
from geonature.utils.env import DB

from gn_module_monitoring.monitoring.models import BibCategorieSite

Expand All @@ -16,3 +17,30 @@ class BibCategorieSiteView(CruvedProtectedMixin, ModelView):
def __init__(self, session, **kwargs):
# Référence au model utilisé
super(BibCategorieSiteView, self).__init__(BibCategorieSite, session, **kwargs)

def get_only_type_site_asc():
return (
DB.session.query(TNomenclatures)
.filter(TNomenclatures.id_type == 116)
.order_by(TNomenclatures.label_fr.asc())
)

def get_label_fr_nomenclature(x):
return x.label_fr

def list_label_site_type_formatter(view, _context, model, _name):
return [item.label_fr for item in model.site_type]

# Nom de colonne user friendly
column_labels = dict(site_type="Type de site")
# Description des colonnes
column_descriptions = dict(site_type="Type de site à choisir en lien avec la catégorie")

column_hide_backrefs = False

form_args = dict(
site_type=dict(query_factory=get_only_type_site_asc, get_label=get_label_fr_nomenclature)
)

column_list = ("label", "config", "site_type")
column_formatters = dict(site_type=list_label_site_type_formatter)
31 changes: 30 additions & 1 deletion backend/gn_module_monitoring/monitoring/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from sqlalchemy.ext.hybrid import hybrid_property


from pypnnomenclature.models import TNomenclatures, BibNomenclaturesTypes
from geonature.core.gn_commons.models import TMedias
from geonature.core.gn_monitoring.models import TBaseSites, TBaseVisits
from geonature.core.gn_meta.models import TDatasets
Expand All @@ -20,6 +20,35 @@
from pypnusershub.db.models import User
from geonature.core.gn_monitoring.models import corVisitObserver

cor_module_categorie = DB.Table(
"cor_module_categorie",
DB.Column(
"id_module",
DB.Integer,
DB.ForeignKey("gn_commons.t_modules.id_module"),
primary_key=True,
),
DB.Column(
"id_categorie",
DB.Integer,
DB.ForeignKey("gn_monitoring.bib_categorie_site.id_categorie"),
primary_key=True,
), schema="gn_monitoring")

cor_site_type_categorie = DB.Table(
"cor_site_type_categorie",
DB.Column(
"id_nomenclature",
DB.Integer,
DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"),
primary_key=True,
),
DB.Column(
"id_categorie",
DB.Integer,
DB.ForeignKey("gn_monitoring.bib_categorie_site.id_categorie"),
primary_key=True,
), schema="gn_monitoring")

@serializable
class TMonitoringObservationDetails(DB.Model):
Expand Down
8 changes: 3 additions & 5 deletions backend/gn_module_monitoring/routes/site.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
from typing import Tuple

from flask import request
from flask.json import jsonify
from geonature.core.gn_monitoring.models import TBaseSites
from werkzeug.datastructures import MultiDict

from gn_module_monitoring.blueprint import blueprint
from gn_module_monitoring.monitoring.models import BibCategorieSite
from gn_module_monitoring.utils.routes import (filter_params, get_limit_offset,
paginate)
from gn_module_monitoring.utils.routes import filter_params, get_limit_offset, paginate


@blueprint.route("/sites/categories", methods=["GET"])
Expand All @@ -18,7 +15,8 @@ def get_categories():

query = filter_params(query=BibCategorieSite.query, params=params)
query = query.order_by(BibCategorieSite.id_categorie)
return paginate(query=query, object_name="categories", limit=limit, page=page)

return paginate(query=query, object_name="categories", limit=limit, page=page, depth=1)


@blueprint.route("/sites/categories/<int:id_categorie>", methods=["GET"])
Expand Down
Empty file.
21 changes: 21 additions & 0 deletions backend/gn_module_monitoring/tests/fixtures/module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pytest
from geonature.core.gn_commons.models.base import TModules
from geonature.utils.env import db

from gn_module_monitoring.monitoring.models import TMonitoringModules
from gn_module_monitoring.tests.fixtures.site import categories


@pytest.fixture
def monitoring_module(module, categories):
id_module = TModules.query.filter(TModules.id_module == module.id_module).one().id_module
t_monitoring_module = TMonitoringModules()

module_data = {"id_module": id_module, "categories": list(categories.values())}
t_monitoring_module.from_dict(module_data)
# monitoring = TMonitoringModules(id_module=id_module, categories=list(categories.values()))
monitoring = t_monitoring_module
with db.session.begin_nested():
db.session.add(monitoring)

return monitoring
14 changes: 12 additions & 2 deletions backend/gn_module_monitoring/tests/fixtures/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,18 @@


@pytest.fixture()
def categories():
categories = [{"label": "gite", "config": {}}, {"label": "eolienne", "config": {}}]
def site_type():
return TNomenclatures.query.filter(
BibNomenclaturesTypes.mnemonique == "TYPE_SITE", TNomenclatures.mnemonique == "Grotte"
).one()


@pytest.fixture()
def categories(site_type):
categories = [
{"label": "gite", "config": {}, "site_type": [site_type]},
{"label": "eolienne", "config": {}, "site_type": [site_type]},
]

categories = {cat["label"]: BibCategorieSite(**cat) for cat in categories}

Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import pytest

from gn_module_monitoring.tests.fixtures.module import monitoring_module
from gn_module_monitoring.tests.fixtures.site import categories


@pytest.mark.usefixtures("temporary_transaction")
class TestModule:
def test_module(self, monitoring_module):
cateogories = monitoring_module.categories
assert False
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest
from flask import url_for

from gn_module_monitoring.tests.fixtures.site import categories, sites
from gn_module_monitoring.tests.fixtures.site import categories, site_type, sites


@pytest.mark.usefixtures("client_class", "temporary_transaction")
Expand All @@ -20,13 +20,13 @@ def test_get_categories(self, categories):
r = self.client.get(url_for("monitorings.get_categories"))

assert r.json["count"] >= len(categories)
assert all([cat.as_dict() in r.json["categories"] for cat in categories.values()])
assert all([cat.as_dict(depth=1) in r.json["categories"] for cat in categories.values()])

def test_get_categories_label(self, categories):
label = list(categories.keys())[0]

r = self.client.get(url_for("monitorings.get_categories"), query_string={"label": label})
assert categories[label].as_dict() in r.json["categories"]
assert categories[label].as_dict(depth=1) in r.json["categories"]

def test_get_sites(self, sites):
r = self.client.get(url_for("monitorings.get_sites"))
Expand Down
9 changes: 5 additions & 4 deletions backend/gn_module_monitoring/utils/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ def get_limit_offset(params: MultiDict) -> Tuple[int]:
return params.pop("limit", 50), params.pop("offset", 1)


def paginate(query: Query, object_name: str, limit: int, page: int) -> Response:
def paginate(query: Query, object_name: str, limit: int, page: int, depth: int = 0) -> Response:
result = query.paginate(page=page, error_out=False, max_per_page=limit)
data = {
object_name: [res.as_dict() for res in result.items],
object_name: [res.as_dict(depth=depth) for res in result.items],
"count": result.total,
"limit": limit,
"offset": page - 1,
}
return jsonify(data)

def filter_params(query: Query, params: MultiDict) -> Query:

def filter_params(query: Query, params: MultiDict) -> Query:
if len(params) != 0:
query = query.filter_by(**params)
return query
return query

0 comments on commit 95c7b18

Please sign in to comment.