From d2de5bab63dccfab70c50d9d9164a2b03e567508 Mon Sep 17 00:00:00 2001 From: Nik Sauer Date: Wed, 6 Nov 2024 10:58:58 +0100 Subject: [PATCH] changed decorator to get_or_create_station, updated database --- .../1d6aadaa77b1_initial_migration.py | 40 ++++++++ .../5516d2dd3e78_initial_migration.py | 30 ++++++ code/database.py | 2 +- code/routers/station.py | 92 +++---------------- code/utils.py | 62 ++++++++++++- 5 files changed, 143 insertions(+), 83 deletions(-) create mode 100644 code/alembic/versions/1d6aadaa77b1_initial_migration.py create mode 100644 code/alembic/versions/5516d2dd3e78_initial_migration.py diff --git a/code/alembic/versions/1d6aadaa77b1_initial_migration.py b/code/alembic/versions/1d6aadaa77b1_initial_migration.py new file mode 100644 index 0000000..38b733c --- /dev/null +++ b/code/alembic/versions/1d6aadaa77b1_initial_migration.py @@ -0,0 +1,40 @@ +"""Initial migration + +Revision ID: 1d6aadaa77b1 +Revises: 0ab739389abd +Create Date: 2024-11-06 10:57:16.506743 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '1d6aadaa77b1' +down_revision: Union[str, None] = '0ab739389abd' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('StationStatus', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('station_id', sa.Integer(), nullable=True), + sa.Column('timestamp', sa.DateTime(), nullable=True), + sa.Column('level', sa.Integer(), nullable=True), + sa.Column('message', sa.String(), nullable=True), + sa.ForeignKeyConstraint(['station_id'], ['stations.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_StationStatus_id'), 'StationStatus', ['id'], unique=False) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_StationStatus_id'), table_name='StationStatus') + op.drop_table('StationStatus') + # ### end Alembic commands ### diff --git a/code/alembic/versions/5516d2dd3e78_initial_migration.py b/code/alembic/versions/5516d2dd3e78_initial_migration.py new file mode 100644 index 0000000..4cf9b29 --- /dev/null +++ b/code/alembic/versions/5516d2dd3e78_initial_migration.py @@ -0,0 +1,30 @@ +"""Initial migration + +Revision ID: 5516d2dd3e78 +Revises: 1d6aadaa77b1 +Create Date: 2024-11-06 10:57:27.299949 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '5516d2dd3e78' +down_revision: Union[str, None] = '1d6aadaa77b1' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### diff --git a/code/database.py b/code/database.py index 2cc5bbb..d521382 100644 --- a/code/database.py +++ b/code/database.py @@ -26,4 +26,4 @@ def get_db(): try: yield db finally: - db.close() \ No newline at end of file + db.close() diff --git a/code/routers/station.py b/code/routers/station.py index 6b8c6aa..1d16ae8 100644 --- a/code/routers/station.py +++ b/code/routers/station.py @@ -10,80 +10,10 @@ from models import Station, Location, Measurement, Values, StationStatus from schemas import StationDataCreate, SensorsCreate, StationStatusCreate -from utils import get_or_create_location, download_csv +from utils import get_or_create_location, download_csv, get_or_create_station from services.hourly_average import calculate_hourly_average -def validate_station_info(func): - @wraps(func) - async def wrapper( - station: StationDataCreate, - *args, - db: Session = Depends(get_db), - **kwargs - ): - # Prüfen, ob die Station bereits existiert - db_station = db.query(Station).filter(Station.device == station.device).first() - - if db_station is None: - # Neue Station und neue Location anlegen - new_location = Location( - lat=station.location.lat, - lon=station.location.lon, - height=float(station.location.height) - ) - db.add(new_location) - db.commit() - db.refresh(new_location) - - # Neue Station anlegen und das source-Feld überprüfen (Standardwert ist 1) - db_station = Station( - device=station.device, - firmware=station.firmware, - apikey=station.apikey, - location_id=new_location.id, - last_active=station.time, - source=station.source if station.source is not None else 1 - ) - db.add(db_station) - db.commit() - db.refresh(db_station) - else: - # Station existiert, API-Schlüssel überprüfen - if db_station.apikey != station.apikey: - raise HTTPException( - status_code=401, - detail="Invalid API key" - ) - - updated = False - - # Überprüfen, ob Location aktualisiert werden muss - if db_station.location is None or ( - db_station.location.lat != station.location.lat or - db_station.location.lon != station.location.lon or - db_station.location.height != float(station.location.height) - ): - new_location = get_or_create_location(db, station.location.lat, station.location.lon, float(station.location.height)) - db_station.location_id = new_location.id - updated = True - - if db_station.firmware != station.firmware: - db_station.firmware = station.firmware - updated = True - - if updated: - db.commit() - - return await func( - station - *args, - db_station = db_station, - **kwargs - ) - return wrapper - - router = APIRouter() @@ -193,18 +123,18 @@ async def get_current_station_data( return Response(content=content, media_type=media_type) - @router.post("/status", tags=["station"]) -@validate_station_info async def create_station_status( station: StationDataCreate, status_list: list[StationStatusCreate], - - # von @validate_station_info - db_station: Station = Depends(lambda: None), db: Session = Depends(get_db) ): + db_station = get_or_create_station( + db=db, + station=station + ) + for status in status_list: db_status = StationStatus( station_id = db_station.id, @@ -220,16 +150,18 @@ async def create_station_status( @router.post("/data", tags=["station"]) -@validate_station_info async def create_station_data( station: StationDataCreate, sensors: SensorsCreate, background_tasks: BackgroundTasks, - - # von @validate_station_info - db_station: Station = Depends(lambda: None), db: Session = Depends(get_db) ): + + db_station = get_or_create_station( + db = db, + station = station + ) + # Empfangszeit des Requests erfassen time_received = datetime.now() diff --git a/code/utils.py b/code/utils.py index 4dd62c2..ab0f0d5 100644 --- a/code/utils.py +++ b/code/utils.py @@ -2,8 +2,10 @@ from geopy.geocoders import Nominatim from timezonefinder import TimezoneFinder from sqlalchemy.orm import Session -from models import City, Country, Location +from fastapi import HTTPException +from models import City, Country, Location, Station import logging +from schemas import StationDataCreate # Initialisiere TimezoneFinder tf = TimezoneFinder() @@ -104,4 +106,60 @@ def get_or_create_location(db: Session, lat: float, lon: float, height: float): db.rollback() raise - return location \ No newline at end of file + return location + +def get_or_create_station(db: Session, station: StationDataCreate): + # Prüfen, ob die Station bereits existiert + db_station = db.query(Station).filter(Station.device == station.device).first() + + if db_station is None: + # Neue Station und neue Location anlegen + new_location = Location( + lat=station.location.lat, + lon=station.location.lon, + height=float(station.location.height) + ) + db.add(new_location) + db.commit() + db.refresh(new_location) + + # Neue Station anlegen und das source-Feld überprüfen (Standardwert ist 1) + db_station = Station( + device=station.device, + firmware=station.firmware, + apikey=station.apikey, + location_id=new_location.id, + last_active=station.time, + source=station.source if station.source is not None else 1 + ) + db.add(db_station) + db.commit() + db.refresh(db_station) + else: + # Station existiert, API-Schlüssel überprüfen + if db_station.apikey != station.apikey: + raise HTTPException( + status_code=401, + detail="Invalid API key" + ) + + updated = False + + # Überprüfen, ob Location aktualisiert werden muss + if db_station.location is None or ( + db_station.location.lat != station.location.lat or + db_station.location.lon != station.location.lon or + db_station.location.height != float(station.location.height) + ): + new_location = get_or_create_location(db, station.location.lat, station.location.lon, float(station.location.height)) + db_station.location_id = new_location.id + updated = True + + if db_station.firmware != station.firmware: + db_station.firmware = station.firmware + updated = True + + if updated: + db.commit() + + return db_station