diff --git a/toardb/stationmeta/crud.py b/toardb/stationmeta/crud.py index 0a746428ace18ff26cc0b27f7575de7fb5cb98e1..a2842f19b5db5b2e0b0590efc49a0fcbc9186117 100644 --- a/toardb/stationmeta/crud.py +++ b/toardb/stationmeta/crud.py @@ -12,7 +12,8 @@ from sqlalchemy.dialects.postgresql import JSONB, ARRAY from fastapi import File, UploadFile from fastapi.responses import JSONResponse from . import models -from .models import StationmetaCore, stationmeta_core_stationmeta_roles_table, stationmeta_core_stationmeta_annotations_table, \ +from .models import StationmetaCore, StationmetaChangelog, stationmeta_core_stationmeta_roles_table, \ + stationmeta_core_stationmeta_annotations_table, \ CZ_enum, CV_enum, ST_enum, TA_enum from toardb.generic.models import RS_enum, RC_enum from .schemas import get_coordinates_from_geom, get_geom_from_coordinates, StationmetaCreate, StationmetaPatch, Coordinates @@ -174,7 +175,7 @@ def create_stationmeta(db: Session, stationmeta: StationmetaCreate): db_stationmeta.coordinates = tmp_coordinates return db_stationmeta -def patch_stationmeta(db: Session, station_id: int, stationmeta: StationmetaPatch): +def patch_stationmeta(db: Session, description: str, station_id: int, stationmeta: StationmetaPatch): stationmeta_dict = stationmeta.dict() roles_data = stationmeta_dict.pop('roles', None) annotations_data = stationmeta_dict.pop('annotations', None) @@ -183,6 +184,8 @@ def patch_stationmeta(db: Session, station_id: int, stationmeta: StationmetaPatc aux_urls_data = stationmeta_dict.pop('aux_urls', None) globalmeta_data = stationmeta_dict.pop('globalmeta', None) globalservice_data = stationmeta_dict.pop('globalservice', None) + # prepare changelog entry/entries + db_changelog = StationmetaChangelog(description=description, station_id=station_id, author_id=1, type_of_change=1) # there's a mismatch with coordinates --> how to automatically switch back and forth?! # ==> the following two commands are not working # ==> workaround @@ -194,7 +197,9 @@ def patch_stationmeta(db: Session, station_id: int, stationmeta: StationmetaPatc db_stationmeta.coordinates = get_geom_from_coordinates(db_stationmeta.coordinates) for k, v in stationmeta_dict.items(): if v is not None: + db_changelog.old_value=str(getattr(db_stationmeta,k)) setattr(db_stationmeta,k,stationmeta_dict[k]) + db_changelog.new_value=str(getattr(db_stationmeta,k)) result = db.commit() db.refresh(db_stationmeta) # store roles and update association table @@ -269,6 +274,9 @@ def patch_stationmeta(db: Session, station_id: int, stationmeta: StationmetaPatc db.add(db_globalservice) db.commit() db.refresh(db_globalservice) + # add patch to changelog table + db.add(db_changelog) + db.commit() # there's a mismatch with coordinates --> how to automatically switch back and forth?! db_stationmeta.coordinates = tmp_coordinates return db_stationmeta diff --git a/toardb/stationmeta/models_changelog.py b/toardb/stationmeta/models_changelog.py index 329837057995fda916bcb11f3921d4924344ba73..3848c9756dab4c00db06d7e2aa1a9829da4c6f80 100644 --- a/toardb/stationmeta/models_changelog.py +++ b/toardb/stationmeta/models_changelog.py @@ -3,7 +3,7 @@ class StationmetaChangelog(Base) ================================ """ -from sqlalchemy import Column, DateTime, BigInteger, ForeignKey, String, \ +from sqlalchemy import Column, DateTime, BigInteger, ForeignKey, String, text, \ Text, CheckConstraint, Table, Sequence from sqlalchemy.orm import relationship from .models_core import StationmetaCore @@ -19,7 +19,7 @@ class StationmetaChangelog(Base): +================+==========================+===========+==========+========================================================+ | id | bigint | | not null | nextval('stationmeta_changelog_id_seq'::regclass) | +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ - | datetime | timestamp with time zone | | not null | | + | datetime | timestamp with time zone | | not null | now() | +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ | station_id | bigint | | not null | | +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ @@ -43,17 +43,17 @@ class StationmetaChangelog(Base): __tablename__ = 'stationmeta_changelog' id = Column(BigInteger, STATIONMETA_CHANGELOG_ID_SEQ, primary_key=True, server_default=STATIONMETA_CHANGELOG_ID_SEQ.next_value()) - datetime = Column(DateTime(True), nullable=False) + datetime = Column(DateTime(True), nullable=False, server_default=text("now()")) description = Column(Text, nullable=False) old_value = Column(String(256), nullable=False) new_value = Column(String(256), nullable=False) # do not use string declaration here (not working for pytest) # use the explicit class name here, # see: https://groups.google.com/forum/#!topic/sqlalchemy/YjGhE4d6K4U - station_id = Column(ForeignKey(StationmetaCore.id), nullable=False) + station_id = Column(ForeignKey(StationmetaCore.id, deferrable=True, initially='DEFERRED'), nullable=False) author_id = Column(ForeignKey(AuthUser.id), nullable=False) # still to check for some pytest solution for controlled vocabulary - type_of_change = Column(ForeignKey('cl_Vocabulary.enum_val'), nullable=False) + type_of_change = Column(ForeignKey('cl_vocabulary.enum_val'), nullable=False) author = relationship('AuthUser') station = relationship('StationmetaCore') diff --git a/toardb/stationmeta/models_core.py b/toardb/stationmeta/models_core.py index 7e263307fa7112cabdefec76dcc2b2254508880a..92262f5af3f41bd8caca2ff645c18cbe77eab832 100644 --- a/toardb/stationmeta/models_core.py +++ b/toardb/stationmeta/models_core.py @@ -87,6 +87,7 @@ class StationmetaCore_WithoutCoords(Base): aux_urls = relationship('StationmetaAuxUrl', back_populates='station') globalmeta = relationship('StationmetaGlobal', uselist=False, back_populates='station') globalservice = relationship('StationmetaGlobalService', uselist=False, back_populates='station') + changelog = relationship('StationmetaChangelog', back_populates='station') # for nested view timeseries = relationship("Timeseries", back_populates="station") diff --git a/toardb/stationmeta/schemas.py b/toardb/stationmeta/schemas.py index 67266c6a81cd38427c8934c326cd2a24c7feddfb..520d3fcd48ac94ee61206aa29b49859ae9990082 100644 --- a/toardb/stationmeta/schemas.py +++ b/toardb/stationmeta/schemas.py @@ -448,6 +448,27 @@ class StationmetaRole(StationmetaRoleBase): class Config: orm_mode = True + +# ======== StationmetaChangelog ========= + +class StationmetaChangelogBase(BaseModel): + id: int + datetime: dt.datetime + description: str + old_value: str + new_value: str + station_id: int + author_id: int + type_of_change: int + + +class StationmetaChangelog(StationmetaChangelogBase): + id: int + + class Config: + orm_mode = True + + # ======== for nested view/upload ========= class StationmetaBase(StationmetaCoreBase): @@ -457,6 +478,7 @@ class StationmetaBase(StationmetaCoreBase): aux_docs: List[StationmetaAuxDoc] = None aux_urls: List[StationmetaAuxUrl] = None globalmeta: StationmetaGlobal = None + changelog: List[StationmetaChangelog] = None class Config: orm_mode = True diff --git a/toardb/stationmeta/stationmeta.py b/toardb/stationmeta/stationmeta.py index 240a3a9ad1492e6421f6c8c2ad41d87b1132a104..ddc5261f08d4c8da2f843e436c61e332088f221a 100644 --- a/toardb/stationmeta/stationmeta.py +++ b/toardb/stationmeta/stationmeta.py @@ -60,11 +60,11 @@ def create_stationmeta_core(stationmeta: schemas.StationmetaCreate = Body(..., e return crud.create_stationmeta(db=db, stationmeta=stationmeta) @router.patch('/stationmeta/{station_code}', response_model=schemas.StationmetaPatch) -def patch_stationmeta_core(station_code: str, stationmeta: schemas.StationmetaPatch = Body(..., embed = True), db: Session = Depends(get_db)): +def patch_stationmeta_core(station_code: str, description: str, stationmeta: schemas.StationmetaPatch = Body(..., embed = True), db: Session = Depends(get_db)): db_stationmeta = crud.get_stationmeta(db, station_code=station_code) if db_stationmeta is None: raise HTTPException(status_code=404, detail="Station for patching not found.") - return crud.patch_stationmeta(db=db, station_id=db_stationmeta.id, stationmeta=stationmeta) + return crud.patch_stationmeta(db=db, description=description, station_id=db_stationmeta.id, stationmeta=stationmeta) @router.patch('/stationmeta/delete_field/{station_code}', response_model=schemas.StationmetaPatch) def patch_stationmeta_core(station_code: str, field: str, db: Session = Depends(get_db)): diff --git a/toardb/timeseries/models_changelog.py b/toardb/timeseries/models_changelog.py index c4ac170754c34ec827c7f8dcceaae3ee7a5fe38e..3eb58ff9851621afe0399534cb0f3da994afb5c1 100644 --- a/toardb/timeseries/models_changelog.py +++ b/toardb/timeseries/models_changelog.py @@ -3,7 +3,7 @@ class TimeseriesChangelog(Base) =============================== """ -from sqlalchemy import Column, DateTime, ForeignKey, BigInteger, String, CHAR, \ +from sqlalchemy import Column, DateTime, ForeignKey, BigInteger, String, CHAR, text, \ Text, Table, Sequence from sqlalchemy.orm import relationship from .models_core import Timeseries @@ -19,7 +19,7 @@ class TimeseriesChangelog(Base): +================+==========================+===========+==========+==================================================+ | id | bigint | | not null | nextval('timeseries_changelog_id_seq'::regclass) | +----------------+--------------------------+-----------+----------+--------------------------------------------------+ - | datetime | timestamp with time zone | | not null | | + | datetime | timestamp with time zone | | not null | now() | +----------------+--------------------------+-----------+----------+--------------------------------------------------+ | timeseries_id | bigint | | not null | | +----------------+--------------------------+-----------+----------+--------------------------------------------------+ @@ -50,7 +50,7 @@ class TimeseriesChangelog(Base): __tablename__ = 'timeseries_changelog' id = Column(BigInteger, TIMESERIES_CHANGELOG_ID_SEQ, primary_key=True, server_default=TIMESERIES_CHANGELOG_ID_SEQ.next_value()) - datetime = Column(DateTime(True), nullable=False) + datetime = Column(DateTime(True), nullable=False, server_default=text("now()")) description = Column(Text, nullable=False) old_value = Column(String(256), nullable=False) new_value = Column(String(256), nullable=False)