From dfb96e768e8480c81a8cb919a28e13f979c589db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kv=C3=A1=C4=8Dek?= Date: Sat, 20 Jan 2024 22:09:05 +0100 Subject: [PATCH] Aktualizace zavislosti, pridani debrief poznamek --- ...ght_debriefind_notes_field_39ebf5a1ab7e.py | 28 +++++++++++++++++++ requirements.txt | 24 ++++++++-------- src/database/models.py | 1 + src/endpoints/forgotten_password.py | 4 +++ src/endpoints/registration.py | 4 +-- src/external/gpx_parser.py | 1 - src/graphql_schema/entities/types/types.py | 26 ++++++++++++++++- src/main.py | 5 ++++ 8 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 alembic/versions/20240120-162200_add_flight_debriefind_notes_field_39ebf5a1ab7e.py create mode 100644 src/endpoints/forgotten_password.py diff --git a/alembic/versions/20240120-162200_add_flight_debriefind_notes_field_39ebf5a1ab7e.py b/alembic/versions/20240120-162200_add_flight_debriefind_notes_field_39ebf5a1ab7e.py new file mode 100644 index 0000000..8a11c12 --- /dev/null +++ b/alembic/versions/20240120-162200_add_flight_debriefind_notes_field_39ebf5a1ab7e.py @@ -0,0 +1,28 @@ +"""add flight.debriefind_notes field + +Revision ID: 39ebf5a1ab7e +Revises: 6648fb80dd0e +Create Date: 2024-01-20 16:22:00.487226 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '39ebf5a1ab7e' +down_revision = '6648fb80dd0e' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('flight', sa.Column('debriefing_notes', sa.Text(), server_default='', nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('flight', 'debriefing_notes') + # ### end Alembic commands ### diff --git a/requirements.txt b/requirements.txt index f95773c..319c3b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,15 @@ -fastapi==0.100.0 -fastapi-jwt==0.1.12 -strawberry-graphql[fastapi]==0.194.4 -uvicorn==0.22.0 -sqlalchemy[asyncio] >= 2.0.9 +fastapi==0.109.0 +fastapi-jwt==0.2.0 +strawberry-graphql[fastapi]==0.217.1 +uvicorn==0.26.0 +sqlalchemy[asyncio] == 2.0.25 aiomysql==0.2.0 -alembic==1.11.1 +alembic==1.13.1 passlib==1.7.4 -pydantic==1.10.11 # vysla uz 2.0, ale nejak mi to nefunguje +pydantic==2.5.3 sentry-sdk[fastapi] -pillow -exif -aiocache -aiohttp -lxml \ No newline at end of file +pillow==10.2.0 +exif==1.6.0 +aiocache==0.12.2 +aiohttp==3.9.1 +lxml==5.1.0 \ No newline at end of file diff --git a/src/database/models.py b/src/database/models.py index 501d3a8..942f1ef 100644 --- a/src/database/models.py +++ b/src/database/models.py @@ -276,6 +276,7 @@ class Flight(BaseModel): id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(128), nullable=False, server_default="") description: Mapped[str] = mapped_column(Text, nullable=False, server_default="") + debriefing_notes: Mapped[str] = mapped_column(Text, nullable=False, server_default="") url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="") event_id: Mapped[int] = mapped_column(Integer, ForeignKey("event.id"), nullable=True) title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True) diff --git a/src/endpoints/forgotten_password.py b/src/endpoints/forgotten_password.py new file mode 100644 index 0000000..db5891f --- /dev/null +++ b/src/endpoints/forgotten_password.py @@ -0,0 +1,4 @@ + +class ForgottenPasswordEndpoint(): + async def on_get(self): + pass \ No newline at end of file diff --git a/src/endpoints/registration.py b/src/endpoints/registration.py index b43358e..5dce9a4 100644 --- a/src/endpoints/registration.py +++ b/src/endpoints/registration.py @@ -2,7 +2,7 @@ import re from fastapi import HTTPException from sqlalchemy import select from typing import Optional -from pydantic import BaseModel, root_validator, Field +from pydantic import BaseModel, Field, model_validator from database.models import User from database.transaction import get_session from passlib.hash import bcrypt @@ -13,7 +13,7 @@ class RegistrationInput(BaseModel): name: Optional[str] password: str - @root_validator() + @model_validator(mode="before") def validate_email(cls, values): email = values.get("email") or "" diff --git a/src/external/gpx_parser.py b/src/external/gpx_parser.py index b351037..a475506 100644 --- a/src/external/gpx_parser.py +++ b/src/external/gpx_parser.py @@ -1,6 +1,5 @@ from datetime import datetime from typing import List, Dict - from aiocache import cached from lxml import etree from lxml.etree import _ElementTree diff --git a/src/graphql_schema/entities/types/types.py b/src/graphql_schema/entities/types/types.py index 449033b..c4f9beb 100644 --- a/src/graphql_schema/entities/types/types.py +++ b/src/graphql_schema/entities/types/types.py @@ -1,7 +1,11 @@ from __future__ import annotations from datetime import datetime -from typing import Optional, List +from typing import Optional, List, Any import strawberry +from graphql import GraphQLError +from strawberry.permission import PermissionExtension, BasePermission +from strawberry.types import Info + from database import models from decorators.endpoints import authenticated_user_only from external.gpx_parser import GPXParser @@ -92,8 +96,23 @@ class Photo: ) +class IsAuthenticated(BasePermission): + message = "User is not authenticated" + error_class = GraphQLError + error_extensions = {"code": "UNAUTHORIZED"} + + def has_permission(self, source: Any, info: Info, **kwargs) -> bool: + return bool(info.context.user_id) + + @strawberry_sqlalchemy_type(models.Flight) class Flight: + def __init__(self, **kwargs): + super().__init__() + + for key, value in kwargs.items(): + setattr(self, key, value) + async def load_gpx_track(root): if not root.gpx_track_filename: return None @@ -148,6 +167,11 @@ class Flight: resolver=lambda root: flight_duration_dataloader.load(root.id) ) + debriefing_notes: Optional[str] = strawberry.field( + permission_classes=[IsAuthenticated], + resolver=lambda root: root.debriefing_notes + ) + @strawberry_sqlalchemy_type(models.Copilot) class Copilot: diff --git a/src/main.py b/src/main.py index 6ef67ed..d58b232 100644 --- a/src/main.py +++ b/src/main.py @@ -12,6 +12,7 @@ from starlette.staticfiles import StaticFiles from strawberry.fastapi import GraphQLRouter from config import APP_SECRET_KEY, GRAPHIQL, APP_DEBUG, ALLOW_CORS_ORIGINS, SENTRY_DSN, REFRESH_TOKEN_VALIDITY_DAYS from database import models, async_session +from endpoints.forgotten_password import ForgottenPasswordEndpoint from endpoints.login import LoginEndpoint, LoginInput, RefreshEndpoint, LogoutEndpoint from endpoints.photo_editor_preview import PhotoEditorEndpoint from endpoints.registration import RegistrationInput, RegistrationEndpoint @@ -131,6 +132,10 @@ class App: refresh_token=self.refresh_security ).on_post(resp) + # @self.api_router.get("/forgotten-password") + # async def logout(resp: Response): + # return await ForgottenPasswordEndpoint().on_get(resp) + @self.api_router.get("/photo/editor-preview/{photo_id}") async def photo_editor_preview( photo_id: int,