diff --git a/.gitignore b/.gitignore index 68ea2beb..19a84231 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,4 @@ dmypy.json # Pyre type checker .pyre/ +.idea/ diff --git a/app/database/models.py b/app/database/models.py index 0c92ae94..ac66267d 100644 --- a/app/database/models.py +++ b/app/database/models.py @@ -30,5 +30,5 @@ class Event(Base): start = Column(DateTime, nullable=False) end = Column(DateTime, nullable=False) owner_id = Column(Integer, ForeignKey("users.id")) - + invitees = Column(String) owner = relationship("User", back_populates="events") diff --git a/app/routers/event.py b/app/routers/event.py index f2a0b2dc..01ff3211 100644 --- a/app/routers/event.py +++ b/app/routers/event.py @@ -1,7 +1,16 @@ -from fastapi import APIRouter, Request +import re +from datetime import datetime as dt +from fastapi import APIRouter, Request, Depends, HTTPException +from fastapi.responses import RedirectResponse +from starlette.status import HTTP_303_SEE_OTHER +from app.database.database import get_db +from app.database.models import Event, User from app.dependencies import templates +ZOOM_REGEX = re.compile(r'https://.*?\.zoom.us/[a-z]/.[^.,\b\t\n]+') +VALID_MAIL_REGEX = re.compile(r'^\S+@\S+\.\S+$') + router = APIRouter( prefix="/event", tags=["event"], @@ -15,7 +24,58 @@ async def eventedit(request: Request): {"request": request}) +@router.post("/edit") +async def create_event(request: Request, session=Depends(get_db)): + data = await request.form() + title = data['title'] + content = data['description'] + start = dt.strptime(data['start_date'] + ' ' + data['start_time'], + '%Y-%m-%d %H:%M') + end = dt.strptime(data['end_date'] + ' ' + data['end_time'], + '%Y-%m-%d %H:%M') + user = session.query(User).filter_by(id=1).first() + if not user: + user = User( + username='new_user', + email='my@email.po', + password='1a2s3d4f5g6', + ) + owner_id = user.id + location_type = data['location_type'] + is_zoom = location_type == 'vc_url' + location = data['location'] + + if is_zoom and not ZOOM_REGEX.findall(location): + raise HTTPException(status_code=400, + detail="VC type with no valid zoom link") + + invitees = [] + for invited_mail in data['invited'].split(','): + invited_mail = invited_mail.strip() + if VALID_MAIL_REGEX.fullmatch(invited_mail): + invitees.append(invited_mail) + + event = Event(title=title, content=content, start=start, end=end, + owner_id=owner_id, invitees=','.join(invitees)) + + regular_invitees = set() + for record in session.query(Event).with_entities(Event.invitees).filter(Event.owner_id == owner_id, + Event.title == title).all(): + for email in record[0].split(','): + regular_invitees.add(email) + + uninvited_contacts = regular_invitees.difference(set(invitees)) + + session.add(event) + session.commit() + + message = f'Forgot to invite {", ".join(uninvited_contacts)} maybe?' + return RedirectResponse(f'/event/view/{event.id}?message={message}', + status_code=HTTP_303_SEE_OTHER) + + @router.get("/view/{id}") async def eventview(request: Request, id: int): + message = request.query_params.get('message', '') return templates.TemplateResponse("event/eventview.html", - {"request": request, "event_id": id}) + {"request": request, "event_id": id, "message": message}) diff --git a/app/templates/event/eventview.html b/app/templates/event/eventview.html index dc343a01..bb694a26 100644 --- a/app/templates/event/eventview.html +++ b/app/templates/event/eventview.html @@ -8,6 +8,9 @@
+
+

{{ message }}

+
diff --git a/app/templates/event/partials/edit_event_details_tab.html b/app/templates/event/partials/edit_event_details_tab.html index 4c682c3e..16ebb584 100644 --- a/app/templates/event/partials/edit_event_details_tab.html +++ b/app/templates/event/partials/edit_event_details_tab.html @@ -21,6 +21,10 @@ +
+ +
+
diff --git a/tests/test_event.py b/tests/test_event.py index d50bd567..d2adbf84 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -1,7 +1,40 @@ +from urllib.parse import urlparse + from fastapi.testclient import TestClient +from starlette.status import HTTP_303_SEE_OTHER from app.main import app +CORRECT_EVENT_FORM_DATA = { + 'title': 'test title', + 'start_date': '2021-01-28', + 'start_time': '15:59', + 'end_date': '2021-01-27', + 'end_time': '15:01', + 'location_type': 'vc_url', + 'location': 'https://us02web.zoom.us/j/875384596', + 'description': 'content', + 'color': 'red', + 'availability': 'busy', + 'privacy': 'public', + 'invited': 'a@a.com,b@b.com' +} + +WRONG_EVENT_FORM_DATA = { + 'title': 'test title', + 'start_date': '2021-01-28', + 'start_time': '15:59', + 'end_date': '2021-01-27', + 'end_time': '15:01', + 'location_type': 'vc_url', + 'location': 'not a zoom link', + 'description': 'content', + 'color': 'red', + 'availability': 'busy', + 'privacy': 'public', + 'invited': 'a@a.com,b@b.com' +} + client = TestClient(app) @@ -11,6 +44,29 @@ def test_eventedit(): assert b"Edit Event" in response.content +def test_eventedit_post_correct(user): + response = client.post("/event/edit", data=CORRECT_EVENT_FORM_DATA) + assert response.status_code == HTTP_303_SEE_OTHER + assert '/event/view/' in response.headers['location'] + + +def test_eventedit_post_wrong(user): + response = client.post("/event/edit", data=WRONG_EVENT_FORM_DATA) + assert response.json()['detail'] == 'VC type with no valid zoom link' + + +def test_eventedit_missing_old_invites(user): + response = client.post("/event/edit", data=CORRECT_EVENT_FORM_DATA) + assert response.status_code == HTTP_303_SEE_OTHER + + same_event_with_different_invitees = CORRECT_EVENT_FORM_DATA.copy() + same_event_with_different_invitees['invited'] = 'c@c.com,d@d.com' + response = client.post("/event/edit", data=same_event_with_different_invitees) + assert response.status_code == HTTP_303_SEE_OTHER + assert f'Forgot to invite {", ".join(CORRECT_EVENT_FORM_DATA["invited"].split(","))} maybe?' in \ + response.headers['location'].replace('+', ' ') + + def test_eventview_with_id(): response = client.get("/event/view/1") assert response.status_code == 200