1- from datetime import datetime as dt
1+ from datetime import datetime
22from operator import attrgetter
33from typing import Any , Dict , List , Optional
44
5- from fastapi import APIRouter , Depends , Request
5+ from fastapi import APIRouter , Depends , HTTPException , Request
6+ from loguru import logger
67from sqlalchemy .exc import SQLAlchemyError
78from sqlalchemy .orm import Session
89from starlette import status
910from starlette .responses import RedirectResponse
10- from starlette .status import HTTP_302_FOUND
1111
1212from app .database .database import get_db
1313from app .database .models import Event , User , UserEvent
@@ -34,10 +34,10 @@ async def create_new_event(request: Request, session=Depends(get_db)):
3434 data = await request .form ()
3535 title = data ['title' ]
3636 content = data ['description' ]
37- start = dt .strptime (data ['start_date' ] + ' ' + data ['start_time' ],
38- '%Y-%m-%d %H:%M' )
39- end = dt .strptime (data ['end_date' ] + ' ' + data ['end_time' ],
40- '%Y-%m-%d %H:%M' )
37+ start = datetime .strptime (data ['start_date' ] + ' ' + data ['start_time' ],
38+ '%Y-%m-%d %H:%M' )
39+ end = datetime .strptime (data ['end_date' ] + ' ' + data ['end_time' ],
40+ '%Y-%m-%d %H:%M' )
4141 user = session .query (User ).filter_by (id = 1 ).first ()
4242 user = user if user else create_user ("u" , "p" , "e@mail.com" , session )
4343 owner_id = user .id
@@ -51,7 +51,7 @@ async def create_new_event(request: Request, session=Depends(get_db)):
5151 event = create_event (session , title , start , end , owner_id , content ,
5252 location )
5353 return RedirectResponse (router .url_path_for ('eventview' , id = event .id ),
54- status_code = HTTP_302_FOUND )
54+ status_code = status . HTTP_302_FOUND )
5555
5656
5757@router .get ("/view/{id}" )
@@ -60,43 +60,68 @@ async def eventview(request: Request, id: int):
6060 {"request" : request , "event_id" : id })
6161
6262
63+ UPDATE_EVENTS_FIELDS = {
64+ 'title' : str ,
65+ 'start' : datetime ,
66+ 'end' : datetime ,
67+ 'content' : (str , type (None )),
68+ 'location' : (str , type (None ))
69+ }
70+
71+
6372def by_id (db : Session , event_id : int ) -> Event :
6473 """Select event by id"""
6574
6675 return db .query (Event ).filter (Event .id == event_id ).first ()
6776
6877
69- def is_date_before (start_date : dt , end_date : dt ) -> bool :
78+ def is_date_before (start_date : datetime , end_date : datetime ) -> bool :
7079 """Check if the start date is earlier than the end date"""
7180
7281 return start_date < end_date
7382
7483
75- def is_it_possible_to_change_dates (
76- db : Session , old_event : Event , event : Dict [str , Any ]) -> bool :
77- return is_date_before (
78- event .get ('start' , old_event .start ),
79- event .get ('end' , old_event .end ))
84+ def is_change_dates_allowed (
85+ old_event : Event , event : Dict [str , Any ]) -> bool :
86+ try :
87+ return is_date_before (
88+ event .get ('start' , old_event .start ),
89+ event .get ('end' , old_event .end ))
90+ except TypeError :
91+ return False
92+
93+
94+ def is_fields_types_valid (to_check : Dict [str , Any ], types : Dict [str , Any ]):
95+ """validate dictionary values by dictionary of types"""
96+ errors = []
97+ for field_name , field_type in to_check .items ():
98+ if types [field_name ] and not isinstance (field_type , types [field_name ]):
99+ errors .append (
100+ f"{ field_name } is '{ type (field_type ).__name__ } ' and"
101+ + f"it should be from type '{ types [field_name ].__name__ } '" )
102+ logger .warning (errors )
103+ if errors :
104+ raise HTTPException (
105+ status_code = status .HTTP_400_BAD_REQUEST , detail = errors )
80106
81107
82- def get_items_that_can_be_updated (event : Dict [str , Any ]) -> Dict [str , Any ]:
83- """Extract only that keys to update"""
108+ def get_event_with_editable_fields_only (event : Dict [str , Any ]
109+ ) -> Dict [str , Any ]:
110+ """Remove all keys that are not allowed to update"""
84111
85- return {i : event [i ] for i in (
86- 'title' , 'start' , 'end' , 'content' , 'location' ) if i in event }
112+ return {i : event [i ] for i in UPDATE_EVENTS_FIELDS if i in event }
87113
88114
89115def update_event (event_id : int , event : Dict , db : Session
90116 ) -> Optional [Event ]:
91117 # TODO Check if the user is the owner of the event.
92118
93- event_to_update = get_items_that_can_be_updated (event )
94- if not event_to_update :
95- return None
119+ event_to_update = get_event_with_editable_fields_only (event )
120+ is_fields_types_valid (event_to_update , UPDATE_EVENTS_FIELDS )
96121 try :
97- old_event = by_id (db = db , event_id = event_id )
98- if old_event is None or not is_it_possible_to_change_dates (
99- db , old_event , event_to_update ) :
122+ old_event = by_id (db , event_id )
123+ forbidden = not is_change_dates_allowed ( old_event , event_to_update )
124+ if not event_to_update or old_event is None or forbidden :
100125 return None
101126
102127 # Update database
@@ -105,9 +130,10 @@ def update_event(event_id: int, event: Dict, db: Session
105130 db .commit ()
106131
107132 # TODO: Send emails to recipients.
108- except (AttributeError , SQLAlchemyError , TypeError ):
133+ return by_id (db , event_id )
134+ except (AttributeError , SQLAlchemyError ) as e :
135+ logger .error (str (e ))
109136 return None
110- return by_id (db = db , event_id = event_id )
111137
112138
113139def create_event (db , title , start , end , owner_id , content = None , location = None ):
@@ -149,28 +175,40 @@ def get_participants_emails_by_event(db: Session, event_id: int) -> List[str]:
149175 all ()]
150176
151177
152- @router .delete ("/{event_id}" )
153- def delete_event (request : Request ,
154- event_id : int ,
155- db : Session = Depends (get_db )):
156-
157- # TODO: Check if the user is the owner of the event.
158- event = by_id (db , event_id )
159- participants = get_participants_emails_by_event (db , event_id )
178+ def _delete_event (db : Session , event : Event ):
160179 try :
161180 # Delete event
162181 db .delete (event )
163182
164183 # Delete user_event
165- db .query (UserEvent ).filter (UserEvent .event_id == event_id ).delete ()
184+ db .query (UserEvent ).filter (UserEvent .event_id == event . id ).delete ()
166185
167186 db .commit ()
168187
169- except (SQLAlchemyError , TypeError ):
170- return templates .TemplateResponse (
171- "event/eventview.html" , {"request" : request , "event_id" : event_id },
172- status_code = status .HTTP_500_INTERNAL_SERVER_ERROR )
173- if participants and event .start > dt .now ():
188+ except (SQLAlchemyError , AttributeError ) as e :
189+ logger .error (str (e ))
190+ raise HTTPException (
191+ status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
192+ detail = "Deletion failed" )
193+
194+
195+ @router .delete ("/{event_id}" )
196+ def delete_event (event_id : int ,
197+ db : Session = Depends (get_db )):
198+
199+ # TODO: Check if the user is the owner of the event.
200+ try :
201+ event = by_id (db , event_id )
202+ except AttributeError as e :
203+ logger .error (str (e ) + "Could not connect to database" )
204+ raise HTTPException (status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
205+ detail = "Could not connect to database" )
206+ if not event :
207+ raise HTTPException (status_code = status .HTTP_404_NOT_FOUND ,
208+ detail = "The event was not found" )
209+ participants = get_participants_emails_by_event (db , event_id )
210+ _delete_event (db , event )
211+ if participants and event .start > datetime .now ():
174212 pass
175213 # TODO: Send them a cancellation notice
176214 # if the deletion is successful
0 commit comments