Skip to content
Closed
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,4 @@ dmypy.json

# Pyre type checker
.pyre/
.idea/
2 changes: 1 addition & 1 deletion app/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
64 changes: 62 additions & 2 deletions app/routers/event.py
Original file line number Diff line number Diff line change
@@ -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"],
Expand All @@ -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='[email protected]',
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})
4 changes: 4 additions & 0 deletions app/templates/event/eventview.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<body>
<div class = "event_view_wrapper">
<!-- Temporary nav layout based on bootstrap -->
<div class="forgot-to-invite">
<h2>{{ message }}</h2>
</div>
<ul class="nav nav-tabs" id="event_view_nav" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="eventdetails-tab" data-toggle="tab" href="#eventdetails" role="tab"
Expand All @@ -29,6 +32,7 @@
</div>
<!-- Copy commented section to add another tab-->
<!-- <div class="tab-pane fade" id="(CHANGE_ME)" role="tabpanel" aria-labelledby="(CHANGE_ME)-tab">-->
<!-- <div class="tab-pane fade" id="(CHANGE_ME)" role="tabpanel" aria-labelledby="(CHANGE_ME)-tab">-->
<!-- ADD INCLUDE HERE -->
<!-- </div>-->
</div>
Expand Down
4 changes: 4 additions & 0 deletions app/templates/event/partials/edit_event_details_tab.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<input type="text" name="location" placeholder="VC URL/Location">
</div>

<div class="form_row">
<input type="text" name="invited" placeholder="Invited emails, separated by commas">
</div>

<div class="form_row textarea">
<textarea name="description" placeholder="Description"></textarea>
</div>
Expand Down
56 changes: 56 additions & 0 deletions tests/test_event.py
Original file line number Diff line number Diff line change
@@ -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': '[email protected],[email protected]'
}

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': '[email protected],[email protected]'
}

client = TestClient(app)


Expand All @@ -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'] = '[email protected],[email protected]'
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
Expand Down