"""
Modèles du schéma gn_monitoring
Correspond a la centralisation des données de base
relatifs aux protocoles de suivis
"""
from flask import g
from datetime import datetime
from geoalchemy2 import Geometry
from sqlalchemy import ForeignKey, or_, false
from sqlalchemy.orm import relationship
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.sql import select, func
from sqlalchemy.schema import FetchedValue
from sqlalchemy.ext.hybrid import hybrid_property
from pypnnomenclature.models import TNomenclatures
from pypnusershub.db.models import User
from ref_geo.models import LAreas
from utils_flask_sqla.serializers import serializable
from utils_flask_sqla_geo.serializers import geoserializable
from geonature.core.gn_commons.models import TModules, TMedias
from geonature.core.gn_meta.models import TDatasets
from geonature.utils.env import DB
[docs]
cor_visit_observer = DB.Table(
"cor_visit_observer",
DB.Column(
"id_base_visit",
DB.Integer,
ForeignKey("gn_monitoring.t_base_visits.id_base_visit"),
primary_key=True,
),
DB.Column(
"id_role",
DB.Integer,
ForeignKey("utilisateurs.t_roles.id_role"),
primary_key=True,
),
schema="gn_monitoring",
)
[docs]
cor_site_module = DB.Table(
"cor_site_module",
DB.Column(
"id_base_site",
DB.Integer,
ForeignKey("gn_monitoring.t_base_sites.id_base_site"),
primary_key=True,
),
DB.Column(
"id_module",
DB.Integer,
ForeignKey("gn_commons.t_modules.id_module"),
primary_key=True,
),
schema="gn_monitoring",
)
[docs]
cor_site_area = DB.Table(
"cor_site_area",
DB.Column(
"id_base_site",
DB.Integer,
ForeignKey("gn_monitoring.t_base_sites.id_base_site"),
primary_key=True,
),
DB.Column("id_area", DB.Integer, ForeignKey(LAreas.id_area), primary_key=True),
schema="gn_monitoring",
)
[docs]
cor_module_type = DB.Table(
"cor_module_type",
DB.Column(
"id_module",
DB.Integer,
DB.ForeignKey("gn_commons.t_modules.id_module"),
primary_key=True,
),
DB.Column(
"id_type_site",
DB.Integer,
DB.ForeignKey("gn_monitoring.bib_type_site.id_nomenclature_type_site"),
primary_key=True,
),
schema="gn_monitoring",
)
[docs]
cor_site_type = DB.Table(
"cor_site_type",
DB.Column(
"id_base_site",
DB.Integer,
DB.ForeignKey("gn_monitoring.t_base_sites.id_base_site"),
primary_key=True,
),
DB.Column(
"id_type_site",
DB.Integer,
DB.ForeignKey("gn_monitoring.bib_type_site.id_nomenclature_type_site"),
primary_key=True,
),
schema="gn_monitoring",
)
@serializable
[docs]
class BibTypeSite(DB.Model):
[docs]
__tablename__ = "bib_type_site"
[docs]
__table_args__ = {"schema": "gn_monitoring"}
[docs]
id_nomenclature_type_site = DB.Column(
DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"),
nullable=False,
primary_key=True,
)
[docs]
config = DB.Column(JSONB)
[docs]
nomenclature = DB.relationship(
TNomenclatures, uselist=False, backref=DB.backref("bib_type_site", uselist=False)
)
[docs]
sites = DB.relationship("TBaseSites", secondary=cor_site_type, lazy="noload")
@serializable
[docs]
class TBaseVisits(DB.Model):
"""
Table de centralisation des visites liées à un site
"""
[docs]
__tablename__ = "t_base_visits"
[docs]
__table_args__ = {"schema": "gn_monitoring"}
[docs]
id_base_visit = DB.Column(DB.Integer, primary_key=True)
[docs]
id_base_site = DB.Column(DB.Integer, ForeignKey("gn_monitoring.t_base_sites.id_base_site"))
[docs]
id_digitiser = DB.Column(DB.Integer, ForeignKey("utilisateurs.t_roles.id_role"))
[docs]
id_dataset = DB.Column(DB.Integer, ForeignKey("gn_meta.t_datasets.id_dataset"))
# Pour le moment non défini comme une clé étrangère
# pour les questions de perfs
# a voir en fonction des usage
[docs]
id_module = DB.Column(DB.Integer, ForeignKey("gn_commons.t_modules.id_module"))
[docs]
visit_date_min = DB.Column(DB.DateTime)
[docs]
visit_date_max = DB.Column(DB.DateTime)
[docs]
id_nomenclature_tech_collect_campanule = DB.Column(DB.Integer)
[docs]
id_nomenclature_grp_typ = DB.Column(DB.Integer)
[docs]
uuid_base_visit = DB.Column(UUID(as_uuid=True), default=select(func.uuid_generate_v4()))
[docs]
digitiser = relationship(
User, primaryjoin=(User.id_role == id_digitiser), foreign_keys=[id_digitiser]
)
[docs]
observers = DB.relationship(
User,
secondary=cor_visit_observer,
primaryjoin=(cor_visit_observer.c.id_base_visit == id_base_visit),
secondaryjoin=(cor_visit_observer.c.id_role == User.id_role),
foreign_keys=[cor_visit_observer.c.id_base_visit, cor_visit_observer.c.id_role],
)
[docs]
observers_txt = DB.Column(DB.Unicode)
[docs]
dataset = relationship(
TDatasets,
primaryjoin=(TDatasets.id_dataset == id_dataset),
foreign_keys=[id_dataset],
)
@serializable
@geoserializable(geoCol="geom", idCol="id_base_site")
[docs]
class TBaseSites(DB.Model):
"""
Table centralisant les données élémentaire des sites
"""
[docs]
__tablename__ = "t_base_sites"
[docs]
__table_args__ = {"schema": "gn_monitoring"}
[docs]
id_base_site = DB.Column(DB.Integer, primary_key=True)
[docs]
id_inventor = DB.Column(DB.Integer, ForeignKey("utilisateurs.t_roles.id_role"))
[docs]
id_digitiser = DB.Column(DB.Integer, ForeignKey("utilisateurs.t_roles.id_role"))
[docs]
base_site_name = DB.Column(DB.Unicode)
[docs]
base_site_description = DB.Column(DB.Unicode)
[docs]
base_site_code = DB.Column(DB.Unicode)
[docs]
first_use_date = DB.Column(DB.DateTime)
[docs]
geom = DB.Column(Geometry("GEOMETRY", 4326))
[docs]
uuid_base_site = DB.Column(UUID(as_uuid=True), default=select(func.uuid_generate_v4()))
[docs]
altitude_min = DB.Column(DB.Integer)
[docs]
altitude_max = DB.Column(DB.Integer)
[docs]
digitiser = relationship(
User, primaryjoin=(User.id_role == id_digitiser), foreign_keys=[id_digitiser]
)
[docs]
inventor = relationship(
User, primaryjoin=(User.id_role == id_inventor), foreign_keys=[id_inventor]
)
[docs]
t_base_visits = relationship("TBaseVisits", lazy="select", cascade="all,delete-orphan")
[docs]
modules = DB.relationship(
"TModules",
lazy="select",
enable_typechecks=False,
secondary=cor_site_module,
primaryjoin=(cor_site_module.c.id_base_site == id_base_site),
secondaryjoin=(cor_site_module.c.id_module == TModules.id_module),
foreign_keys=[cor_site_module.c.id_base_site, cor_site_module.c.id_module],
)
[docs]
corIndividualModule = DB.Table(
"cor_individual_module",
DB.Column(
"id_individual",
DB.Integer,
DB.ForeignKey("gn_monitoring.t_individuals.id_individual", ondelete="CASCADE"),
primary_key=True,
),
DB.Column(
"id_module",
DB.Integer,
DB.ForeignKey("gn_commons.t_modules.id_module", ondelete="CASCADE"),
primary_key=True,
),
schema="gn_monitoring",
)
@serializable
[docs]
class TObservations(DB.Model):
[docs]
__tablename__ = "t_observations"
[docs]
__table_args__ = {"schema": "gn_monitoring"}
[docs]
id_observation = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True)
[docs]
id_base_visit = DB.Column(DB.ForeignKey("gn_monitoring.t_base_visits.id_base_visit"))
[docs]
id_digitiser = DB.Column(DB.Integer, DB.ForeignKey("utilisateurs.t_roles.id_role"))
[docs]
digitiser = DB.relationship(
User, primaryjoin=(User.id_role == id_digitiser), foreign_keys=[id_digitiser]
)
[docs]
cd_nom = DB.Column(DB.Integer, DB.ForeignKey("taxonomie.taxref.cd_nom"), nullable=False)
[docs]
uuid_observation = DB.Column(UUID(as_uuid=True), default=select(func.uuid_generate_v4()))
[docs]
id_individual = DB.Column(DB.ForeignKey("gn_monitoring.t_individuals.id_individual"))
@serializable
[docs]
class TMarkingEvent(DB.Model):
[docs]
__tablename__ = "t_marking_events"
[docs]
__table_args__ = {"schema": "gn_monitoring"}
[docs]
id_marking = DB.Column(DB.Integer, primary_key=True, autoincrement=True)
[docs]
uuid_marking = DB.Column(UUID(as_uuid=True), default=select(func.uuid_generate_v4()))
[docs]
id_individual = DB.Column(
DB.ForeignKey(f"gn_monitoring.t_individuals.id_individual", ondelete="CASCADE"),
nullable=False,
)
[docs]
id_module = DB.Column(
DB.ForeignKey("gn_commons.t_modules.id_module"),
primary_key=True,
nullable=False,
unique=True,
)
[docs]
id_digitiser = DB.Column(
DB.ForeignKey("utilisateurs.t_roles.id_role"),
nullable=False,
)
[docs]
marking_date = DB.Column(DB.DateTime(timezone=False), nullable=False)
[docs]
id_operator = DB.Column(DB.ForeignKey("utilisateurs.t_roles.id_role"), nullable=False)
[docs]
id_base_marking_site = DB.Column(DB.ForeignKey("gn_monitoring.t_base_sites.id_base_site"))
[docs]
id_nomenclature_marking_type = DB.Column(
DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"), nullable=False
)
[docs]
marking_location = DB.Column(DB.Unicode(255))
[docs]
marking_code = DB.Column(DB.Unicode(255))
[docs]
marking_details = DB.Column(DB.Text)
[docs]
data = DB.Column(JSONB)
[docs]
operator = DB.relationship(User, lazy="joined", foreign_keys=[id_operator])
[docs]
digitiser = DB.relationship(User, lazy="joined", foreign_keys=[id_digitiser])
@hybrid_property
[docs]
def organism_actors(self):
# return self.digitiser.id_organisme
actors_organism_list = []
if isinstance(self.digitiser, User):
actors_organism_list.append(self.digitiser.id_organisme)
if isinstance(self.operator, User):
actors_organism_list.append(self.operator.id_organisme)
return actors_organism_list
[docs]
def has_instance_permission(self, scope):
if scope == 0:
return False
elif scope in (1, 2):
if (
g.current_user.id_role == self.id_digitiser
or g.current_user.id_role == self.id_operator
):
return True
if scope == 2 and g.current_user.id_organisme in self.organism_actors:
return True
elif scope == 3:
return True
return False
@serializable
[docs]
class TIndividuals(DB.Model):
[docs]
__tablename__ = "t_individuals"
[docs]
__table_args__ = {"schema": "gn_monitoring"}
[docs]
id_individual = DB.Column(DB.Integer, primary_key=True)
[docs]
uuid_individual = DB.Column(UUID, nullable=False, server_default=DB.text("uuid_generate_v4()"))
[docs]
individual_name = DB.Column(DB.Unicode(255), nullable=False)
[docs]
cd_nom = DB.Column(DB.Integer, DB.ForeignKey("taxonomie.taxref.cd_nom"), nullable=False)
[docs]
id_nomenclature_sex = DB.Column(
DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"),
server_default=DB.text(
"ref_nomenclatures.get_default_nomenclature_value('SEXE'::character varying)"
),
)
[docs]
active = DB.Column(DB.Boolean, default=True)
[docs]
id_digitiser = DB.Column(
DB.ForeignKey("utilisateurs.t_roles.id_role"),
nullable=False,
)
[docs]
digitiser = DB.relationship(
User,
lazy="joined",
)
[docs]
nomenclature_sex = DB.relationship(
TNomenclatures,
lazy="select",
primaryjoin=(TNomenclatures.id_nomenclature == id_nomenclature_sex),
)
[docs]
modules = DB.relationship(
"TModules",
lazy="joined",
secondary=corIndividualModule,
primaryjoin=(corIndividualModule.c.id_individual == id_individual),
secondaryjoin=(corIndividualModule.c.id_module == TModules.id_module),
foreign_keys=[corIndividualModule.c.id_individual, corIndividualModule.c.id_module],
)
[docs]
markings = DB.relationship(
TMarkingEvent,
primaryjoin=(id_individual == TMarkingEvent.id_individual),
)
@classmethod
[docs]
def filter_by_scope(cls, query, scope, user):
if scope == 0:
query = query.where(false())
elif scope in (1, 2):
ors = [
cls.id_digitiser == user.id_role,
]
# if organism is None => do not filter on id_organism even if level = 2
if scope == 2 and user.id_organisme is not None:
ors.append(cls.digitiser.has(id_organisme=user.id_organisme))
query = query.where(or_(*ors))
return query
@hybrid_property
[docs]
def organism_actors(self):
# return self.digitiser.id_organisme
actors_organism_list = []
if isinstance(self.digitiser, User):
actors_organism_list.append(self.digitiser.id_organisme)
return actors_organism_list
[docs]
def has_instance_permission(self, scope):
if scope == 0:
return False
elif scope in (1, 2):
if g.current_user.id_role == self.id_digitiser:
return True
if scope == 2 and g.current_user.id_organisme in self.organism_actors:
return True
elif scope == 3:
return True
return False