Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build_and_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ jobs:
--network=web \
--volume com_profcomff_api_timetable_test_static:/app/static \
--env DB_DSN=${{ secrets.DB_DSN }} \
--env AUTH_URL='https://api.test.profcomff.com/auth' \
--env ROOT_PATH='/timetable' \
--env GUNICORN_CMD_ARGS='--log-config logging_test.conf' \
--env GOOGLE_CLIENT_SECRET='${{ secrets.GOOGLE_CLIENT_SECRET }}' \
Expand Down Expand Up @@ -132,6 +133,7 @@ jobs:
--network=web \
--volume com_profcomff_api_timetable_static:/app/static \
--env DB_DSN='${{ secrets.DB_DSN }}' \
--env AUTH_URL='https://api.profcomff.com/auth' \
--env ROOT_PATH='/timetable' \
--env ADMIN_SECRET='${{ secrets.ADMIN_SECRET }}' \
--env REDIRECT_URL='https://www.profcomff.com/timetable/google' \
Expand Down
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
run:
source ./venv/bin/activate && uvicorn --reload --log-level debug calendar_backend.routes.base:app

configure: venv
source ./venv/bin/activate && pip install -r requirements.dev.txt -r requirements.txt

venv:
python3.11 -m venv venv

format:
autoflake -r --in-place --remove-all-unused-imports ./calendar_backend
isort ./calendar_backend
black ./calendar_backend

db:
docker run -d -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust --name db-timetable_api postgres:15

Expand Down
7 changes: 2 additions & 5 deletions calendar_backend/methods/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
from . import auth, utils
from . import utils


__all__ = [
"utils",
"auth",
]
__all__ = ("utils",)
41 changes: 0 additions & 41 deletions calendar_backend/methods/auth.py

This file was deleted.

27 changes: 0 additions & 27 deletions calendar_backend/routes/auth.py

This file was deleted.

11 changes: 2 additions & 9 deletions calendar_backend/routes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from calendar_backend.exceptions import ForbiddenAction, NotEnoughCriteria, ObjectNotFound
from calendar_backend.settings import get_settings

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
Expand Down Expand Up @@ -52,22 +51,17 @@
description=dedent(
"""
API для работы с календарем физфака.

Пример работы на питоне(Создание Room):
```python
import reqests, json
url=f"https://api.test.profcomff.com/timetable"

# Авторизация
beaver = requests.post(f"{url}/token", {"username": "...", "password": "..."})

# Парсинг ответа
auth_data=json.loads(beaver.content)

# Создание
create_room = requests.post(
f"{url}/room",
json={"name": "test", "direction": "South"},
headers={"Authorization": f"Bearer {auth_data.get('access_token')}"}
headers={"Authorization": f"ТокенАвторизацииТвойФФ"}
)
```
"""
Expand Down Expand Up @@ -141,7 +135,6 @@ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -
# 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)
Expand Down
30 changes: 16 additions & 14 deletions calendar_backend/routes/event/comment.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from auth_lib.fastapi import UnionAuth
from fastapi import APIRouter, Depends
from fastapi_sqlalchemy import db

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, EventCommentPatch, EventCommentPost, EventComments
Expand All @@ -11,12 +11,12 @@

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 = APIRouter(prefix="/timetable/event/{event_id}/comment", tags=["Event: Comment"], deprecated=True)
router = APIRouter(prefix="/event/{event_id}/comment", tags=["Event: Comment"])


@event_comment_router.post("/comment/", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01
@router.post("/comment/", response_model=CommentEventGet)
@event_comment_router.post("/", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01
@router.post("/", 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(
Expand All @@ -26,8 +26,8 @@ async def comment_event(event_id: int, comment: EventCommentPost) -> CommentEven
return CommentEventGet.from_orm(comment_event)


@event_comment_router.patch("/comment/{id}", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01
@router.patch("/comment/{id}", response_model=CommentEventGet)
@event_comment_router.patch("/{id}", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01
@router.patch("/{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:
Expand All @@ -39,18 +39,20 @@ async def update_comment(id: int, event_id: int, comment_inp: EventCommentPatch)
return CommentEventGet.from_orm(comment_event)


@event_comment_router.get("/comment/{id}", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01
@router.get("/comment/{id}", response_model=CommentEventGet)
@event_comment_router.get("/{id}", response_model=CommentEventGet) # DEPRICATED TODO: Drop 2023-04-01
@router.get("/{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:
raise ObjectNotFound(DbCommentEvent, id)
return CommentEventGet.from_orm(comment)


@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:
@event_comment_router.delete("/{id}", response_model=None) # DEPRICATED TODO: Drop 2023-04-01
@router.delete("/{id}", response_model=None)
async def delete_comment(
id: int, event_id: int, _=Depends(UnionAuth(scopes=["timetable.event.comment.delete"]))
) -> None:
comment = DbCommentEvent.get(id, only_approved=False, session=db.session)
if comment.event_id != event_id or comment.approve_status != ApproveStatuses.APPROVED:
raise ObjectNotFound(DbCommentEvent, id)
Expand All @@ -59,8 +61,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) # DEPRICATED TODO: Drop 2023-04-01
@router.get("/comment/", response_model=EventComments)
@event_comment_router.get("/", response_model=EventComments) # DEPRICATED TODO: Drop 2023-04-01
@router.get("/", 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:
Expand Down
6 changes: 3 additions & 3 deletions calendar_backend/routes/event/comment_review.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Literal

from auth_lib.fastapi import UnionAuth
from fastapi import APIRouter, Depends
from fastapi_sqlalchemy import db
from pydantic import parse_obj_as

from calendar_backend.exceptions import 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
Expand All @@ -23,7 +23,7 @@
@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)
event_id: int, _=Depends(UnionAuth(scopes=["timetable.event.comment.review"]))
) -> list[CommentEventGet]:
comments = (
DbCommentEvent.get_all(session=db.session, only_approved=False)
Expand All @@ -39,7 +39,7 @@ async def review_comment(
id: int,
event_id: int,
action: Literal[ApproveStatuses.APPROVED, ApproveStatuses.DECLINED] = ApproveStatuses.DECLINED,
_: auth.User = Depends(auth.get_current_user),
_=Depends(UnionAuth(scopes=["timetable.event.comment.review"])),
) -> CommentEventGet:
comment = DbCommentEvent.get(id, only_approved=False, session=db.session)
if comment.event_id != event_id or comment.approve_status is not ApproveStatuses.PENDING:
Expand Down
17 changes: 11 additions & 6 deletions calendar_backend/routes/event/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from datetime import date, timedelta
from typing import Literal

from auth_lib.fastapi import UnionAuth
from fastapi import APIRouter, Depends, Query
from fastapi.responses import FileResponse
from fastapi_sqlalchemy import db
from pydantic import parse_obj_as

from calendar_backend.exceptions import NotEnoughCriteria
from calendar_backend.methods import auth, list_calendar
from calendar_backend.methods import list_calendar
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
Expand Down Expand Up @@ -88,7 +89,7 @@ async def get_events(

@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:
async def create_event(event: EventPost, _=Depends(UnionAuth(scopes=["timetable.event.create"]))) -> 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", [])]
Expand All @@ -106,7 +107,9 @@ async def create_event(event: EventPost, _: auth.User = Depends(auth.get_current

@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]:
async def create_events(
events: list[EventPost], _=Depends(UnionAuth(scopes=["timetable.event.create"]))
) -> list[EventGet]:
result = []
for event in events:
event_dict = event.dict()
Expand All @@ -128,21 +131,23 @@ async def create_events(events: list[EventPost], _: auth.User = Depends(auth.get

@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:
async def patch_event(
id: int, event_inp: EventPatch, _=Depends(UnionAuth(scopes=["timetable.event.update"]))
) -> 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) # 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:
async def delete_events(start: date, end: date, _=Depends(UnionAuth(scopes=["timetable.event.delete"]))) -> None:
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) # 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:
async def delete_event(id: int, _=Depends(UnionAuth(scopes=["timetable.event.delete"]))) -> None:
Event.delete(id, session=db.session)
db.session.commit()
8 changes: 4 additions & 4 deletions calendar_backend/routes/group/group.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import logging

from auth_lib.fastapi import UnionAuth
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 GetListGroup, GroupGet, GroupPatch, GroupPost
from calendar_backend.settings import get_settings
Expand Down Expand Up @@ -42,7 +42,7 @@ async def get_groups(query: str = "", limit: int = 10, offset: int = 0) -> GetLi

@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:
async def create_group(group: GroupPost, _=Depends(UnionAuth(scopes=["timetable.group.create"]))) -> GroupGet:
if db.session.query(Group).filter(Group.number == group.number).one_or_none():
raise HTTPException(status_code=423, detail="Already exists")
group = Group.create(**group.dict(), session=db.session)
Expand All @@ -55,7 +55,7 @@ async def create_group(group: GroupPost, _: auth.User = Depends(auth.get_current
async def patch_group(
id: int,
group_inp: GroupPatch,
_: auth.User = Depends(auth.get_current_user),
_=Depends(UnionAuth(scopes=["timetable.group.update"])),
) -> GroupGet:
if (
bool(query := Group.get_all(session=db.session).filter(Group.number == group_inp.number).one_or_none())
Expand All @@ -69,6 +69,6 @@ async def patch_group(

@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:
async def delete_group(id: int, _=Depends(UnionAuth(scopes=["timetable.group.delete"]))) -> None:
Group.delete(id, session=db.session)
db.session.commit()
6 changes: 4 additions & 2 deletions calendar_backend/routes/lecturer/comment.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from auth_lib.fastapi import UnionAuth
from fastapi import APIRouter, Depends
from fastapi_sqlalchemy import db

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, LecturerCommentPatch, LecturerCommentPost, LecturerComments
Expand Down Expand Up @@ -48,7 +48,9 @@ async def update_comment_lecturer(id: int, lecturer_id: int, comment_inp: Lectur

@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:
async def delete_comment(
id: int, lecturer_id: int, _=Depends(UnionAuth(scopes=["timetable.lecturer.comment.delete"]))
) -> None:
comment = DbCommentLecturer.get(id, only_approved=False, session=db.session)
if comment.lecturer_id != lecturer_id:
raise ObjectNotFound(DbCommentLecturer, id)
Expand Down
Loading