Restructure api

Fixes in geo api, registry
Cleanups
This commit is contained in:
phil 2024-02-27 05:05:33 +05:30
parent c84dd61f6a
commit 8c299f0041
17 changed files with 212 additions and 162 deletions

View file

@ -27,7 +27,7 @@ class UserBase(SQLModel):
class User(UserBase, table=True):
__table_args__ = gisaf_admin.table_args
id: int | None = Field(default=None, primary_key=True)
id: str | None = Field(default=None, primary_key=True)
roles: list["Role"] = Relationship(back_populates="users",
link_model=UserRoleLink)
password: str | None = None

View file

@ -61,8 +61,8 @@ class CategoryBase(BaseModel):
style: str | None = Field(sa_type=TEXT)
symbol: str | None = Field(sa_type=String(1)) # type: ignore
mapbox_type_custom: str | None = Field(sa_type=String(12)) # type: ignore
mapbox_paint: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
mapbox_layout: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
mapbox_paint: dict[str, dict | list | float | int | str] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
mapbox_layout: dict[str, dict | list | float | int | str] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
viewable_role: str | None
extra: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore

View file

@ -14,20 +14,20 @@ import shapely # type: ignore
import pyproj
from pydantic import BaseModel
from sqlmodel import select, Field, Relationship
from sqlmodel import select, Field
from sqlmodel.ext.asyncio.session import AsyncSession
from sqlalchemy import BigInteger, MetaData, String, func, and_, text
from sqlalchemy import BigInteger, String, func, and_, text
from sqlalchemy.sql import sqltypes
from sqlalchemy.orm import declared_attr
from psycopg2.extensions import adapt
from geoalchemy2.shape import from_shape
from geoalchemy2.types import Geometry, WKBElement
from shapely import wkb, from_wkb
from shapely.geometry import mapping
from shapely.geometry import mapping # type: ignore
from shapely.ops import transform # type: ignore
from shapefile import (
Writer as ShapeFileWriter, # type: ignore
from shapefile import ( # type: ignore
Writer as ShapeFileWriter,
POINT, POINTZ,
POLYLINE, POLYLINEZ,
POLYGON, POLYGONZ,
@ -35,8 +35,9 @@ from shapefile import (
from gisaf.database import db_session
from gisaf.config import conf
from gisaf.models.map_bases import MaplibreStyle
from gisaf.models.models_base import Model
from gisaf.models.metadata import gisaf_survey, gisaf_admin, survey
from gisaf.models.metadata import gisaf_survey, gisaf_admin, survey, raw_survey
from gisaf.models.misc import Qml
from gisaf.models.category import Category
from gisaf.models.to_migrate import InfoItem
@ -157,6 +158,7 @@ class SurveyModel(BaseSurveyModel):
# status: str = Field(sa_type=String(1))
get_gdf_with_related: ClassVar[bool] = False
category_name: ClassVar[str]
filtered_columns_on_map: ClassVar[list[str]] = [
'equip_id',
@ -219,9 +221,8 @@ class SurveyModel(BaseSurveyModel):
@classmethod
async def get_geojson(cls,
registry=None, simplify_tolerance=0, preserve_topology=False):
if registry is None:
from ..registry import registry
simplify_tolerance=0, preserve_topology=False):
from gisaf.registry import registry
## Fastest, but the id is in properties and needs the front end (eg Gisaf for mapbox)
## to move it at the feature level
@ -592,36 +593,35 @@ class GeoModelNoStatus(Model):
return zip_file
@classmethod
async def get_mapbox_style(cls):
async def get_maplibre_style(cls) -> MaplibreStyle | None:
"""
Get the mapbox style (paint, layout, attribution...)
"""
## If the model is from survey, it should have a category, which has a style
## Get from database
style = {}
if hasattr(cls, 'category'):
category = await Category.get_item_by_pk(pk=cls.category.name)
if category:
if category['mapbox_paint'] is not None:
style['paint'] = category['mapbox_paint']
if category['mapbox_layout'] is not None:
style['layout'] = category['mapbox_layout']
else:
category = None
qml = await Qml.get_item_by_pk(pk=cls.__name__)
if qml:
if qml['mapbox_paint']:
style['paint'] = qml['mapbox_paint']
if qml['mapbox_layout']:
style['layout'] = qml['mapbox_layout']
if cls.attribution is not None:
style['attribution'] = cls.attribution
style: MaplibreStyle | None
async with db_session() as session:
if hasattr(cls, 'category'):
category = await session.get(Category, cls.get_store_name())
if category:
style = MaplibreStyle(
layout=category.mapbox_layout,
paint=category.mapbox_paint,
)
else:
style = None
else:
qml = await session.get(Qml, cls.__name__)
if qml:
style = MaplibreStyle(
layout=qml.mapbox_layout,
paint=qml.mapbox_paint,
attribution=qml.attr,
)
else:
style = None
return style
@classmethod
async def get_features_attrs(cls, simplify_tolerance):
"""
@ -1094,10 +1094,13 @@ class RawSurveyBaseModel(BaseSurveyModel, GeoPointModelNoStatus):
"""
Abstract base class for category based raw survey point models
"""
# metadata: ClassVar[MetaData] = raw_survey
geom: Annotated[str, WKBElement] = Field(sa_type=Geometry('POINTZ', dimension=3,
srid=conf.geo.raw_survey.srid))
status: str = Field(sa_type=String(1))
__table_args__ = raw_survey.table_args
geom: Annotated[str, WKBElement] = Field(
sa_type=Geometry('POINTZ',
dimension=3,
srid=conf.geo.raw_survey.srid),
) # type: ignore
status: str = Field(sa_type=String(1)) # type: ignore
## store_name is set in category_models_maker.make_category_models
store_name: ClassVar[str | None] = None

View file

@ -28,30 +28,6 @@ class BaseStyle(Model, table=True):
return f'<models.BaseStyle {self.name:s}>'
class BaseMap(Model, table=True):
__table_args__ = gisaf_map.table_args
__tablename__: str = 'base_map' # type: ignore
class Admin:
menu = 'Other'
id: int | None = Field(primary_key=True, default=None)
name: str
layers: list['BaseMapLayer'] = Relationship(back_populates='base_map')
def __repr__(self) -> str:
return f'<models.BaseMap {self.name:s}>'
def __str__(self) -> str:
return self.name
@classmethod
def selectinload(cls) -> list[list['BaseMapLayer']]:
return [
cls.layers
]
class BaseMapLayer(Model, table=True):
__table_args__ = gisaf_map.table_args
__tablename__: str = 'base_map_layer' # type: ignore
@ -62,7 +38,7 @@ class BaseMapLayer(Model, table=True):
id: int | None = Field(primary_key=True, default=None)
base_map_id: int = Field(foreign_key=gisaf_map.table('base_map.id'),
index=True)
base_map: BaseMap = Relationship(back_populates='layers')
base_map: 'BaseMap' = Relationship() #back_populates='layers')
store: str = Field(sa_type=String(100)) # type: ignore
@classmethod
@ -78,8 +54,46 @@ class BaseMapLayer(Model, table=True):
return f"{self.store or '':s}"
class BaseMap(Model, table=True):
__table_args__ = gisaf_map.table_args
__tablename__: str = 'base_map' # type: ignore
class Admin:
menu = 'Other'
id: int | None = Field(primary_key=True, default=None)
name: str
# layers: list['BaseMapLayer'] = Relationship(
# back_populates='base_map',
# # link_model=BaseMapLayer
# )
def __repr__(self) -> str:
return f'<models.BaseMap {self.name:s}>'
def __str__(self) -> str:
return self.name
# @classmethod
# def selectinload(cls) -> list[list[BaseMapLayer]]:
# return [
# cls.layers
# ]
class BaseMapWithStores(BaseModel):
name: str
stores: list[str]
class MapInitData(BaseModel):
baseStyles: list[BaseStyle] = []
baseMaps: list[BaseMap] = []
baseMaps: list[BaseMapWithStores] = []
groups: list[CategoryGroup] = []
stores: list[Store] = []
stores: list[Store] = []
class MaplibreStyle(BaseModel):
paint: dict[str, dict | list | float | int | str] | None = None
layout: dict[str, dict | list | float | int | str] | None = None
attribution: str | None = None

View file

@ -14,11 +14,11 @@ class NotADataframeError(Exception):
pass
class Qml(Model):
class Qml(Model, table=True):
"""
Model for storing qml (QGis style)
"""
model_config = ConfigDict(protected_namespaces=())
model_config = ConfigDict(protected_namespaces=()) # type: ignore
__table_args__ = gisaf_map.table_args
class Admin:
@ -26,11 +26,11 @@ class Qml(Model):
flask_admin_model_view = 'QmlModelView'
model_name: str | None = Field(default=None, primary_key=True)
qml: str
attr: str
style: str
mapbox_paint: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True))
mapbox_layout: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True))
qml: str | None = None
attr: str | None = None
style: str | None = None
mapbox_paint: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
mapbox_layout: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
def __repr__(self):
return '<models.Qml {self.model_name:s}>'.format(self=self)

View file

@ -1,10 +1,4 @@
from typing import Any
from pydantic import BaseModel
from gisaf.models.geo_models_base import GeoModel, RawSurveyBaseModel, GeoPointSurveyModel
class MapLibreStyle(BaseModel):
...
class StoreNameOnly(BaseModel):
@ -12,6 +6,7 @@ class StoreNameOnly(BaseModel):
class Store(StoreNameOnly):
category: str | None = None
auto_import: bool
# base_gis_type: str
count: int | None = None
@ -39,7 +34,6 @@ class Store(StoreNameOnly):
#raw_model: GeoPointSurveyModel
#raw_model_store_name: str
status: str
store: str
style: str | None
symbol: str | None
title: str

View file

@ -73,11 +73,3 @@ class FeatureInfo(BaseModel):
files: list[Attachment] = []
images: list[Attachment] = []
externalRecordUrl: str | None = None
class MapboxPaint(BaseModel):
...
class MapboxLayout(BaseModel):
...