|
1 | 1 | import logging |
2 | | -from datetime import date, timedelta |
| 2 | +from datetime import date, datetime, timedelta |
3 | 3 | from typing import Literal |
4 | 4 |
|
5 | 5 | from auth_lib.fastapi import UnionAuth |
6 | | -from fastapi import APIRouter, Depends, Query |
7 | | -from fastapi.responses import FileResponse |
| 6 | +from fastapi import APIRouter, Depends, Query, status |
| 7 | +from fastapi.responses import FileResponse, JSONResponse |
8 | 8 | from fastapi_sqlalchemy import db |
9 | 9 | from pydantic import TypeAdapter |
10 | 10 |
|
11 | 11 | from calendar_backend.exceptions import NotEnoughCriteria |
12 | 12 | from calendar_backend.methods import list_calendar |
13 | 13 | from calendar_backend.models import Event, Group, Lecturer, Room |
14 | 14 | from calendar_backend.routes.models import EventGet |
15 | | -from calendar_backend.routes.models.event import EventPatch, EventPost, GetListEvent |
| 15 | +from calendar_backend.routes.models.event import ( |
| 16 | + EventPatch, |
| 17 | + EventPatchName, |
| 18 | + EventPatchResult, |
| 19 | + EventPost, |
| 20 | + EventRepeatedPost, |
| 21 | + GetListEvent, |
| 22 | +) |
16 | 23 | from calendar_backend.settings import get_settings |
17 | 24 |
|
18 | 25 |
|
@@ -98,6 +105,44 @@ async def create_event(event: EventPost, _=Depends(UnionAuth(scopes=["timetable. |
98 | 105 | return EventGet.model_validate(event_get) |
99 | 106 |
|
100 | 107 |
|
| 108 | +@router.post("/repeating", response_model=list[EventGet]) |
| 109 | +async def create_repeating_event( |
| 110 | + event: EventRepeatedPost, # _=Depends(UnionAuth(scopes=["timetable.event.create"])) |
| 111 | +) -> list[EventGet]: |
| 112 | + if event.repeat_timedelta_days <= 0: |
| 113 | + return JSONResponse( |
| 114 | + status_code=status.HTTP_400_BAD_REQUEST, content={"detail": f"Timedelta must be a positive integer"} |
| 115 | + ) |
| 116 | + if event.repeat_until_ts > event.start_ts + timedelta(days=1095): |
| 117 | + return JSONResponse( |
| 118 | + status_code=status.HTTP_400_BAD_REQUEST, |
| 119 | + content={"detail": "Due to disk utilization limits, events with duration > 3 years is restricted"}, |
| 120 | + ) |
| 121 | + events = [] |
| 122 | + event_dict = event.model_dump() |
| 123 | + rooms = [Room.get(room_id, session=db.session) for room_id in event_dict.pop("room_id", [])] |
| 124 | + lecturers = [Lecturer.get(lecturer_id, session=db.session) for lecturer_id in event_dict.pop("lecturer_id", [])] |
| 125 | + groups = [Group.get(group_id, session=db.session) for group_id in event_dict.pop("group_id", [])] |
| 126 | + repeat_timedelta_days = timedelta(days=event.repeat_timedelta_days) |
| 127 | + cur_start_ts = event_dict["start_ts"] |
| 128 | + cur_end_ts = event_dict["end_ts"] |
| 129 | + while cur_start_ts <= event.repeat_until_ts: |
| 130 | + event_get = Event.create( |
| 131 | + name=event_dict["name"], |
| 132 | + start_ts=cur_start_ts, |
| 133 | + end_ts=cur_end_ts, |
| 134 | + room=rooms, |
| 135 | + lecturer=lecturers, |
| 136 | + group=groups, |
| 137 | + session=db.session, |
| 138 | + ) |
| 139 | + events.append(event_get) |
| 140 | + cur_start_ts += repeat_timedelta_days |
| 141 | + cur_end_ts += repeat_timedelta_days |
| 142 | + adapter = TypeAdapter(list[EventGet]) |
| 143 | + return adapter.validate_python(events) |
| 144 | + |
| 145 | + |
101 | 146 | @router.post("/bulk", response_model=list[EventGet]) |
102 | 147 | async def create_events( |
103 | 148 | events: list[EventPost], _=Depends(UnionAuth(scopes=["timetable.event.create"])) |
@@ -139,6 +184,17 @@ async def create_events( |
139 | 184 | return adapter.validate_python(result) |
140 | 185 |
|
141 | 186 |
|
| 187 | +@router.patch("/patch_name", response_model=EventPatchResult, summary="Batch update events by name") |
| 188 | +async def patch_event_by_name( |
| 189 | + event_inp: EventPatchName, _=Depends(UnionAuth(scopes=["timetable.event.update"])) |
| 190 | +) -> EventPatchResult: |
| 191 | + updated = ( |
| 192 | + db.session.query(Event).filter(Event.name == event_inp.old_name).update(values={"name": event_inp.new_name}) |
| 193 | + ) |
| 194 | + db.session.commit() |
| 195 | + return EventPatchResult(old_name=event_inp.old_name, new_name=event_inp.new_name, updated=updated) |
| 196 | + |
| 197 | + |
142 | 198 | @router.patch("/{id}", response_model=EventGet) |
143 | 199 | async def patch_event( |
144 | 200 | id: int, event_inp: EventPatch, _=Depends(UnionAuth(scopes=["timetable.event.update"])) |
|
0 commit comments