Fix config for ws devices
Cleanups
This commit is contained in:
parent
50b4dff145
commit
41e92fad57
2 changed files with 135 additions and 97 deletions
|
@ -3,55 +3,63 @@ import logging
|
|||
from pathlib import Path
|
||||
from typing import Any, Type, Tuple
|
||||
|
||||
from pydantic_settings import (BaseSettings,
|
||||
PydanticBaseSettingsSource,
|
||||
SettingsConfigDict)
|
||||
#from pydantic import ConfigDict
|
||||
from pydantic_settings import (
|
||||
BaseSettings,
|
||||
PydanticBaseSettingsSource,
|
||||
SettingsConfigDict,
|
||||
)
|
||||
|
||||
# from pydantic import ConfigDict
|
||||
from pydantic.v1.utils import deep_update
|
||||
from yaml import safe_load
|
||||
|
||||
from gisaf._version import __version__
|
||||
#from sqlalchemy.ext.asyncio.engine import AsyncEngine
|
||||
#from sqlalchemy.orm.session import sessionmaker
|
||||
# from sqlalchemy.ext.asyncio.engine import AsyncEngine
|
||||
# from sqlalchemy.orm.session import sessionmaker
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
ENV = environ.get('env', 'prod')
|
||||
ENV = environ.get("env", "prod")
|
||||
|
||||
config_files = [
|
||||
Path(Path.cwd().root) / 'etc' / 'gisaf' / ENV,
|
||||
Path.home() / '.local' / 'gisaf' / ENV
|
||||
Path(Path.cwd().root) / "etc" / "gisaf" / ENV,
|
||||
Path.home() / ".local" / "gisaf" / ENV,
|
||||
]
|
||||
|
||||
|
||||
class DashboardHome(BaseSettings):
|
||||
title: str = 'Gisaf - home/dashboards'
|
||||
content_file: str = '/etc/gisaf/dashboard_home_content.html'
|
||||
footer_file: str = '/etc/gisaf/dashboard_home_footer.html'
|
||||
title: str = "Gisaf - home/dashboards"
|
||||
content_file: str = "/etc/gisaf/dashboard_home_content.html"
|
||||
footer_file: str = "/etc/gisaf/dashboard_home_footer.html"
|
||||
|
||||
|
||||
class GisafConfig(BaseSettings):
|
||||
title: str = 'Gisaf'
|
||||
windowTitle: str = 'Gisaf'
|
||||
debugLevel: str = 'INFO'
|
||||
title: str = "Gisaf"
|
||||
windowTitle: str = "Gisaf"
|
||||
debugLevel: str = "INFO"
|
||||
dashboard_home: DashboardHome = DashboardHome()
|
||||
redirect: str = ''
|
||||
redirect: str = ""
|
||||
use_pretty_errors: bool = False
|
||||
|
||||
|
||||
class SpatialSysRef(BaseSettings):
|
||||
author: str = 'AVSM'
|
||||
ellps: str = 'WGS84'
|
||||
author: str = "AVSM"
|
||||
ellps: str = "WGS84"
|
||||
k: int = 1
|
||||
lat_0: float = 12.01605433
|
||||
lon_0: float = 79.80998934
|
||||
no_defs: bool = True
|
||||
proj: str = 'tmerc'
|
||||
towgs84: str = '0,0,0,0,0,0,0'
|
||||
units: str = 'm'
|
||||
proj: str = "tmerc"
|
||||
towgs84: str = "0,0,0,0,0,0,0"
|
||||
units: str = "m"
|
||||
x_0: float = 370455.630
|
||||
y_0: float = 1328608.994
|
||||
|
||||
|
||||
class RawSurvey(BaseSettings):
|
||||
spatial_sys_ref: SpatialSysRef = SpatialSysRef()
|
||||
srid: int = 910001
|
||||
|
||||
|
||||
class Geo(BaseSettings):
|
||||
raw_survey: RawSurvey = RawSurvey()
|
||||
simplify_geom_factor: int = 10000000
|
||||
|
@ -59,43 +67,50 @@ class Geo(BaseSettings):
|
|||
srid: int = 4326
|
||||
srid_for_proj: int = 32644
|
||||
|
||||
|
||||
# class Flask(BaseSettings):
|
||||
# secret_key: str
|
||||
# debug: int
|
||||
|
||||
|
||||
class MQTT(BaseSettings):
|
||||
broker: str = 'localhost'
|
||||
broker: str = "localhost"
|
||||
port: int = 1883
|
||||
|
||||
|
||||
class GisafLive(BaseSettings):
|
||||
hostname: str = 'localhost'
|
||||
hostname: str = "localhost"
|
||||
port: int = 80
|
||||
scheme: str = 'http'
|
||||
redis: str = 'redis://localhost'
|
||||
scheme: str = "http"
|
||||
redis: str = "redis://localhost"
|
||||
mqtt: MQTT = MQTT()
|
||||
|
||||
|
||||
class DefaultSurvey(BaseSettings):
|
||||
surveyor_id: int = 1
|
||||
equipment_id: int = 1
|
||||
|
||||
|
||||
class Survey(BaseSettings):
|
||||
# model_config = ConfigDict(extra='ignore')
|
||||
db_schema_raw: str = 'raw_survey'
|
||||
db_schema: str = 'survey'
|
||||
db_schema_raw: str = "raw_survey"
|
||||
db_schema: str = "survey"
|
||||
default: DefaultSurvey = DefaultSurvey()
|
||||
|
||||
|
||||
class Crypto(BaseSettings):
|
||||
secret: str = 'Gisaf big secret'
|
||||
algorithm: str = 'HS256'
|
||||
secret: str = "Gisaf big secret"
|
||||
algorithm: str = "HS256"
|
||||
expire: float = 21600
|
||||
|
||||
|
||||
class DB(BaseSettings):
|
||||
# uri: str
|
||||
host: str = 'localhost'
|
||||
host: str = "localhost"
|
||||
port: int = 5432
|
||||
user: str = 'gisaf'
|
||||
db: str = 'gisaf'
|
||||
password: str = 'secret'
|
||||
user: str = "gisaf"
|
||||
db: str = "gisaf"
|
||||
password: str = "secret"
|
||||
debug: bool = False
|
||||
info: bool = True
|
||||
pool_size: int = 10
|
||||
|
@ -103,41 +118,46 @@ class DB(BaseSettings):
|
|||
echo: bool = False
|
||||
|
||||
def get_sqla_url(self):
|
||||
return f'postgresql+asyncpg://{self.user}:{self.password}@{self.host}:{self.port}/{self.db}'
|
||||
return f"postgresql+asyncpg://{self.user}:{self.password}@{self.host}:{self.port}/{self.db}"
|
||||
|
||||
def get_pg_url(self):
|
||||
return f'postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.db}'
|
||||
return f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.db}"
|
||||
|
||||
|
||||
class Log(BaseSettings):
|
||||
level: str = 'WARNING'
|
||||
level: str = "WARNING"
|
||||
|
||||
|
||||
class OGCAPILicense(BaseSettings):
|
||||
name: str = 'CC-BY 4.0 license'
|
||||
url: str = 'https://creativecommons.org/licenses/by/4.0/'
|
||||
name: str = "CC-BY 4.0 license"
|
||||
url: str = "https://creativecommons.org/licenses/by/4.0/"
|
||||
|
||||
|
||||
class OGCAPIProvider(BaseSettings):
|
||||
name: str = 'Organization Name'
|
||||
url: str = 'https://pygeoapi.io'
|
||||
name: str = "Organization Name"
|
||||
url: str = "https://pygeoapi.io"
|
||||
|
||||
|
||||
class OGCAPIServerContact(BaseSettings):
|
||||
name: str = 'Lastname, Firstname'
|
||||
position: str = 'Position Title'
|
||||
address: str = 'Mailing Address'
|
||||
city: str = 'City'
|
||||
stateorprovince: str = 'Administrative Area'
|
||||
name: str = "Lastname, Firstname"
|
||||
position: str = "Position Title"
|
||||
address: str = "Mailing Address"
|
||||
city: str = "City"
|
||||
stateorprovince: str = "Administrative Area"
|
||||
postalcode: int = 0
|
||||
country: str = 'Country'
|
||||
email: str = 'you@example.org'
|
||||
country: str = "Country"
|
||||
email: str = "you@example.org"
|
||||
url: str | None = None
|
||||
|
||||
|
||||
class OGCAPIIdentification(BaseSettings):
|
||||
title: str = 'pygeoapi default instance'
|
||||
description: str = 'pygeoapi provides an API to geospatial data'
|
||||
keywords: list[str] = ['geospatial', 'data', 'api']
|
||||
keywords_type: str = 'theme'
|
||||
terms_of_service: str = 'https://creativecommons.org/licenses/by/4.0/'
|
||||
url: str = 'http://example.org'
|
||||
title: str = "pygeoapi default instance"
|
||||
description: str = "pygeoapi provides an API to geospatial data"
|
||||
keywords: list[str] = ["geospatial", "data", "api"]
|
||||
keywords_type: str = "theme"
|
||||
terms_of_service: str = "https://creativecommons.org/licenses/by/4.0/"
|
||||
url: str = "http://example.org"
|
||||
|
||||
|
||||
class OGCAPIMetadata(BaseSettings):
|
||||
identification: OGCAPIIdentification = OGCAPIIdentification()
|
||||
|
@ -145,38 +165,44 @@ class OGCAPIMetadata(BaseSettings):
|
|||
provider: OGCAPIProvider = OGCAPIProvider()
|
||||
contact: OGCAPIServerContact = OGCAPIServerContact()
|
||||
|
||||
|
||||
class ServerBind(BaseSettings):
|
||||
host: str = '0.0.0.0'
|
||||
host: str = "0.0.0.0"
|
||||
port: int = 5000
|
||||
|
||||
|
||||
class OGCAPIServerMap(BaseSettings):
|
||||
url: str = 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png'
|
||||
attribution: str = '''<a href="https://wikimediafoundation.org/wiki/Maps_Terms_of_Use">Wikimedia maps</a> | Map data © <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'''
|
||||
url: str = "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png"
|
||||
attribution: str = """<a href="https://wikimediafoundation.org/wiki/Maps_Terms_of_Use">Wikimedia maps</a> | Map data © <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>"""
|
||||
|
||||
|
||||
class OGCAPIServer(BaseSettings):
|
||||
bind: ServerBind = ServerBind()
|
||||
url: str = 'https://example.org/ogcapi'
|
||||
mimetype: str = 'application/json; charset=UTF-8'
|
||||
encoding: str = 'utf-8'
|
||||
language: str = 'en-US'
|
||||
url: str = "https://example.org/ogcapi"
|
||||
mimetype: str = "application/json; charset=UTF-8"
|
||||
encoding: str = "utf-8"
|
||||
language: str = "en-US"
|
||||
pretty_print: bool = False
|
||||
limit: int = 1000
|
||||
map: OGCAPIServerMap = OGCAPIServerMap()
|
||||
|
||||
|
||||
class OGCAPI(BaseSettings):
|
||||
base_url: str = 'http://example.org/ogcapi'
|
||||
base_url: str = "http://example.org/ogcapi"
|
||||
bbox: list[float] = [-180, -90, 180, 90]
|
||||
log: Log = Log()
|
||||
metadata: OGCAPIMetadata = OGCAPIMetadata()
|
||||
server: OGCAPIServer = OGCAPIServer()
|
||||
|
||||
|
||||
class TileServer(BaseSettings):
|
||||
baseDir: str = '/path/to/mbtiles_files_dir'
|
||||
useRequestUrl: bool = False
|
||||
spriteBaseDir: str = '/path/to/mbtiles_sprites_dir'
|
||||
spriteUrl: str = '/tiles/sprite/sprite'
|
||||
spriteBaseUrl: str = 'https://gisaf.example.org'
|
||||
openMapTilesKey: str | None = None
|
||||
baseDir: str = "/path/to/mbtiles_files_dir"
|
||||
useRequestUrl: bool = False
|
||||
spriteBaseDir: str = "/path/to/mbtiles_sprites_dir"
|
||||
spriteUrl: str = "/tiles/sprite/sprite"
|
||||
spriteBaseUrl: str = "https://gisaf.example.org"
|
||||
openMapTilesKey: str | None = None
|
||||
|
||||
|
||||
class Map(BaseSettings):
|
||||
tileServer: TileServer = TileServer()
|
||||
|
@ -185,46 +211,56 @@ class Map(BaseSettings):
|
|||
lat: float = 12.0000
|
||||
lng: float = 79.8106
|
||||
bearing: float = 0
|
||||
style: str = 'OSM (vector)'
|
||||
style: str = "OSM (vector)"
|
||||
opacity: float = 1
|
||||
attribution: str = ''
|
||||
status: list[str] = ['E', 'F', 'D']
|
||||
defaultStatus: list[str] = ['E'] # FIXME: should be str
|
||||
tagKeys: list[str] = ['source']
|
||||
attribution: str = ""
|
||||
status: list[str] = ["E", "F", "D"]
|
||||
defaultStatus: list[str] = ["E"] # FIXME: should be str
|
||||
tagKeys: list[str] = ["source"]
|
||||
|
||||
|
||||
class Measures(BaseSettings):
|
||||
defaultStore: str | None = None
|
||||
|
||||
|
||||
class BasketDefault(BaseSettings):
|
||||
surveyor: str = 'Default surveyor'
|
||||
equipment: str = 'Default equipment'
|
||||
project: str = 'Default project'
|
||||
status: str = 'E'
|
||||
surveyor: str = "Default surveyor"
|
||||
equipment: str = "Default equipment"
|
||||
project: str = "Default project"
|
||||
status: str = "E"
|
||||
store: str | None = None
|
||||
|
||||
|
||||
# class BasketOldDef(BaseSettings):
|
||||
# base_dir: str
|
||||
|
||||
|
||||
class Basket(BaseSettings):
|
||||
base_dir: str = '/var/local/gisaf/baskets'
|
||||
base_dir: str = "/var/local/gisaf/baskets"
|
||||
default: BasketDefault = BasketDefault()
|
||||
|
||||
|
||||
class Plot(BaseSettings):
|
||||
maxDataSize: int = 10000
|
||||
|
||||
|
||||
class Dashboard(BaseSettings):
|
||||
base_source_url: str = 'http://url.to.jupyter/lab/tree/'
|
||||
base_storage_dir: str = '/var/lib/share/gisaf/dashboard'
|
||||
base_storage_url: str = '/dashboard-attachment/'
|
||||
base_source_url: str = "http://url.to.jupyter/lab/tree/"
|
||||
base_storage_dir: str = "/var/lib/share/gisaf/dashboard"
|
||||
base_storage_url: str = "/dashboard-attachment/"
|
||||
|
||||
|
||||
class Widgets(BaseSettings):
|
||||
footer: str = """Generated by <span class='link' onclick="window.open('https://redmine.auroville.org.in/projects/gisaf/')">Gisaf</span>"""
|
||||
|
||||
|
||||
class Admin(BaseSettings):
|
||||
basket: Basket = Basket()
|
||||
|
||||
|
||||
class Attachments(BaseSettings):
|
||||
base_dir: str = '/var/local/gisaf/attachments'
|
||||
base_dir: str = "/var/local/gisaf/attachments"
|
||||
|
||||
|
||||
class Job(BaseSettings):
|
||||
id: str
|
||||
|
@ -233,20 +269,23 @@ class Job(BaseSettings):
|
|||
minutes: int | None = 0
|
||||
seconds: int | None = 0
|
||||
|
||||
|
||||
class Crs(BaseSettings):
|
||||
'''
|
||||
"""
|
||||
Handy definitions for crs-es
|
||||
'''
|
||||
"""
|
||||
|
||||
db: str
|
||||
geojson: str
|
||||
for_proj: str
|
||||
survey: str
|
||||
web_mercator: str
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
#env_prefix='gisaf_',
|
||||
env_nested_delimiter='__',
|
||||
# env_prefix='gisaf_',
|
||||
env_nested_delimiter="__",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -258,7 +297,7 @@ class Config(BaseSettings):
|
|||
dotenv_settings: PydanticBaseSettingsSource,
|
||||
file_secret_settings: PydanticBaseSettingsSource,
|
||||
) -> Tuple[PydanticBaseSettingsSource, ...]:
|
||||
return env_settings, init_settings, file_secret_settings, config_file_settings # type: ignore
|
||||
return env_settings, init_settings, file_secret_settings, config_file_settings # type: ignore
|
||||
|
||||
# def __init__(self, **kwargs):
|
||||
# super().__init__(**kwargs)
|
||||
|
@ -289,19 +328,20 @@ class Config(BaseSettings):
|
|||
plugins: dict[str, dict[str, Any]] = {}
|
||||
survey: Survey = Survey()
|
||||
version: str = __version__
|
||||
weather_station: dict[str, list[dict[str, Any]] | dict[str, Any]] = {}
|
||||
weather_station: dict[str, dict[str, Any]] = {}
|
||||
widgets: Widgets = Widgets()
|
||||
|
||||
@property
|
||||
def crs(self) -> Crs:
|
||||
return Crs(
|
||||
db=f'epsg:{self.geo.srid}',
|
||||
geojson=f'epsg:{self.geo.srid}',
|
||||
for_proj=f'epsg:{self.geo.srid_for_proj}',
|
||||
survey=f'epsg:{self.geo.raw_survey.srid}',
|
||||
web_mercator='epsg:3857',
|
||||
db=f"epsg:{self.geo.srid}",
|
||||
geojson=f"epsg:{self.geo.srid}",
|
||||
for_proj=f"epsg:{self.geo.srid_for_proj}",
|
||||
survey=f"epsg:{self.geo.raw_survey.srid}",
|
||||
web_mercator="epsg:3857",
|
||||
)
|
||||
|
||||
|
||||
def config_file_settings() -> dict[str, Any]:
|
||||
config: dict[str, Any] = {}
|
||||
for p in config_files:
|
||||
|
@ -322,9 +362,7 @@ def load_yaml(path: Path) -> dict[str, Any]:
|
|||
with Path(path).open("r") as f:
|
||||
config = safe_load(f)
|
||||
if not isinstance(config, dict):
|
||||
raise TypeError(
|
||||
f"Config file has no top-level mapping: {path}"
|
||||
)
|
||||
raise TypeError(f"Config file has no top-level mapping: {path}")
|
||||
return config
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import asyncio
|
|||
from json import dumps
|
||||
from datetime import datetime
|
||||
from importlib.metadata import entry_points
|
||||
from typing import Any, Mapping, List
|
||||
from typing import Any, List
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue