Uprava timezony u letu, error logging

This commit is contained in:
Michal Kváček
2023-08-09 22:46:20 +02:00
parent 57afde90c3
commit bc260a2a8b
8 changed files with 120 additions and 33 deletions
+2
View File
@@ -17,6 +17,8 @@ services:
- 8000:8000 - 8000:8000
volumes: volumes:
- .:/app - .:/app
environment:
TZ: "Europe/Prague"
nginx: nginx:
image: nginx:alpine image: nginx:alpine
+7
View File
@@ -0,0 +1,7 @@
def public_endpoint(func):
pass
def private_endpoint(func):
pass
+13
View File
@@ -0,0 +1,13 @@
from functools import wraps
from graphql import GraphQLError
def error_logging(func):
@wraps(func)
async def decorator(*args, **kwargs):
try:
return await func(*args, **kwargs)
except Exception as e:
raise GraphQLError(f"Not found")
return decorator
+80 -28
View File
@@ -1,10 +1,10 @@
from datetime import timedelta from datetime import timedelta
from typing import List, Optional, Annotated, TYPE_CHECKING from typing import List, Optional, Annotated, TYPE_CHECKING, Tuple
import strawberry import strawberry
from sqlalchemy import select from sqlalchemy import select
from strawberry.file_uploads import Upload from strawberry.file_uploads import Upload
from database import models from database import models
from decorators.error_logging import error_logging
from graphql_schema.dataloaders import copilots_dataloader from graphql_schema.dataloaders import copilots_dataloader
from graphql_schema.dataloaders.aircraft import aircraft_dataloader from graphql_schema.dataloaders.aircraft import aircraft_dataloader
from graphql_schema.dataloaders.airport import airport_dataloader from graphql_schema.dataloaders.airport import airport_dataloader
@@ -126,6 +126,7 @@ class FlightQueries:
return (await info.context.db.scalars(query)).all() return (await info.context.db.scalars(query)).all()
@strawberry.field @strawberry.field
@error_logging
async def flight(root, info, id: int, username: Optional[str] = None) -> Flight: async def flight(root, info, id: int, username: Optional[str] = None) -> Flight:
query = ( query = (
get_base_query(user_id=info.context.user_id, username=username, is_auth=bool(info.context.user_id)) get_base_query(user_id=info.context.user_id, username=username, is_auth=bool(info.context.user_id))
@@ -135,6 +136,21 @@ class FlightQueries:
return (await info.context.db.scalars(query)).one() return (await info.context.db.scalars(query)).one()
async def get_airports(db, takeoff_airport_id: int, landing_airport_id: int) -> Tuple[models.Airport, models.Airport]:
takeoff_airport = (await db.scalars(
select(models.Airport).filter(models.Airport.id == takeoff_airport_id)
)).one()
if takeoff_airport_id == landing_airport_id:
landing_airport = takeoff_airport
else:
landing_airport = (await db.scalars(
select(models.Airport).filter(models.Airport.id == landing_airport_id)
)).one()
return takeoff_airport, landing_airport
@strawberry.type @strawberry.type
class CreateFlightMutation: class CreateFlightMutation:
@strawberry_sqlalchemy_input(models.Flight, exclude_fields=[ @strawberry_sqlalchemy_input(models.Flight, exclude_fields=[
@@ -148,18 +164,20 @@ class CreateFlightMutation:
@strawberry.mutation @strawberry.mutation
async def create_flight(self, info, input: CreateFlightInput) -> Flight: async def create_flight(self, info, input: CreateFlightInput) -> Flight:
aircraft_id = await handle_aircraft_save(info.context.db, info.context.user_id, input.aircraft) db = info.context.db
takeoff_airport = (await info.context.db.scalars(select(models.Airport).filter(models.Airport.id == input.takeoff_airport.id))).one() aircraft_id = await handle_aircraft_save(db, info.context.user_id, input.aircraft)
if input.takeoff_airport.id == input.landing_airport.id:
landing_airport = takeoff_airport
else:
landing_airport = (await info.context.db.scalars(select(models.Airport).filter(models.Airport.id == input.landing_airport.id))).one()
weather_takeoff = await handle_weather_info(info.context.db, input.takeoff_datetime, takeoff_airport) data = input.to_dict()
weather_landing = await handle_weather_info(info.context.db, input.landing_datetime, landing_airport) data['takeoff_datetime'] = data['takeoff_datetime'].astimezone()
data['landing_datetime'] = data['landing_datetime'].astimezone()
return await models.Flight.create(info.context.db, data={ takeoff_airport, landing_airport = await get_airports(db, input.takeoff_airport.id, input.landing_airport.id)
**input.to_dict(),
weather_takeoff = await handle_weather_info(db, input.takeoff_datetime, takeoff_airport)
weather_landing = await handle_weather_info(db, input.landing_datetime, landing_airport)
return await models.Flight.create(db, data={
**data,
"weather_info_takeoff_id": weather_takeoff.id, "weather_info_takeoff_id": weather_takeoff.id,
"weather_info_landing_id": weather_landing.id, "weather_info_landing_id": weather_landing.id,
"takeoff_airport_id": takeoff_airport.id, "takeoff_airport_id": takeoff_airport.id,
@@ -185,13 +203,17 @@ class EditFlightMutation:
@strawberry.mutation @strawberry.mutation
async def edit_flight(self, info, id: int, input: EditFlightInput) -> Flight: async def edit_flight(self, info, id: int, input: EditFlightInput) -> Flight:
# TODO: umoznit editovat jen vlastni lety! db = info.context.db
user_id = info.context.user_id
flight = (await info.context.db.scalars( flight = (await db.scalars(
get_base_query(user_id=info.context.user_id, is_auth=bool(info.context.user_id)).filter(models.Flight.id == id) get_base_query(user_id=user_id, is_auth=bool(user_id))
.filter(models.Flight.id == id)
)).one() )).one()
data = input.to_dict() data = input.to_dict()
data['takeoff_datetime'] = data['takeoff_datetime'].astimezone()
data['landing_datetime'] = data['landing_datetime'].astimezone()
if input.gpx_track is not None: if input.gpx_track is not None:
# TODO: poresit validaci uploadovaneho souboru! # TODO: poresit validaci uploadovaneho souboru!
@@ -202,26 +224,56 @@ class EditFlightMutation:
data['gpx_track_filename'] = await handle_file_upload(input.gpx_track, path) data['gpx_track_filename'] = await handle_file_upload(input.gpx_track, path)
if input.takeoff_airport is not None: update_takeoff_weather = False
# TODO: stahnout nove pocasi na novem miste! Stejne tak pri zmene data/casu odletu update_landing_weather = False
data['takeoff_airport_id'] = input.takeoff_airport.id
if input.landing_airport is not None: if input.takeoff_airport is not None and input.takeoff_airport.id != flight.takeoff_airport_id:
# TODO: stahnout nove pocasi na novem miste! Stejne tak pri zmene data/casu priletu data['takeoff_airport_id'] = input.takeoff_airport.id
update_takeoff_weather = True
if input.landing_airport is not None and input.landing_airport.id != flight.landing_airport_id:
data['landing_airport_id'] = input.landing_airport.id data['landing_airport_id'] = input.landing_airport.id
update_landing_weather = True
takeoff_airport, landing_airport = await get_airports(
db,
takeoff_airport_id=input.takeoff_airport.id if input.takeoff_airport else flight.takeoff_airport_id,
landing_airport_id=input.landing_airport.id if input.landing_airport else flight.landing_airport_id,
)
if input.takeoff_datetime is not None and input.takeoff_datetime != flight.takeoff_datetime:
update_takeoff_weather = True
if input.landing_datetime is not None and input.landing_datetime != flight.landing_datetime:
update_landing_weather = True
if update_takeoff_weather:
weather = await handle_weather_info(db, input.takeoff_datetime, takeoff_airport)
# if flight.weather_info_takeoff_id:
# db.delete(flight.weather_info_takeoff)
data['weather_info_takeoff_id'] = weather.id
if update_landing_weather:
weather = await handle_weather_info(db, input.landing_datetime, landing_airport)
# if flight.weather_info_landing_id:
# db.delete(flight.weather_info_landing)
data['weather_info_landing_id'] = weather.id
# TODO: ^^ to pocasi smrdi zbytecne duplicitnim kodem, neslo by to nejak sjednotit?
if input.aircraft is not None: if input.aircraft is not None:
data['aircraft_id'] = await handle_aircraft_save(info.context.db, info.context.user_id, input.aircraft) data['aircraft_id'] = await handle_aircraft_save(db, user_id, input.aircraft)
flight = await models.Flight.update(info.context.db, id=id, data=data) data['copilot_id'] = await handle_copilot_edit(db, input.copilot, user_id) if input.copilot else None
flight = await models.Flight.update(db, id=id, data=data)
if input.track is not None: if input.track is not None:
await handle_track_edit(db=info.context.db, flight=flight, track=input.track, user_id=info.context.user_id) await handle_track_edit(db=db, flight=flight, track=input.track, user_id=user_id)
if input.copilot:
flight.copilot_id = await handle_copilot_edit(info.context.db, input.copilot, info.context.user_id)
else:
flight.copilot_id = None
return flight return flight
@@ -10,7 +10,7 @@ weather_api = Weather()
async def handle_weather_info(db: AsyncSession, date_time: datetime, airport: models.Airport) -> models.WeatherInfo: async def handle_weather_info(db: AsyncSession, date_time: datetime, airport: models.Airport) -> models.WeatherInfo:
weather = await weather_api.get_weather_for_hour(date_time, (airport.gps_latitude, airport.gps_longitude)) weather = await weather_api.get_weather_for_hour(date_time.astimezone(), (airport.gps_latitude, airport.gps_longitude))
return await models.WeatherInfo.create(db_session=db, data={ return await models.WeatherInfo.create(db_session=db, data={
"datetime": weather['datetime'], "datetime": weather['datetime'],
+7 -1
View File
@@ -1,11 +1,14 @@
from functools import wraps
from typing import Optional from typing import Optional
import strawberry import strawberry
from graphql import GraphQLError from graphql import GraphQLError
from passlib.hash import bcrypt from passlib.hash import bcrypt
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.exc import NoResultFound
from strawberry.file_uploads import Upload from strawberry.file_uploads import Upload
from database import models from database import models
from database.models import User from database.models import User
from decorators.error_logging import error_logging
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input
from upload_utils import handle_file_upload, delete_file from upload_utils import handle_file_upload, delete_file
@@ -32,8 +35,8 @@ class User:
@strawberry.type @strawberry.type
class UserQueries: class UserQueries:
@strawberry.field @strawberry.field
@error_logging
async def user(root, info, username: str) -> User: async def user(root, info, username: str) -> User:
print("username")
if len(username) == 0: if len(username) == 0:
raise GraphQLError("Username not set!") raise GraphQLError("Username not set!")
@@ -43,6 +46,9 @@ class UserQueries:
@strawberry.field @strawberry.field
async def logged_user(root, info) -> User: async def logged_user(root, info) -> User:
if not info.context.user_id:
raise GraphQLError("Not authenticated")
return (await info.context.db.scalars( return (await info.context.db.scalars(
select(models.User).filter_by(id=info.context.user_id) select(models.User).filter_by(id=info.context.user_id)
)).one() )).one()
+6
View File
@@ -1,11 +1,17 @@
import dataclasses import dataclasses
from typing import List, Optional
import strawberry import strawberry
from fastapi_jwt import JwtAuthorizationCredentials from fastapi_jwt import JwtAuthorizationCredentials
from fastapi_jwt.jwt import JwtAccessBearerCookie from fastapi_jwt.jwt import JwtAccessBearerCookie
from graphql import GraphQLError
from sqlalchemy.exc import NoResultFound
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from starlette.background import BackgroundTasks from starlette.background import BackgroundTasks
from strawberry.extensions import SchemaExtension from strawberry.extensions import SchemaExtension
from strawberry.fastapi import BaseContext from strawberry.fastapi import BaseContext
from strawberry.types import ExecutionContext
from .mutation import Mutation from .mutation import Mutation
from .query import Query from .query import Query
+1
View File
@@ -1,3 +1,4 @@
import time
from datetime import timedelta from datetime import timedelta
from fastapi import FastAPI, APIRouter, Depends, Security, HTTPException from fastapi import FastAPI, APIRouter, Depends, Security, HTTPException
from fastapi_jwt import JwtAuthorizationCredentials, JwtAccessBearerCookie, JwtRefreshBearerCookie from fastapi_jwt import JwtAuthorizationCredentials, JwtAccessBearerCookie, JwtRefreshBearerCookie