diff --git a/calendar_backend/__main__.py b/calendar_backend/__main__.py index 0e4f8fdd..b83b5c92 100644 --- a/calendar_backend/__main__.py +++ b/calendar_backend/__main__.py @@ -4,6 +4,7 @@ from calendar_backend.routes import app + logging.basicConfig( filename=f'logger_{__name__}.log', level=logging.DEBUG, diff --git a/calendar_backend/google_engine/__init__.py b/calendar_backend/google_engine/__init__.py index 38c15b10..00f48d51 100644 --- a/calendar_backend/google_engine/__init__.py +++ b/calendar_backend/google_engine/__init__.py @@ -1,5 +1,6 @@ -from .service import get_calendar_service_from_token from .api_utils import create_calendar_with_timetable +from .service import get_calendar_service_from_token + __all__ = [ "get_calendar_service_from_token", diff --git a/calendar_backend/google_engine/api_utils.py b/calendar_backend/google_engine/api_utils.py index 90eac608..81f099d1 100644 --- a/calendar_backend/google_engine/api_utils.py +++ b/calendar_backend/google_engine/api_utils.py @@ -4,9 +4,11 @@ from sqlalchemy.orm import Session from calendar_backend.settings import get_settings + from .event import Event from .event_from_db import create_google_events_from_db + settings = get_settings() logger = logging.getLogger(__name__) diff --git a/calendar_backend/google_engine/event.py b/calendar_backend/google_engine/event.py index c21ecae5..a7a07f5c 100644 --- a/calendar_backend/google_engine/event.py +++ b/calendar_backend/google_engine/event.py @@ -1,6 +1,7 @@ -from calendar_backend.methods import utils from pydantic import BaseModel +from calendar_backend.methods import utils + class Event(BaseModel): summary: str diff --git a/calendar_backend/google_engine/event_from_db.py b/calendar_backend/google_engine/event_from_db.py index 28acf7af..fd6ffb54 100644 --- a/calendar_backend/google_engine/event_from_db.py +++ b/calendar_backend/google_engine/event_from_db.py @@ -3,11 +3,13 @@ from sqlalchemy.orm import Session -from calendar_backend.settings import get_settings from calendar_backend.methods.utils import get_lessons_by_group_from_date from calendar_backend.models import Event, Group +from calendar_backend.settings import get_settings + from .event import create_google_calendar_event + settings = get_settings() logger = logging.getLogger(__name__) diff --git a/calendar_backend/google_engine/service.py b/calendar_backend/google_engine/service.py index 3f2b4e6a..bc122f55 100644 --- a/calendar_backend/google_engine/service.py +++ b/calendar_backend/google_engine/service.py @@ -2,12 +2,13 @@ import google.oauth2.credentials import googleapiclient.discovery -from sqlalchemy.exc import NoResultFound +from fastapi_sqlalchemy import db from googleapiclient.discovery import build +from pydantic import Json +from sqlalchemy.exc import NoResultFound + from calendar_backend.models import Credentials from calendar_backend.settings import get_settings -from fastapi_sqlalchemy import db -from pydantic import Json settings = get_settings() diff --git a/calendar_backend/methods/__init__.py b/calendar_backend/methods/__init__.py index 8d9cb5be..9fc6b6f1 100644 --- a/calendar_backend/methods/__init__.py +++ b/calendar_backend/methods/__init__.py @@ -1,5 +1,5 @@ -from . import utils -from . import auth +from . import auth, utils + __all__ = [ "utils", diff --git a/calendar_backend/methods/auth.py b/calendar_backend/methods/auth.py index 9284cdcc..40f227b5 100644 --- a/calendar_backend/methods/auth.py +++ b/calendar_backend/methods/auth.py @@ -1,9 +1,12 @@ import logging + from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from pydantic import BaseModel + from calendar_backend.settings import get_settings + logger = logging.getLogger(__name__) settings = get_settings() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") diff --git a/calendar_backend/methods/list_calendar.py b/calendar_backend/methods/list_calendar.py index 5e41a30a..e97b3c13 100644 --- a/calendar_backend/methods/list_calendar.py +++ b/calendar_backend/methods/list_calendar.py @@ -4,15 +4,18 @@ import time from datetime import date as date_ from datetime import datetime -from fastapi import HTTPException -from fastapi.responses import FileResponse import pytz +from fastapi import HTTPException +from fastapi.responses import FileResponse from icalendar import Calendar, Event, vText from sqlalchemy.orm import Session + +from calendar_backend.models import Group from calendar_backend.settings import get_settings + from . import utils -from calendar_backend.models import Group + settings = get_settings() logger = logging.getLogger(__name__) diff --git a/calendar_backend/methods/utils.py b/calendar_backend/methods/utils.py index 1d7da66b..8e3222c9 100644 --- a/calendar_backend/methods/utils.py +++ b/calendar_backend/methods/utils.py @@ -5,23 +5,16 @@ import string from concurrent.futures import ThreadPoolExecutor from functools import partial +from io import BytesIO from typing import Final import aiofiles -from fastapi import File, UploadFile, HTTPException +from fastapi import File, HTTPException, UploadFile +from PIL import Image from sqlalchemy.orm import Session -from calendar_backend.models.db import ( - Event, - Group, - Lecturer, - Photo, - Room, - ApproveStatuses, -) +from calendar_backend.models.db import ApproveStatuses, Event, Group, Lecturer, Photo, Room from calendar_backend.settings import get_settings -from PIL import Image -from io import BytesIO settings = get_settings() @@ -75,8 +68,10 @@ async def get_lecturer_lessons_in_daterange( events_list.append(lesson) return events_list + SUPPORTED_FILE_EXTENSIONS: Final[list[str]] = ['png', 'svg', 'jpg', 'jpeg'] + async def upload_lecturer_photo(lecturer_id: int, session: Session, file: UploadFile = File(...)) -> Photo: lecturer = Lecturer.get(lecturer_id, session=session) random_string = ''.join(random.choice(string.ascii_letters) for _ in range(32)) diff --git a/calendar_backend/models/__init__.py b/calendar_backend/models/__init__.py index 4b3dc27e..ff7eaf65 100644 --- a/calendar_backend/models/__init__.py +++ b/calendar_backend/models/__init__.py @@ -1,17 +1,18 @@ from .db import ( - Credentials, - Group, - Lecturer, - Event, - Room, - Direction, + ApproveStatuses, CommentEvent, CommentLecturer, + Credentials, + Direction, + Event, EventsLecturers, EventsRooms, - ApproveStatuses, + Group, + Lecturer, + Room, ) + __all__ = [ "Credentials", "Group", diff --git a/calendar_backend/models/base.py b/calendar_backend/models/base.py index 26d1cb88..35d641df 100644 --- a/calendar_backend/models/base.py +++ b/calendar_backend/models/base.py @@ -3,10 +3,10 @@ import re from enum import Enum -from sqlalchemy import Column, Integer, not_ +from sqlalchemy import Integer, not_ from sqlalchemy.exc import NoResultFound from sqlalchemy.ext.declarative import as_declarative, declared_attr -from sqlalchemy.orm import Query, Session, Mapped, mapped_column +from sqlalchemy.orm import Mapped, Query, Session, mapped_column from calendar_backend.exceptions import ObjectNotFound diff --git a/calendar_backend/models/db.py b/calendar_backend/models/db.py index 6005df43..93776187 100644 --- a/calendar_backend/models/db.py +++ b/calendar_backend/models/db.py @@ -5,12 +5,13 @@ from datetime import datetime from enum import Enum -from sqlalchemy import and_, or_, Integer, String, Boolean, JSON, DateTime, Text, ForeignKey, true +from sqlalchemy import JSON, Boolean, DateTime from sqlalchemy import Enum as DbEnum +from sqlalchemy import ForeignKey, Integer, String, Text, and_, or_, true from sqlalchemy.ext.hybrid import hybrid_method, hybrid_property -from sqlalchemy.orm import relationship, Mapped, mapped_column +from sqlalchemy.orm import Mapped, mapped_column, relationship -from .base import BaseDbModel, ApproveStatuses +from .base import ApproveStatuses, BaseDbModel class Credentials(BaseDbModel): diff --git a/calendar_backend/routes/__init__.py b/calendar_backend/routes/__init__.py index 7c8d47d2..5086daf1 100644 --- a/calendar_backend/routes/__init__.py +++ b/calendar_backend/routes/__init__.py @@ -1,3 +1,4 @@ from .base import app + __all__ = ["app"] diff --git a/calendar_backend/routes/auth.py b/calendar_backend/routes/auth.py index b5c64d34..b86ebd7c 100644 --- a/calendar_backend/routes/auth.py +++ b/calendar_backend/routes/auth.py @@ -1,14 +1,18 @@ +"""DEPRICATED TODO: Drop 2023-04-01 +""" import logging -from fastapi import APIRouter, HTTPException, Depends +from fastapi import APIRouter, Depends, HTTPException from fastapi.security import OAuth2PasswordRequestForm -from calendar_backend.settings import get_settings from calendar_backend.methods import auth +from calendar_backend.settings import get_settings + -auth_router = APIRouter(prefix="", tags=["Utils: Auth"]) settings = get_settings() logger = logging.getLogger(__name__) +# DEPRICATED TODO: Drop 2023-04-01 +auth_router = APIRouter(prefix="", tags=["Utils: Auth"], deprecated=True) @auth_router.post("/token") diff --git a/calendar_backend/routes/base.py b/calendar_backend/routes/base.py index df78e1cd..0a0c3721 100644 --- a/calendar_backend/routes/base.py +++ b/calendar_backend/routes/base.py @@ -5,8 +5,8 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse -from fastapi_sqlalchemy import DBSessionMiddleware from fastapi.staticfiles import StaticFiles +from fastapi_sqlalchemy import DBSessionMiddleware from starlette import status from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint from starlette.requests import Request @@ -14,33 +14,48 @@ from starlette.types import ASGIApp from calendar_backend import __version__ -from calendar_backend.exceptions import ObjectNotFound, ForbiddenAction, NotEnoughCriteria +from calendar_backend.exceptions import ForbiddenAction, NotEnoughCriteria, ObjectNotFound from calendar_backend.settings import get_settings -from .auth import auth_router +from .auth import auth_router # TODO: Replace with PKFF Auth +from .event import event_comment_review_router as old_event_comment_review_router # DEPRICATED TODO: Drop 2023-04-01 +from .event import event_comment_router as old_event_comment_router # DEPRICATED TODO: Drop 2023-04-01 +from .event import event_router as old_event_router # DEPRICATED TODO: Drop 2023-04-01 +from .event.comment import router as event_comment_router +from .event.comment_review import router as event_comment_review_router +from .event.event import router as event_router from .gcal import gcal +from .group import group_router as old_group_router # DEPRICATED TODO: Drop 2023-04-01 +from .group.group import router as group_router from .lecturer import ( - lecturer_router, - lecturer_comment_router, - lecturer_comment_review_router, - lecturer_photo_review_router, - lecturer_photo_router, -) -from .group import group_router -from .room import room_router -from .event import event_router, event_comment_router, event_comment_review_router + lecturer_comment_review_router as old_lecturer_comment_review_router, +) # DEPRICATED TODO: Drop 2023-04-01 +from .lecturer import lecturer_comment_router as old_lecturer_comment_router # DEPRICATED TODO: Drop 2023-04-01 +from .lecturer import ( + lecturer_photo_review_router as old_lecturer_photo_review_router, +) # DEPRICATED TODO: Drop 2023-04-01 +from .lecturer import lecturer_photo_router as old_lecturer_photo_router # DEPRICATED TODO: Drop 2023-04-01 +from .lecturer import lecturer_router as old_lecturer_router # DEPRICATED TODO: Drop 2023-04-01 +from .lecturer.comment import router as lecturer_comment_router +from .lecturer.comment_review import router as lecturer_comment_review_router +from .lecturer.lecturer import router as lecturer_router +from .lecturer.photo import router as lecturer_photo_router +from .lecturer.photo_review import router as lecturer_photo_review_router +from .room import room_router as old_room_router # DEPRICATED TODO: Drop 2023-04-01 +from .room.room import router as room_router settings = get_settings() logger = logging.getLogger(__name__) app = FastAPI( - title='Сервис мониторинга активности', - description=dedent(""" + title='Сервис расписания', + description=dedent( + """ API для работы с календарем физфака. Пример работы на питоне(Создание Room): ```python import reqests, json - url=f"https://timetable.api.test.profcomff.com" + url=f"https://api.test.profcomff.com/timetable" # Авторизация beaver = requests.post(f"{url}/token", {"username": "...", "password": "..."}) @@ -50,14 +65,14 @@ # Создание create_room = requests.post( - f"{url}/timetable/room", + f"{url}/room", json={"name": "test", "direction": "South"}, headers={"Authorization": f"Bearer {auth_data.get('access_token')}"} ) ``` - """), + """ + ), version=__version__, - # Настраиваем интернет документацию root_path=settings.ROOT_PATH if __version__ != 'dev' else '/', docs_url=None if __version__ != 'dev' else '/docs', @@ -123,8 +138,22 @@ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) - app.mount('/static', StaticFiles(directory=settings.STATIC_PATH), 'static') +# region DEPRICATED +# TODO: Drop 2023-04-01 app.include_router(gcal) app.include_router(auth_router) +app.include_router(old_lecturer_router) +app.include_router(old_lecturer_comment_router) +app.include_router(old_lecturer_comment_review_router) +app.include_router(old_lecturer_photo_router) +app.include_router(old_lecturer_photo_review_router) +app.include_router(old_group_router) +app.include_router(old_room_router) +app.include_router(old_event_router) +app.include_router(old_event_comment_router) +app.include_router(old_event_comment_review_router) +# endregion + app.include_router(lecturer_router) app.include_router(lecturer_comment_router) app.include_router(lecturer_comment_review_router) diff --git a/calendar_backend/routes/event/__init__.py b/calendar_backend/routes/event/__init__.py index a9b67941..12db3f89 100644 --- a/calendar_backend/routes/event/__init__.py +++ b/calendar_backend/routes/event/__init__.py @@ -1,5 +1,6 @@ -from .event import event_router -from .comment_review import event_comment_review_router from .comment import event_comment_router +from .comment_review import event_comment_review_router +from .event import event_router + __all__ = ["event_router", "event_comment_review_router", "event_comment_router"] diff --git a/calendar_backend/routes/event/comment.py b/calendar_backend/routes/event/comment.py index 038bfe45..d0bc4089 100644 --- a/calendar_backend/routes/event/comment.py +++ b/calendar_backend/routes/event/comment.py @@ -1,35 +1,33 @@ from fastapi import APIRouter, Depends from fastapi_sqlalchemy import db -from calendar_backend.exceptions import ObjectNotFound, ForbiddenAction +from calendar_backend.exceptions import ForbiddenAction, ObjectNotFound from calendar_backend.methods import auth from calendar_backend.models import ApproveStatuses from calendar_backend.models import CommentEvent as DbCommentEvent -from calendar_backend.routes.models.event import ( - CommentEventGet, - EventCommentPost, - EventCommentPatch, - EventComments, -) +from calendar_backend.routes.models.event import CommentEventGet, EventCommentPatch, EventCommentPost, EventComments from calendar_backend.settings import get_settings -settings = get_settings() - -event_comment_router = APIRouter(prefix="/timetable/event/{event_id}", tags=["Event: Comment"]) +settings = get_settings() +# DEPRICATED TODO: Drop 2023-04-01 +event_comment_router = APIRouter(prefix="/timetable/event/{event_id}", tags=["Event: Comment"], deprecated=True) +router = APIRouter(prefix="/event/{event_id}", tags=["Event: Comment"]) -@event_comment_router.post("/comment/", response_model=CommentEventGet) +@event_comment_router.post("/comment/", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/comment/", response_model=CommentEventGet) async def comment_event(event_id: int, comment: EventCommentPost) -> CommentEventGet: approve_status = ApproveStatuses.APPROVED if not settings.REQUIRE_REVIEW_EVENT_COMMENT else ApproveStatuses.PENDING - comment_event = DbCommentEvent.create(event_id=event_id, session=db.session, **comment.dict(), approve_status=approve_status) - db.session.commit() - return CommentEventGet.from_orm( - comment_event + comment_event = DbCommentEvent.create( + event_id=event_id, session=db.session, **comment.dict(), approve_status=approve_status ) + db.session.commit() + return CommentEventGet.from_orm(comment_event) -@event_comment_router.patch("/comment/{id}", response_model=CommentEventGet) +@event_comment_router.patch("/comment/{id}", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.patch("/comment/{id}", response_model=CommentEventGet) async def update_comment(id: int, event_id: int, comment_inp: EventCommentPatch) -> CommentEventGet: comment = DbCommentEvent.get(id, only_approved=False, session=db.session) if comment.event_id != event_id: @@ -38,12 +36,11 @@ async def update_comment(id: int, event_id: int, comment_inp: EventCommentPatch) raise ForbiddenAction(DbCommentEvent, id) comment_event = DbCommentEvent.update(id, session=db.session, **comment_inp.dict(exclude_unset=True)) db.session.commit() - return CommentEventGet.from_orm( - comment_event - ) + return CommentEventGet.from_orm(comment_event) -@event_comment_router.get("/comment/{id}", response_model=CommentEventGet) +@event_comment_router.get("/comment/{id}", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/comment/{id}", response_model=CommentEventGet) async def get_comment(id: int, event_id: int) -> CommentEventGet: comment = DbCommentEvent.get(id, session=db.session) if not comment.event_id == event_id or comment.approve_status != ApproveStatuses.APPROVED: @@ -51,7 +48,8 @@ async def get_comment(id: int, event_id: int) -> CommentEventGet: return CommentEventGet.from_orm(comment) -@event_comment_router.delete("/comment/{id}", response_model=None) +@event_comment_router.delete("/comment/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/comment/{id}", response_model=None) async def delete_comment(id: int, event_id: int, _: auth.User = Depends(auth.get_current_user)) -> None: comment = DbCommentEvent.get(id, only_approved=False, session=db.session) if comment.event_id != event_id or comment.approve_status != ApproveStatuses.APPROVED: @@ -61,7 +59,8 @@ async def delete_comment(id: int, event_id: int, _: auth.User = Depends(auth.get return None -@event_comment_router.get("/comment/", response_model=EventComments) +@event_comment_router.get("/comment/", response_model=EventComments) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/comment/", response_model=EventComments) async def get_event_comments(event_id: int, limit: int = 10, offset: int = 0) -> EventComments: res = DbCommentEvent.get_all(session=db.session).filter(DbCommentEvent.event_id == event_id) if limit: diff --git a/calendar_backend/routes/event/comment_review.py b/calendar_backend/routes/event/comment_review.py index e6234d6a..81b8b308 100644 --- a/calendar_backend/routes/event/comment_review.py +++ b/calendar_backend/routes/event/comment_review.py @@ -8,16 +8,20 @@ from calendar_backend.methods import auth from calendar_backend.models import ApproveStatuses from calendar_backend.models import CommentEvent as DbCommentEvent -from calendar_backend.routes.models.event import ( - CommentEventGet, -) +from calendar_backend.routes.models.event import CommentEventGet from calendar_backend.settings import get_settings -event_comment_review_router = APIRouter(prefix="/timetable/event/{event_id}/comment", tags=["Event: Comment Review"]) + settings = get_settings() +# DEPRICATED TODO: Drop 2023-04-01 +event_comment_review_router = APIRouter( + prefix="/timetable/event/{event_id}/comment", tags=["Event: Comment Review"], deprecated=True +) +router = APIRouter(prefix="/event/{event_id}/comment", tags=["Event: Comment Review"]) -@event_comment_review_router.get("/review/", response_model=list[CommentEventGet]) +@event_comment_review_router.get("/review/", response_model=list[CommentEventGet]) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/review/", response_model=list[CommentEventGet]) async def get_unreviewed_comments( event_id: int, _: auth.User = Depends(auth.get_current_user) ) -> list[CommentEventGet]: @@ -29,7 +33,8 @@ async def get_unreviewed_comments( return parse_obj_as(list[CommentEventGet], comments) -@event_comment_review_router.post("/{id}/review/", response_model=CommentEventGet) +@event_comment_review_router.post("/{id}/review/", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/{id}/review/", response_model=CommentEventGet) async def review_comment( id: int, event_id: int, diff --git a/calendar_backend/routes/event/event.py b/calendar_backend/routes/event/event.py index 44845020..16b22cc5 100644 --- a/calendar_backend/routes/event/event.py +++ b/calendar_backend/routes/event/event.py @@ -9,21 +9,21 @@ from calendar_backend.exceptions import NotEnoughCriteria from calendar_backend.methods import auth, list_calendar -from calendar_backend.models import Room, Lecturer, Event, EventsLecturers, EventsRooms, Group +from calendar_backend.models import Event, EventsLecturers, EventsRooms, Group, Lecturer, Room from calendar_backend.routes.models import EventGet -from calendar_backend.routes.models.event import ( - EventPatch, - EventPost, - GetListEvent, -) +from calendar_backend.routes.models.event import EventPatch, EventPost, GetListEvent from calendar_backend.settings import get_settings -event_router = APIRouter(prefix="/timetable/event", tags=["Event"]) + settings = get_settings() logger = logging.getLogger(__name__) +# DEPRICATED TODO: Drop 2023-04-01 +event_router = APIRouter(prefix="/timetable/event", tags=["Event"], deprecated=True) +router = APIRouter(prefix="/event", tags=["Event"]) -@event_router.get("/{id}", response_model=EventGet) +@event_router.get("/{id}", response_model=EventGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/{id}", response_model=EventGet) async def get_event_by_id(id: int) -> EventGet: return EventGet.from_orm(Event.get(id, session=db.session)) @@ -64,7 +64,8 @@ async def _get_timetable(start: date, end: date, group_id, lecturer_id, room_id, return GetListEvent(items=events, limit=limit, offset=offset, total=cnt).dict(exclude=fmt) -@event_router.get("/", response_model=GetListEvent | None) +@event_router.get("/", response_model=GetListEvent | None) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/", response_model=GetListEvent | None) async def get_events( start: date | None = Query(default=None, description="Default: Today"), end: date | None = Query(default=None, description="Default: Tomorrow"), @@ -85,26 +86,26 @@ async def get_events( return await fmt_cases[format]() -@event_router.post("/", response_model=EventGet) +@event_router.post("/", response_model=EventGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/", response_model=EventGet) async def create_event(event: EventPost, _: auth.User = Depends(auth.get_current_user)) -> EventGet: event_dict = event.dict() rooms = [Room.get(room_id, session=db.session) for room_id in event_dict.pop("room_id", [])] lecturers = [Lecturer.get(lecturer_id, session=db.session) for lecturer_id in event_dict.pop("lecturer_id", [])] group = Group.get(event.group_id, session=db.session) event_get = Event.create( - **event_dict, - room=rooms, - lecturer=lecturers, - group=group, - session=db.session, - ) - db.session.commit() - return EventGet.from_orm( - event_get + **event_dict, + room=rooms, + lecturer=lecturers, + group=group, + session=db.session, ) + db.session.commit() + return EventGet.from_orm(event_get) -@event_router.post("/bulk", response_model=list[EventGet]) +@event_router.post("/bulk", response_model=list[EventGet]) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/bulk", response_model=list[EventGet]) async def create_events(events: list[EventPost], _: auth.User = Depends(auth.get_current_user)) -> list[EventGet]: result = [] for event in events: @@ -125,22 +126,23 @@ async def create_events(events: list[EventPost], _: auth.User = Depends(auth.get return parse_obj_as(list[EventGet], result) -@event_router.patch("/{id}", response_model=EventGet) +@event_router.patch("/{id}", response_model=EventGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.patch("/{id}", response_model=EventGet) async def patch_event(id: int, event_inp: EventPatch, _: auth.User = Depends(auth.get_current_user)) -> EventGet: patched = Event.update(id, session=db.session, **event_inp.dict(exclude_unset=True)) db.session.commit() return EventGet.from_orm(patched) -@event_router.delete("/bulk", response_model=None) +@event_router.delete("/bulk", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/bulk", response_model=None) async def delete_events(start: date, end: date, _: auth.User = Depends(auth.get_current_user)) -> None: - db.session.query(Event).filter(Event.start_ts >= start, Event.end_ts < end).update( - values={"is_deleted": True} - ) + db.session.query(Event).filter(Event.start_ts >= start, Event.end_ts < end).update(values={"is_deleted": True}) db.session.commit() -@event_router.delete("/{id}", response_model=None) +@event_router.delete("/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/{id}", response_model=None) async def delete_event(id: int, _: auth.User = Depends(auth.get_current_user)) -> None: Event.delete(id, session=db.session) db.session.commit() diff --git a/calendar_backend/routes/gcal.py b/calendar_backend/routes/gcal.py index 9099af09..1a37fdb2 100644 --- a/calendar_backend/routes/gcal.py +++ b/calendar_backend/routes/gcal.py @@ -1,30 +1,32 @@ +"""DEPRICATED TODO: Drop 2023-04-01 +""" import logging import os from functools import lru_cache from urllib.parse import unquote -from fastapi import APIRouter, HTTPException, Request, BackgroundTasks +from fastapi import APIRouter, BackgroundTasks, HTTPException, Request from fastapi.responses import RedirectResponse from fastapi.templating import Jinja2Templates from fastapi_sqlalchemy import db -from fastapi_sqlalchemy.exceptions import ( - SessionNotInitialisedError, - MissingSessionError, -) +from fastapi_sqlalchemy.exceptions import MissingSessionError, SessionNotInitialisedError from google_auth_oauthlib.flow import Flow -from googleapiclient.discovery import build, UnknownApiNameOrVersion +from googleapiclient.discovery import UnknownApiNameOrVersion, build from pydantic.types import Json -from calendar_backend.google_engine import create_calendar_with_timetable -from calendar_backend.google_engine import get_calendar_service_from_token +from calendar_backend.google_engine import create_calendar_with_timetable, get_calendar_service_from_token from calendar_backend.models import Credentials, Group from calendar_backend.settings import get_settings -gcal = APIRouter(tags=["Utils: Google"]) + settings = get_settings() +logger = logging.getLogger(__name__) templates = Jinja2Templates(directory="calendar_backend/templates") +# DEPRICATED TODO: Drop 2023-04-01 +gcal = APIRouter(tags=["Utils: Google"], deprecated=True) + + os.environ["OAUTHLIB_RELAX_TOKEN_SCOPE"] = "1" -logger = logging.getLogger(__name__) @lru_cache(2) @@ -39,8 +41,9 @@ def get_flow(state=""): @gcal.get("/") async def home(request: Request): - groups = [f"{row.number}, {row.name}" if row.name else f"{row.number}" - for row in db.session.query(Group).filter().all()] + groups = [ + f"{row.number}, {row.name}" if row.name else f"{row.number}" for row in db.session.query(Group).filter().all() + ] return templates.TemplateResponse( "index.html", {"request": request, "groups": groups}, @@ -64,8 +67,9 @@ async def get_credentials( scope: str, state: str, ): - groups = [f"{row.number}, {row.name}" if row.name else f"{row.number}" - for row in db.session.query(Group).filter().all()] + groups = [ + f"{row.number}, {row.name}" if row.name else f"{row.number}" for row in db.session.query(Group).filter().all() + ] scope = scope.split(unquote("%20")) group = state flow = get_flow() diff --git a/calendar_backend/routes/group/__init__.py b/calendar_backend/routes/group/__init__.py index d6467ebf..f23f94fa 100644 --- a/calendar_backend/routes/group/__init__.py +++ b/calendar_backend/routes/group/__init__.py @@ -1,3 +1,4 @@ from .group import group_router + __all__ = ["group_router"] diff --git a/calendar_backend/routes/group/group.py b/calendar_backend/routes/group/group.py index 543733d5..996a826e 100644 --- a/calendar_backend/routes/group/group.py +++ b/calendar_backend/routes/group/group.py @@ -1,24 +1,29 @@ import logging -from fastapi import APIRouter, HTTPException, Depends +from fastapi import APIRouter, Depends, HTTPException from fastapi_sqlalchemy import db from calendar_backend.methods import auth from calendar_backend.models import Group -from calendar_backend.routes.models import GroupGet, GroupPost, GroupPatch, GetListGroup +from calendar_backend.routes.models import GetListGroup, GroupGet, GroupPatch, GroupPost from calendar_backend.settings import get_settings -group_router = APIRouter(prefix="/timetable/group", tags=["Group"]) + settings = get_settings() logger = logging.getLogger(__name__) +# DEPRICATED TODO: Drop 2023-04-01 +group_router = APIRouter(prefix="/timetable/group", tags=["Group"], deprecated=True) +router = APIRouter(prefix="/group", tags=["Group"]) -@group_router.get("/{id}", response_model=GroupGet) +@group_router.get("/{id}", response_model=GroupGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/{id}", response_model=GroupGet) async def get_group_by_id(id: int) -> GroupGet: return GroupGet.from_orm(Group.get(id, session=db.session)) -@group_router.get("/", response_model=GetListGroup) +@group_router.get("/", response_model=GetListGroup) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/", response_model=GetListGroup) async def get_groups(query: str = "", limit: int = 10, offset: int = 0) -> GetListGroup: res = Group.get_all(session=db.session).filter(Group.number.contains(query)) if limit: @@ -35,7 +40,8 @@ async def get_groups(query: str = "", limit: int = 10, offset: int = 0) -> GetLi ) -@group_router.post("/", response_model=GroupGet) +@group_router.post("/", response_model=GroupGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/", response_model=GroupGet) async def create_group(group: GroupPost, _: auth.User = Depends(auth.get_current_user)) -> GroupGet: if db.session.query(Group).filter(Group.number == group.number).one_or_none(): raise HTTPException(status_code=423, detail="Already exists") @@ -44,15 +50,16 @@ async def create_group(group: GroupPost, _: auth.User = Depends(auth.get_current return GroupGet.from_orm(group) -@group_router.patch("/{id}", response_model=GroupGet) +@group_router.patch("/{id}", response_model=GroupGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.patch("/{id}", response_model=GroupGet) async def patch_group( id: int, group_inp: GroupPatch, _: auth.User = Depends(auth.get_current_user), ) -> GroupGet: if ( - bool(query := Group.get_all(session=db.session).filter(Group.number == group_inp.number).one_or_none()) and - query.id != id + bool(query := Group.get_all(session=db.session).filter(Group.number == group_inp.number).one_or_none()) + and query.id != id ): raise HTTPException(status_code=423, detail="Already exists") patched = Group.update(id, **group_inp.dict(exclude_unset=True), session=db.session) @@ -60,7 +67,8 @@ async def patch_group( return GroupGet.from_orm(patched) -@group_router.delete("/{id}", response_model=None) +@group_router.delete("/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/{id}", response_model=None) async def delete_group(id: int, _: auth.User = Depends(auth.get_current_user)) -> None: Group.delete(id, session=db.session) db.session.commit() diff --git a/calendar_backend/routes/lecturer/__init__.py b/calendar_backend/routes/lecturer/__init__.py index a30d0e7a..0b068543 100644 --- a/calendar_backend/routes/lecturer/__init__.py +++ b/calendar_backend/routes/lecturer/__init__.py @@ -1,9 +1,10 @@ -from .lecturer import lecturer_router -from .photo import lecturer_photo_router from .comment import lecturer_comment_router from .comment_review import lecturer_comment_review_router +from .lecturer import lecturer_router +from .photo import lecturer_photo_router from .photo_review import lecturer_photo_review_router + __all__ = [ "lecturer_photo_review_router", "lecturer_comment_review_router", diff --git a/calendar_backend/routes/lecturer/comment.py b/calendar_backend/routes/lecturer/comment.py index 0463d432..300ebdd2 100644 --- a/calendar_backend/routes/lecturer/comment.py +++ b/calendar_backend/routes/lecturer/comment.py @@ -1,41 +1,40 @@ from fastapi import APIRouter, Depends from fastapi_sqlalchemy import db -from calendar_backend.exceptions import ObjectNotFound, ForbiddenAction +from calendar_backend.exceptions import ForbiddenAction, ObjectNotFound from calendar_backend.methods import auth from calendar_backend.models.db import ApproveStatuses from calendar_backend.models.db import CommentLecturer as DbCommentLecturer -from calendar_backend.routes.models import ( - CommentLecturer, - LecturerCommentPost, - LecturerCommentPatch, - LecturerComments, -) +from calendar_backend.routes.models import CommentLecturer, LecturerCommentPatch, LecturerCommentPost, LecturerComments from calendar_backend.settings import get_settings -settings = get_settings() -lecturer_comment_router = APIRouter(prefix="/timetable/lecturer/{lecturer_id}", tags=["Lecturer: Comment"]) +settings = get_settings() +# DEPRICATED TODO: Drop 2023-04-01 +lecturer_comment_router = APIRouter( + prefix="/timetable/lecturer/{lecturer_id}", tags=["Lecturer: Comment"], deprecated=True +) +router = APIRouter(prefix="/lecturer/{lecturer_id}", tags=["Lecturer: Comment"]) -@lecturer_comment_router.post("/comment/", response_model=CommentLecturer) +@lecturer_comment_router.post("/comment/", response_model=CommentLecturer) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/comment/", response_model=CommentLecturer) async def comment_lecturer(lecturer_id: int, comment: LecturerCommentPost) -> CommentLecturer: approve_status = ( ApproveStatuses.APPROVED if not settings.REQUIRE_REVIEW_LECTURER_COMMENT else ApproveStatuses.PENDING ) db_comment_lecturer = DbCommentLecturer.create( - lecturer_id=lecturer_id, - session=db.session, - **comment.dict(), - approve_status=approve_status, - ) - db.session.commit() - return CommentLecturer.from_orm( - db_comment_lecturer + lecturer_id=lecturer_id, + session=db.session, + **comment.dict(), + approve_status=approve_status, ) + db.session.commit() + return CommentLecturer.from_orm(db_comment_lecturer) -@lecturer_comment_router.patch("/comment/{id}", response_model=CommentLecturer) +@lecturer_comment_router.patch("/comment/{id}", response_model=CommentLecturer) # DEPRICATED TODO: Drop 2023-04-01 +@router.patch("/comment/{id}", response_model=CommentLecturer) async def update_comment_lecturer(id: int, lecturer_id: int, comment_inp: LecturerCommentPatch) -> CommentLecturer: comment = DbCommentLecturer.get(id=id, only_approved=False, session=db.session) if comment.lecturer_id != lecturer_id: @@ -44,12 +43,11 @@ async def update_comment_lecturer(id: int, lecturer_id: int, comment_inp: Lectur raise ForbiddenAction(DbCommentLecturer, id) patched = DbCommentLecturer.update(id, session=db.session, **comment_inp.dict(exclude_unset=True)) db.session.commit() - return CommentLecturer.from_orm( - patched - ) + return CommentLecturer.from_orm(patched) -@lecturer_comment_router.delete("/comment/{id}", response_model=None) +@lecturer_comment_router.delete("/comment/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/comment/{id}", response_model=None) async def delete_comment(id: int, lecturer_id: int, _: auth.User = Depends(auth.get_current_user)) -> None: comment = DbCommentLecturer.get(id, only_approved=False, session=db.session) if comment.lecturer_id != lecturer_id: @@ -58,7 +56,8 @@ async def delete_comment(id: int, lecturer_id: int, _: auth.User = Depends(auth. db.session.commit() -@lecturer_comment_router.get("/comment/{id}", response_model=CommentLecturer) +@lecturer_comment_router.get("/comment/{id}", response_model=CommentLecturer) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/comment/{id}", response_model=CommentLecturer) async def get_comment(id: int, lecturer_id: int) -> CommentLecturer: comment = DbCommentLecturer.get(id, session=db.session) if not comment.lecturer_id == lecturer_id: @@ -68,7 +67,8 @@ async def get_comment(id: int, lecturer_id: int) -> CommentLecturer: return CommentLecturer.from_orm(comment) -@lecturer_comment_router.get("/comment/", response_model=LecturerComments) +@lecturer_comment_router.get("/comment/", response_model=LecturerComments) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/comment/", response_model=LecturerComments) async def get_all_lecturer_comments(lecturer_id: int, limit: int = 10, offset: int = 0) -> LecturerComments: res = DbCommentLecturer.get_all(session=db.session).filter(DbCommentLecturer.lecturer_id == lecturer_id) if limit: diff --git a/calendar_backend/routes/lecturer/comment_review.py b/calendar_backend/routes/lecturer/comment_review.py index 1f5c4927..e7f9be8d 100644 --- a/calendar_backend/routes/lecturer/comment_review.py +++ b/calendar_backend/routes/lecturer/comment_review.py @@ -8,16 +8,20 @@ from calendar_backend.methods import auth from calendar_backend.models.db import ApproveStatuses from calendar_backend.models.db import CommentLecturer as DbCommentLecturer -from calendar_backend.routes.models import ( - CommentLecturer, -) +from calendar_backend.routes.models import CommentLecturer + +# DEPRICATED TODO: Drop 2023-04-01 lecturer_comment_review_router = APIRouter( - prefix="/timetable/lecturer/{lecturer_id}/comment", tags=["Lecturer: Comment Review"] + prefix="/timetable/lecturer/{lecturer_id}/comment", tags=["Lecturer: Comment Review"], deprecated=True ) +router = APIRouter(prefix="/lecturer/{lecturer_id}/comment", tags=["Lecturer: Comment Review"]) -@lecturer_comment_review_router.get("/review/", response_model=list[CommentLecturer]) +@lecturer_comment_review_router.get( + "/review/", response_model=list[CommentLecturer] +) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/review/", response_model=list[CommentLecturer]) async def get_unreviewed_comments( lecturer_id: int, _: auth.User = Depends(auth.get_current_user) ) -> list[CommentLecturer]: @@ -31,7 +35,10 @@ async def get_unreviewed_comments( return parse_obj_as(list[CommentLecturer], comments) -@lecturer_comment_review_router.post("/{id}/review/", response_model=CommentLecturer) +@lecturer_comment_review_router.post( + "/{id}/review/", response_model=CommentLecturer +) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/{id}/review/", response_model=CommentLecturer) async def review_comment( id: int, lecturer_id: int, diff --git a/calendar_backend/routes/lecturer/lecturer.py b/calendar_backend/routes/lecturer/lecturer.py index a60300bd..121a18aa 100644 --- a/calendar_backend/routes/lecturer/lecturer.py +++ b/calendar_backend/routes/lecturer/lecturer.py @@ -6,23 +6,21 @@ from calendar_backend.exceptions import ObjectNotFound from calendar_backend.methods import auth -from calendar_backend.models.db import Lecturer, ApproveStatuses +from calendar_backend.models.db import ApproveStatuses, Lecturer from calendar_backend.models.db import Photo as DbPhoto -from calendar_backend.routes.models import ( - GetListLecturer, - LecturerGet, - LecturerPost, - LecturerPatch, -) +from calendar_backend.routes.models import GetListLecturer, LecturerGet, LecturerPatch, LecturerPost from calendar_backend.settings import get_settings -lecturer_router = APIRouter(prefix="/timetable/lecturer", tags=["Lecturer"]) -review_lecturer_router = APIRouter(prefix="/timetable/lecturer/{lecturer_id}", tags=["Review"]) + settings = get_settings() logger = logging.getLogger(__name__) +# DEPRICATED TODO: Drop 2023-04-01 +lecturer_router = APIRouter(prefix="/timetable/lecturer", tags=["Lecturer"], deprecated=True) +router = APIRouter(prefix="/lecturer", tags=["Lecturer"]) -@lecturer_router.get("/{id}", response_model=LecturerGet) +@lecturer_router.get("/{id}", response_model=LecturerGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/{id}", response_model=LecturerGet) async def get_lecturer_by_id(id: int) -> LecturerGet: lecturer = Lecturer.get(id, session=db.session) if lecturer.avatar_id: @@ -30,7 +28,8 @@ async def get_lecturer_by_id(id: int) -> LecturerGet: return LecturerGet.from_orm(Lecturer.get(id, session=db.session)) -@lecturer_router.get("/", response_model=GetListLecturer) +@lecturer_router.get("/", response_model=GetListLecturer) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/", response_model=GetListLecturer) async def get_lecturers( query: str = "", limit: int = 10, @@ -52,14 +51,16 @@ async def get_lecturers( } -@lecturer_router.post("/", response_model=LecturerGet) +@lecturer_router.post("/", response_model=LecturerGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/", response_model=LecturerGet) async def create_lecturer(lecturer: LecturerPost, _: auth.User = Depends(auth.get_current_user)) -> LecturerGet: dblecturer = Lecturer.create(session=db.session, **lecturer.dict()) db.session.commit() return LecturerGet.from_orm(dblecturer) -@lecturer_router.patch("/{id}", response_model=LecturerGet) +@lecturer_router.patch("/{id}", response_model=LecturerGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.patch("/{id}", response_model=LecturerGet) async def patch_lecturer( id: int, lecturer_inp: LecturerPatch, _: auth.User = Depends(auth.get_current_user) ) -> LecturerGet: @@ -76,7 +77,8 @@ async def patch_lecturer( return LecturerGet.from_orm(lecturer_upd) -@lecturer_router.delete("/{id}", response_model=None) +@lecturer_router.delete("/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/{id}", response_model=None) async def delete_lecturer(id: int, _: auth.User = Depends(auth.get_current_user)) -> None: Lecturer.delete(id, session=db.session) db.session.commit() diff --git a/calendar_backend/routes/lecturer/photo.py b/calendar_backend/routes/lecturer/photo.py index d9c5ad6d..08b62c21 100644 --- a/calendar_backend/routes/lecturer/photo.py +++ b/calendar_backend/routes/lecturer/photo.py @@ -1,19 +1,20 @@ -from fastapi import APIRouter, UploadFile, File +from fastapi import APIRouter, File, UploadFile from fastapi_sqlalchemy import db from calendar_backend.exceptions import ObjectNotFound from calendar_backend.methods import utils from calendar_backend.models.db import ApproveStatuses, Lecturer from calendar_backend.models.db import Photo as DbPhoto -from calendar_backend.routes.models import ( - Photo, - LecturerPhotos, -) +from calendar_backend.routes.models import LecturerPhotos, Photo -lecturer_photo_router = APIRouter(prefix="/timetable/lecturer/{lecturer_id}", tags=["Lecturer: Photo"]) +# DEPRICATED TODO: Drop 2023-04-01 +lecturer_photo_router = APIRouter(prefix="/timetable/lecturer/{lecturer_id}", tags=["Lecturer: Photo"], deprecated=True) +router = APIRouter(prefix="/lecturer/{lecturer_id}", tags=["Lecturer: Photo"]) -@lecturer_photo_router.post("/photo", response_model=Photo) + +@lecturer_photo_router.post("/photo", response_model=Photo) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/photo", response_model=Photo) async def upload_photo(lecturer_id: int, photo: UploadFile = File(...)) -> Photo: """Загрузить фотографию преподавателя из локального файла @@ -32,7 +33,8 @@ async def upload_photo(lecturer_id: int, photo: UploadFile = File(...)) -> Photo return Photo.from_orm(photo) -@lecturer_photo_router.get("/photo", response_model=LecturerPhotos) +@lecturer_photo_router.get("/photo", response_model=LecturerPhotos) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/photo", response_model=LecturerPhotos) async def get_lecturer_photos(lecturer_id: int, limit: int = 10, offset: int = 0) -> LecturerPhotos: if not Lecturer.get(id=lecturer_id, session=db.session): raise ObjectNotFound(Lecturer, lecturer_id) @@ -44,7 +46,8 @@ async def get_lecturer_photos(lecturer_id: int, limit: int = 10, offset: int = 0 return LecturerPhotos(**{"items": [row.link for row in res], "limit": limit, "offset": offset, "total": cnt}) -@lecturer_photo_router.delete("/photo/{id}", response_model=None) +@lecturer_photo_router.delete("/photo/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/photo/{id}", response_model=None) async def delete_photo(id: int, lecturer_id: int) -> None: photo = DbPhoto.get(id, only_approved=False, session=db.session) if photo.lecturer_id != lecturer_id: @@ -56,7 +59,8 @@ async def delete_photo(id: int, lecturer_id: int) -> None: return None -@lecturer_photo_router.get("/photo/{id}", response_model=Photo) +@lecturer_photo_router.get("/photo/{id}", response_model=Photo) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/photo/{id}", response_model=Photo) async def get_photo(id: int, lecturer_id: int) -> Photo: if not Lecturer.get(id=lecturer_id, session=db.session): raise ObjectNotFound(Lecturer, lecturer_id) diff --git a/calendar_backend/routes/lecturer/photo_review.py b/calendar_backend/routes/lecturer/photo_review.py index 05277d8e..e466f49d 100644 --- a/calendar_backend/routes/lecturer/photo_review.py +++ b/calendar_backend/routes/lecturer/photo_review.py @@ -6,14 +6,18 @@ from calendar_backend.methods import auth from calendar_backend.models.db import ApproveStatuses, Lecturer from calendar_backend.models.db import Photo as DbPhoto -from calendar_backend.routes.models import Photo, Action +from calendar_backend.routes.models import Action, Photo + +# DEPRICATED TODO: Drop 2023-04-01 lecturer_photo_review_router = APIRouter( - prefix="/timetable/lecturer/{lecturer_id}/photo", tags=["Lecturer: Photo Review"] + prefix="/timetable/lecturer/{lecturer_id}/photo", tags=["Lecturer: Photo Review"], deprecated=True ) +router = APIRouter(prefix="/lecturer/{lecturer_id}/photo", tags=["Lecturer: Photo Review"]) -@lecturer_photo_review_router.get("/review/", response_model=list[Photo]) +@lecturer_photo_review_router.get("/review/", response_model=list[Photo]) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/review/", response_model=list[Photo]) async def get_unreviewed_photos(lecturer_id: int, _: auth.User = Depends(auth.get_current_user)) -> list[Photo]: photos = ( DbPhoto.get_all(session=db.session, only_approved=False) @@ -23,7 +27,8 @@ async def get_unreviewed_photos(lecturer_id: int, _: auth.User = Depends(auth.ge return parse_obj_as(list[Photo], photos) -@lecturer_photo_review_router.post("/{id}/review/", response_model=Photo) +@lecturer_photo_review_router.post("/{id}/review/", response_model=Photo) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/{id}/review/", response_model=Photo) async def review_photo( id: int, lecturer_id: int, diff --git a/calendar_backend/routes/models/__init__.py b/calendar_backend/routes/models/__init__.py index cca444c1..90a5b9c5 100644 --- a/calendar_backend/routes/models/__init__.py +++ b/calendar_backend/routes/models/__init__.py @@ -1,16 +1,16 @@ -from .base import LecturerGet, CommentLecturer, CommentEventGet, EventGet, GroupGet, RoomGet +from .base import CommentEventGet, CommentLecturer, EventGet, GroupGet, LecturerGet, RoomGet +from .event import Event, EventComments, EventPatch, EventPost, GetListEvent +from .group import GetListGroup, GroupEvents, GroupPatch, GroupPost from .lecturer import ( - LecturerPost, - LecturerPatch, - LecturerPhotos, - LecturerEvents, + Action, GetListLecturer, - Photo, - LecturerCommentPost, LecturerCommentPatch, + LecturerCommentPost, LecturerComments, - Action, + LecturerEvents, + LecturerPatch, + LecturerPhotos, + LecturerPost, + Photo, ) -from .room import RoomPost, RoomPatch, RoomEvents, GetListRoom -from .event import EventPost, EventPatch, Event, GetListEvent, EventComments -from .group import GroupPost, GroupPatch, GroupEvents, GetListGroup +from .room import GetListRoom, RoomEvents, RoomPatch, RoomPost diff --git a/calendar_backend/routes/models/event.py b/calendar_backend/routes/models/event.py index aac37a6c..bf0fa382 100644 --- a/calendar_backend/routes/models/event.py +++ b/calendar_backend/routes/models/event.py @@ -1,6 +1,6 @@ import datetime -from .base import Base, RoomGet, GroupGet, CommentEventGet, LecturerGet +from .base import Base, CommentEventGet, GroupGet, LecturerGet, RoomGet class EventPatch(Base): diff --git a/calendar_backend/routes/models/group.py b/calendar_backend/routes/models/group.py index 34da2d22..c77853e5 100644 --- a/calendar_backend/routes/models/group.py +++ b/calendar_backend/routes/models/group.py @@ -1,6 +1,6 @@ from pydantic import validator -from .base import Base, GroupGet, EventGet +from .base import Base, EventGet, GroupGet class GroupPatch(Base): diff --git a/calendar_backend/routes/models/lecturer.py b/calendar_backend/routes/models/lecturer.py index 46ddea9a..776095ba 100644 --- a/calendar_backend/routes/models/lecturer.py +++ b/calendar_backend/routes/models/lecturer.py @@ -1,5 +1,6 @@ from calendar_backend.models import ApproveStatuses -from .base import Base, LecturerGet, EventGet, CommentLecturer + +from .base import Base, CommentLecturer, EventGet, LecturerGet class LecturerPhotos(Base): diff --git a/calendar_backend/routes/models/room.py b/calendar_backend/routes/models/room.py index 74edf53c..cdae4f7c 100644 --- a/calendar_backend/routes/models/room.py +++ b/calendar_backend/routes/models/room.py @@ -1,6 +1,7 @@ -from .base import Base, RoomGet, EventGet from calendar_backend.models import Direction +from .base import Base, EventGet, RoomGet + class RoomPatch(Base): name: str | None diff --git a/calendar_backend/routes/room/__init__.py b/calendar_backend/routes/room/__init__.py index 1fb9da69..f86fd55b 100644 --- a/calendar_backend/routes/room/__init__.py +++ b/calendar_backend/routes/room/__init__.py @@ -1,3 +1,4 @@ from .room import room_router + __all__ = ["room_router"] diff --git a/calendar_backend/routes/room/room.py b/calendar_backend/routes/room/room.py index 44a645fa..91e734a7 100644 --- a/calendar_backend/routes/room/room.py +++ b/calendar_backend/routes/room/room.py @@ -1,24 +1,29 @@ import logging -from fastapi import APIRouter, HTTPException, Depends +from fastapi import APIRouter, Depends, HTTPException from fastapi_sqlalchemy import db from calendar_backend.methods import auth from calendar_backend.models import Room -from calendar_backend.routes.models import GetListRoom, RoomPost, RoomPatch, RoomGet +from calendar_backend.routes.models import GetListRoom, RoomGet, RoomPatch, RoomPost from calendar_backend.settings import get_settings -room_router = APIRouter(prefix="/timetable/room", tags=["Room"]) + settings = get_settings() logger = logging.getLogger(__name__) +# DEPRICATED TODO: Drop 2023-04-01 +room_router = APIRouter(prefix="/timetable/room", tags=["Room"], deprecated=True) +router = APIRouter(prefix="/room", tags=["Room"]) -@room_router.get("/{id}", response_model=RoomGet) +@room_router.get("/{id}", response_model=RoomGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/{id}", response_model=RoomGet) async def get_room_by_id(id: int) -> RoomGet: return RoomGet.from_orm(Room.get(id, session=db.session)) -@room_router.get("/", response_model=GetListRoom) +@room_router.get("/", response_model=GetListRoom) # DEPRICATED TODO: Drop 2023-04-01 +@router.get("/", response_model=GetListRoom) async def get_rooms(query: str = "", limit: int = 10, offset: int = 0) -> GetListRoom: res = Room.get_all(session=db.session).filter(Room.name.contains(query)) if limit: @@ -35,7 +40,8 @@ async def get_rooms(query: str = "", limit: int = 10, offset: int = 0) -> GetLis ) -@room_router.post("/", response_model=RoomGet) +@room_router.post("/", response_model=RoomGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.post("/", response_model=RoomGet) async def create_room(room: RoomPost, _: auth.User = Depends(auth.get_current_user)) -> RoomGet: if bool( Room.get_all(session=db.session).filter(Room.name == room.name, Room.building == room.building).one_or_none() @@ -46,7 +52,8 @@ async def create_room(room: RoomPost, _: auth.User = Depends(auth.get_current_us return RoomGet.from_orm(db_room) -@room_router.patch("/{id}", response_model=RoomGet) +@room_router.patch("/{id}", response_model=RoomGet) # DEPRICATED TODO: Drop 2023-04-01 +@router.patch("/{id}", response_model=RoomGet) async def patch_room(id: int, room_inp: RoomPatch, _: auth.User = Depends(auth.get_current_user)) -> RoomGet: room = ( Room.get_all(session=db.session) @@ -60,7 +67,8 @@ async def patch_room(id: int, room_inp: RoomPatch, _: auth.User = Depends(auth.g return RoomGet.from_orm(patched) -@room_router.delete("/{id}", response_model=None) +@room_router.delete("/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01 +@router.delete("/{id}", response_model=None) async def delete_room(id: int, _: auth.User = Depends(auth.get_current_user)) -> None: Room.delete(id, session=db.session) db.session.commit() diff --git a/calendar_backend/settings.py b/calendar_backend/settings.py index 5fb4bb38..ec10723e 100644 --- a/calendar_backend/settings.py +++ b/calendar_backend/settings.py @@ -1,7 +1,7 @@ import os from functools import lru_cache -from pydantic import BaseSettings, PostgresDsn, AnyHttpUrl, DirectoryPath, Json +from pydantic import AnyHttpUrl, BaseSettings, DirectoryPath, Json, PostgresDsn class Settings(BaseSettings): diff --git a/migrations/env.py b/migrations/env.py index 3818bf8d..54d9554c 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -1,12 +1,12 @@ from logging.config import fileConfig -from sqlalchemy import engine_from_config -from sqlalchemy import pool - from alembic import context +from sqlalchemy import engine_from_config, pool + from calendar_backend.models.base import DeclarativeBase from calendar_backend.settings import get_settings + # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config diff --git a/migrations/versions/0929a0a9586e_del_link.py b/migrations/versions/0929a0a9586e_del_link.py index a47c65aa..d975a53d 100644 --- a/migrations/versions/0929a0a9586e_del_link.py +++ b/migrations/versions/0929a0a9586e_del_link.py @@ -5,8 +5,8 @@ Create Date: 2022-08-26 22:06:12.799690 """ -from alembic import op import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. diff --git a/migrations/versions/6d57978a236e_room_building.py b/migrations/versions/6d57978a236e_room_building.py index 03581042..72363b0e 100644 --- a/migrations/versions/6d57978a236e_room_building.py +++ b/migrations/versions/6d57978a236e_room_building.py @@ -5,8 +5,8 @@ Create Date: 2022-11-15 14:28:24.824017 """ -from alembic import op import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. diff --git a/migrations/versions/8bae03e22feb_many_to_many.py b/migrations/versions/8bae03e22feb_many_to_many.py index a6e018d4..2c78e367 100644 --- a/migrations/versions/8bae03e22feb_many_to_many.py +++ b/migrations/versions/8bae03e22feb_many_to_many.py @@ -5,8 +5,8 @@ Create Date: 2022-08-19 03:29:18.184129 """ -from alembic import op import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. diff --git a/migrations/versions/93612883178c_init.py b/migrations/versions/93612883178c_init.py index cfd37918..eacb08b3 100644 --- a/migrations/versions/93612883178c_init.py +++ b/migrations/versions/93612883178c_init.py @@ -5,8 +5,8 @@ Create Date: 2022-08-17 15:40:32.047879 """ -from alembic import op import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. diff --git a/migrations/versions/b0d96bbca3cd_add_review.py b/migrations/versions/b0d96bbca3cd_add_review.py index c2f9d7a6..a5f025ab 100644 --- a/migrations/versions/b0d96bbca3cd_add_review.py +++ b/migrations/versions/b0d96bbca3cd_add_review.py @@ -1,5 +1,5 @@ -from alembic import op import sqlalchemy as sa +from alembic import op revision = 'b0d96bbca3cd' diff --git a/migrations/versions/c66359fe2d1e_photo_comment_is_deleted_flag.py b/migrations/versions/c66359fe2d1e_photo_comment_is_deleted_flag.py index d2f404f9..b2c95821 100644 --- a/migrations/versions/c66359fe2d1e_photo_comment_is_deleted_flag.py +++ b/migrations/versions/c66359fe2d1e_photo_comment_is_deleted_flag.py @@ -5,8 +5,8 @@ Create Date: 2022-08-25 21:14:35.470992 """ -from alembic import op import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. diff --git a/migrations/versions/d6f98271bc6b_no_datatype_directions.py b/migrations/versions/d6f98271bc6b_no_datatype_directions.py index 8bf4559b..c41c2b4c 100644 --- a/migrations/versions/d6f98271bc6b_no_datatype_directions.py +++ b/migrations/versions/d6f98271bc6b_no_datatype_directions.py @@ -5,8 +5,8 @@ Create Date: 2022-08-20 02:44:28.203133 """ -from alembic import op import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. diff --git a/migrations/versions/e111af54f4bb_refactoring.py b/migrations/versions/e111af54f4bb_refactoring.py index 354502fe..fb15ef99 100644 --- a/migrations/versions/e111af54f4bb_refactoring.py +++ b/migrations/versions/e111af54f4bb_refactoring.py @@ -6,8 +6,7 @@ """ from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import postgresql + # revision identifiers, used by Alembic. revision = 'e111af54f4bb' diff --git a/requirements.txt b/requirements.txt index 1e35daad..506a4c4e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,4 @@ gunicorn python-multipart httpx Pillow -logging-profcomff \ No newline at end of file +logging-profcomff diff --git a/tests/conftest.py b/tests/conftest.py index 9335c9bd..b4fa5516 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -39,7 +39,7 @@ def dbsession(): @pytest.fixture() def room_path(client_auth: TestClient, dbsession: Session): - RESOURCE = "/timetable/room/" + RESOURCE = "/room/" request_obj = { "name": datetime.now().isoformat(), "direction": "North", @@ -55,7 +55,7 @@ def room_path(client_auth: TestClient, dbsession: Session): @pytest.fixture() def group_path(client_auth: TestClient, dbsession: Session): - RESOURCE = "/timetable/group/" + RESOURCE = "/group/" request_obj = { "name": "", "number": datetime.now().isoformat(), @@ -71,7 +71,7 @@ def group_path(client_auth: TestClient, dbsession: Session): @pytest.fixture() def lecturer_path(client_auth: TestClient, dbsession: Session): - RESOURCE = "/timetable/lecturer/" + RESOURCE = "/lecturer/" request_obj = { "first_name": "Петр", "middle_name": "Васильевич", @@ -101,11 +101,9 @@ def photo_path(client_auth: TestClient, dbsession: Session, lecturer_path: str): dbsession.commit() - - @pytest.fixture() def event_path(client_auth: TestClient, dbsession: Session, lecturer_path, room_path, group_path): - RESOURCE = f"/timetable/event/" + RESOURCE = f"/event/" room_id = int(room_path.split("/")[-1]) group_id = int(group_path.split("/")[-1]) lecturer_id = int(lecturer_path.split("/")[-1]) @@ -130,7 +128,7 @@ def room_factory(dbsession: Session): ids_ = [] def _room_factory(client_auth: TestClient): - RESOURCE = "/timetable/room/" + RESOURCE = "/room/" request_obj = { "name": datetime.now().isoformat(), "direction": "North", @@ -153,7 +151,7 @@ def lecturer_factory(dbsession: Session): ids_ = [] def _lecturer_factory(client_auth: TestClient): - RESOURCE = "/timetable/lecturer/" + RESOURCE = "/lecturer/" request_obj = { "first_name": "Петр", "middle_name": "Васильевич", @@ -178,7 +176,7 @@ def group_factory(dbsession: Session): ids_ = [] def _group_factory(client_auth: TestClient): - RESOURCE = "/timetable/group/" + RESOURCE = "/group/" request_obj = { "name": "", "number": datetime.now().isoformat(), diff --git a/tests/event/event.py b/tests/event/event.py index a9ddc82b..66e0e7b9 100644 --- a/tests/event/event.py +++ b/tests/event/event.py @@ -1,11 +1,14 @@ -from fastapi.testclient import TestClient import datetime +from urllib.parse import urljoin + +from fastapi.testclient import TestClient from sqlalchemy.orm import Session from starlette import status -from calendar_backend.models import Event, Room, Lecturer, Group +from calendar_backend.models import Event, Group, Lecturer, Room + -RESOURCE = "/timetable/event/" +RESOURCE = "/event/" def test_create(client_auth: TestClient, dbsession: Session, room_path, group_path, lecturer_path): @@ -119,11 +122,11 @@ def test_delete(client_auth: TestClient, dbsession: Session, room_path, lecturer id_ = response_obj['id'] # Delete - response = client_auth.delete(RESOURCE + f"{id_}") + response = client_auth.delete(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_404_NOT_FOUND, response.json() # Read all @@ -177,7 +180,7 @@ def test_update_all(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] @@ -196,8 +199,8 @@ def test_update_all(client_auth: TestClient, dbsession: Session): "start_ts": "2022-08-26T22:32:38.575Z", "end_ts": "2022-08-26T22:32:38.575Z", } - client_auth.patch(RESOURCE + f"{id_}", json=request_obj_2) - response = client_auth.get(RESOURCE + f"{id_}/") + client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj_2["name"] diff --git a/tests/group/group.py b/tests/group/group.py index 016e627b..42b4a995 100644 --- a/tests/group/group.py +++ b/tests/group/group.py @@ -1,4 +1,6 @@ from datetime import datetime +from urllib.parse import urljoin + from fastapi.testclient import TestClient from sqlalchemy.orm import Session from starlette import status @@ -6,7 +8,7 @@ from calendar_backend.models import Group -RESOURCE = "/timetable/group/" +RESOURCE = "/group/" def test_create(client_auth: TestClient, dbsession: Session): @@ -39,7 +41,7 @@ def test_read(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] @@ -66,18 +68,18 @@ def test_delete(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] assert response_obj["number"] == request_obj["number"] # Delete - response = client_auth.delete(RESOURCE + f"{id_}") + response = client_auth.delete(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_404_NOT_FOUND, response.json() # Read all @@ -108,7 +110,7 @@ def test_update_name(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] @@ -118,8 +120,8 @@ def test_update_name(client_auth: TestClient, dbsession: Session): request_obj_2 = { "name": "Hello", } - response = client_auth.patch(RESOURCE + f"{id_}", json=request_obj_2) - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj_2["name"] @@ -155,7 +157,7 @@ def test_update_all(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] @@ -163,8 +165,8 @@ def test_update_all(client_auth: TestClient, dbsession: Session): # Update request_obj_2 = {"name": "HelloWorld", "number": "test105" + datetime.utcnow().isoformat()} - client_auth.patch(RESOURCE + f"{id_}", json=request_obj_2) - response = client_auth.get(RESOURCE + f"{id_}") + client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj_2["name"] diff --git a/tests/lecturer/lecturer.py b/tests/lecturer/lecturer.py index ca9d42bc..631a012d 100644 --- a/tests/lecturer/lecturer.py +++ b/tests/lecturer/lecturer.py @@ -1,3 +1,5 @@ +from urllib.parse import urljoin + from fastapi.testclient import TestClient from sqlalchemy.orm import Session from starlette import status @@ -5,7 +7,7 @@ from calendar_backend.models.db import Lecturer -RESOURCE = "/timetable/lecturer/" +RESOURCE = "/lecturer/" def test_create(client_auth: TestClient, dbsession: Session): @@ -61,7 +63,7 @@ def test_read(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj: dict = response.json() assert { @@ -114,7 +116,7 @@ def test_delete(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj: dict = response.json() assert { @@ -134,11 +136,11 @@ def test_delete(client_auth: TestClient, dbsession: Session): } == set(response_obj.keys()) # Delete - response = client_auth.delete(RESOURCE + f"{id_}") + response = client_auth.delete(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == 404, response.json() # Read all @@ -182,7 +184,7 @@ def test_update_name(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert { @@ -197,8 +199,8 @@ def test_update_name(client_auth: TestClient, dbsession: Session): "first_name": "Hello", } request_obj.update(request_obj_2) - response = client_auth.patch(RESOURCE + f"{id_}", json=request_obj_2) - response = client_auth.get(RESOURCE + f"{id_}") + response = client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["first_name"] == request_obj_2["first_name"] @@ -249,7 +251,7 @@ def test_update_all(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert { @@ -267,9 +269,9 @@ def test_update_all(client_auth: TestClient, dbsession: Session): "description": "Третья попытка", } request_obj.update(request_obj_2) - client_auth.patch(RESOURCE + f"{id_}", json=request_obj_2) + client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) assert response.status_code == status.HTTP_200_OK, response.json() - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert { diff --git a/tests/lecturer/photos.py b/tests/lecturer/photos.py index a221223d..71720a8c 100644 --- a/tests/lecturer/photos.py +++ b/tests/lecturer/photos.py @@ -5,6 +5,7 @@ from calendar_backend.settings import get_settings + settings = get_settings() settings.STATIC_PATH = './static' @@ -41,4 +42,3 @@ def test_corrupted_file(lecturer_path: str, client_auth: TestClient): with open(os.path.dirname(__file__) + "/broken_photo.png", "rb") as f: response = client_auth.post(RESOURCE, files={"photo": f}) assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - diff --git a/tests/room/room.py b/tests/room/room.py index c864b36f..aef49872 100644 --- a/tests/room/room.py +++ b/tests/room/room.py @@ -1,4 +1,5 @@ import datetime +from urllib.parse import urljoin from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -6,7 +7,8 @@ from calendar_backend.models import Room -RESOURCE = "/timetable/room/" + +RESOURCE = "/room/" def test_create(client_auth: TestClient, dbsession: Session): @@ -32,7 +34,7 @@ def test_read(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] @@ -59,17 +61,17 @@ def test_delete(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] assert response_obj["direction"] == request_obj["direction"] # Delete - response = client_auth.delete(RESOURCE + f"{id_}") + response = client_auth.delete(urljoin(RESOURCE, str(id_))) # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_404_NOT_FOUND, response.json() # Read all @@ -99,7 +101,7 @@ def test_update_all(client_auth: TestClient, dbsession: Session): id_ = response_obj['id'] # Read - response = client_auth.get(RESOURCE + f"{id_}/") + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj["name"] @@ -107,8 +109,8 @@ def test_update_all(client_auth: TestClient, dbsession: Session): # Update request_obj_2 = {"name": "" + datetime.datetime.utcnow().isoformat(), "direction": "North"} - client_auth.patch(RESOURCE + f"{id_}", json=request_obj_2) - response = client_auth.get(RESOURCE + f"{id_}") + client_auth.patch(urljoin(RESOURCE, str(id_)), json=request_obj_2) + response = client_auth.get(urljoin(RESOURCE, str(id_))) assert response.status_code == status.HTTP_200_OK, response.json() response_obj = response.json() assert response_obj["name"] == request_obj_2["name"]