class ProgramsModel(TimestampMixinModel, db.Model): """Table des Programmes de GeoNature-citizen""" __tablename__ = "t_programs" __table_args__ = {"schema": "gnc_core"} id_program = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(50), nullable=False) short_desc = db.Column(db.String(200), nullable=False) long_desc = db.Column(db.Text(), nullable=False) image = db.Column(db.String(250)) logo = db.Column(db.String(250)) module = db.Column( db.Integer, ForeignKey(ModulesModel.id_module), nullable=False, default=1, ) taxonomy_list = db.Column( db.Integer, #ForeignKey(BibListes.id_liste), nullable=True ) is_active = db.Column( db.Boolean(), server_default=expression.true(), default=True ) geom = db.Column(Geometry("GEOMETRY", 4326)) def get_geofeature(self, recursif=True, columns=None): return self.as_geofeature( "geom", "id_program", recursif, columns=columns )
class GroupsModel(db.Model): # type: ignore """Table des groupes d'utilisateurs""" __tablename__ = "bib_groups" __table_args__ = {"schema": "gnc_core"} id_group = db.Column(db.Integer, primary_key=True) category = db.Column(db.String(150), nullable=True) group = db.Column(db.String(150), nullable=False)
class GeometryModel(TimestampMixinModel, db.Model): """Table des géométries associées aux programmes""" __tablename__ = "t_geometries" __table_args__ = {"schema": "gnc_core"} id_geom = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) description = db.Column(db.Text(), nullable=True) geom = db.Column(Geometry("GEOMETRY", 4326)) geom_file = db.Column(db.String(250), nullable=True) def get_geom_file_path(self): return os.path.join(str(MEDIA_DIR), self.geom_file) def set_geom_from_geom_file(self): gnc_invalid_err_message = "Géométrie non valide pour GNC" name, ext = os.path.splitext(self.geom_file) with open(self.get_geom_file_path()) as geom_file: geo_data = geom_file.read() if ext in [".geojson", ".json"]: json_geom = json.loads(geo_data)["features"][0]["geometry"] # Validate geometry type if not json_geom["type"] in ["Polygon", "MultiPolygon"]: raise Exception(gnc_invalid_err_message) else: # Minimal coordinate system check coords = json_geom["coordinates"][0][0] if json_geom["type"] == "MultiPolygon": coords = coords[0] x, y = coords if abs(x) > 180 or abs(y) > 180: raise Exception("Mauvais système de projection") # Convert Geo self.geom = ST_SetSRID( ST_GeomFromGeoJSON(json.dumps(json_geom)), 4326) elif ext == ".kml": kml_root = ET.fromstring(geo_data) kml_geom_elt = None # Find first MultiGeometry or Polygon node for child in kml_root.iter(): if "MultiGeometry" in child.tag or "Polygon" in child.tag: kml_geom_elt = child if "MultiGeometry" in child.tag: # We want only Polygon nodes inside the geometry for elt in kml_geom_elt.getchildren(): if not "Polygon" in elt.tag: raise Exception(gnc_invalid_err_message) if kml_geom_elt is None: raise Exception(gnc_invalid_err_message) kml_geom = ET.tostring(kml_geom_elt, encoding="unicode", method="xml") self.geom = ST_GeomFromKML(kml_geom) # KML is always 4326 srid def __repr__(self): return self.name
class ModulesModel(TimestampMixinModel, db.Model): """Table des modules de GeoNature-citizen""" __tablename__ = "t_modules" __table_args__ = {"schema": "gnc_core"} id_module = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) label = db.Column(db.String(50), nullable=False) desc = db.Column(db.String(200)) icon = db.Column(db.String(250)) on_sidebar = db.Column(db.Boolean(), default=False)
class ProgramsModel(TimestampMixinModel, db.Model): """Table des Programmes de GeoNature-citizen""" __tablename__ = "t_programs" __table_args__ = {"schema": "gnc_core"} id_program = db.Column(db.Integer, primary_key=True) unique_id_program = db.Column(UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False) id_project = db.Column(db.Integer, db.ForeignKey(ProjectModel.id_project), nullable=False) title = db.Column(db.String(50), nullable=False) short_desc = db.Column(db.String(200), nullable=False) long_desc = db.Column(db.Text(), nullable=False) form_message = db.Column(db.String(500)) image = db.Column(db.String(250)) logo = db.Column(db.String(250)) id_module = db.Column( db.Integer, ForeignKey(TModules.id_module), nullable=False, default=1, ) module = relationship("TModules") taxonomy_list = db.Column(db.Integer, nullable=True) is_active = db.Column(db.Boolean(), server_default=expression.true(), default=True) id_geom = db.Column(db.Integer, db.ForeignKey(GeometryModel.id_geom), nullable=False) id_form = db.Column(db.Integer, db.ForeignKey(CustomFormModel.id_form), nullable=True) custom_form = relationship("CustomFormModel") geometry = relationship("GeometryModel") project = relationship("ProjectModel") def get_geofeature(self, recursif=True, columns=None): geometry = to_shape(self.geometry.geom) feature = Feature( id=self.id_program, geometry=geometry, properties=self.as_dict(True, exclude=["t_obstax"]), ) return feature def __repr__(self): return self.title
class ProjectModel(TimestampMixinModel, db.Model): """Table des projets regroupant les programmes""" __tablename__ = "t_projects" __table_args__ = {"schema": "gnc_core"} id_project = db.Column(db.Integer, primary_key=True) unique_id_project = db.Column(UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False) name = db.Column(db.String(50), nullable=False) short_desc = db.Column(db.String(200), nullable=True) long_desc = db.Column(db.Text(), nullable=True) def __repr__(self): return self.name
class MediaModel(TimestampMixinModel, db.Model): """Table des Programmes de GeoNature-citizen """ __tablename__ = "t_medias" __table_args__ = {"schema": "gnc_core"} id_media = db.Column(db.Integer, primary_key=True) filename = db.Column(db.String(50), nullable=False)
class CustomFormModel(TimestampMixinModel, db.Model): """Table des Formulaires spécifiques associés aux programmes""" __tablename__ = "t_custom_form" __table_args__ = {"schema": "gnc_core"} id_form = db.Column(db.Integer, primary_key=True, unique=True) name = db.Column(db.String(250)) json_schema = db.Column(JSONB, nullable=True) def __repr__(self): return self.name
class RevokedTokenModel(TimestampCreateMixinModel, db.Model): # type: ignore __tablename__ = "t_revoked_tokens" __table_args__ = {"schema": "gnc_core"} id = db.Column(db.Integer, primary_key=True) jti = db.Column(db.String(120)) def add(self): db.session.add(self) db.session.commit() @classmethod def is_jti_blacklisted(cls, jti): query = cls.query.filter_by(jti=jti).first() return bool(query)
class UserRightsModel(TimestampMixinModel, db.Model): # type: ignore """Table de gestion des droits des utilisateurs de GeoNature-citizen""" __tablename__ = "t_users_rights" __table_args__ = {"schema": "gnc_core"} id_user_right = db.Column(db.Integer, primary_key=True) id_user = db.Column(db.Integer, db.ForeignKey(UserModel.id_user), nullable=False) id_module = db.Column(db.Integer, db.ForeignKey(ModulesModel.id_module), nullable=True) id_module = db.Column(db.Integer, db.ForeignKey(ProgramsModel.id_program), nullable=True) right = db.Column(db.String(150), nullable=False) create = db.Column(db.Boolean(), default=False) read = db.Column(db.Boolean(), default=False) update = db.Column(db.Boolean(), default=False) delete = db.Column(db.Boolean(), default=False)
class ObservationModel( ObserverMixinModel, TimestampMixinModel, db.Model # type: ignore ): """Table des observations""" __tablename__ = "t_obstax" __table_args__ = {"schema": "gnc_obstax"} id_observation = db.Column(db.Integer, primary_key=True, unique=True) uuid_sinp = db.Column(UUID(as_uuid=True), nullable=False, unique=True) id_program = db.Column(db.Integer, db.ForeignKey(ProgramsModel.id_program), nullable=False) cd_nom = db.Column( db.Integer, db.ForeignKey(Taxref.cd_nom), # todo: removal breaks recog rewards nullable=False, ) date = db.Column(db.Date, nullable=False) count = db.Column(db.Integer) comment = db.Column(db.String(300)) municipality = db.Column(db.Integer, db.ForeignKey(LAreas.id_area)) geom = db.Column(Geometry("POINT", 4326))
class UserModel(TimestampMixinModel, db.Model): # type: ignore """ Table des utilisateurs """ __tablename__ = "t_users" __table_args__ = {"schema": "gnc_core"} id_user = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) surname = db.Column(db.String(100), nullable=False) username = db.Column(db.String(12), unique=True, nullable=False) password = db.Column(db.String(120), nullable=False) email = db.Column(db.String(150), unique=True, nullable=False) phone = db.Column(db.String(15)) organism = db.Column(db.String(100)) admin = db.Column(db.Boolean, default=False) def save_to_db(self): db.session.add(self) db.session.commit() def update(self): db.session.commit() def as_user_dict(self): surname = self.username or "" name = self.name or "" return { "id_role": self.id_user, "name": self.name, "surname": self.surname, "username": self.username, "email": self.email, "phone": self.phone, "organism": self.organism, "full_name": name + " " + surname, "admin": self.admin, "timestamp_create": self.timestamp_create.isoformat(), "timestamp_update": self.timestamp_update.isoformat() if self.timestamp_update else None, } @staticmethod def generate_hash(password): return sha256.hash(password) @staticmethod def verify_hash(password, hash_): return sha256.verify(password, hash_) @classmethod def find_by_username(cls, username): try: return cls.query.filter_by(username=username).one() except NoResultFound: raise Exception(f"""User "{username}" not found.""") @classmethod def return_all(cls): def to_dict(x): return { "username": x.username, "password": x.password, "email": x.email, "phone": x.phone, "admin": x.admin, } return { "users": list( map( lambda x: to_dict(x), # pylint: disable=unnecessary-lambda UserModel.query.all(), )) }
def email(self): return db.Column(db.String(150))
def obs_txt(self): return db.Column(db.String(150))