Skip to content

Commit

Permalink
✨ Add endpoint for sending mail to event participants
Browse files Browse the repository at this point in the history
  • Loading branch information
otytlandsvik committed Jan 31, 2024
1 parent ed7f220 commit e1246ef
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
41 changes: 41 additions & 0 deletions app/api/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,47 @@ async def get_confirmation_message(request: Request, id: str, token: AccessToken
raise HTTPException(500, "Error fetching default confirm message")


@router.post('/{id}/mail', dependencies=[Depends(validate_uuid)])
async def send_notification_mail(request: Request, id: str, m: EventMailMessage, token: AccessTokenPayload = Depends(authorize_admin)):
db = get_database(request)
event = get_event_or_404(db, id)

if len(event["participants"]) == 0:
raise HTTPException(400, "No participants in event")

if m.confirmedOnly and num_of_confirmed_participants(event["participants"]) == 0:
raise HTTPException(400, "No confirmed participants in event")

if len(m.subject) > 50:
raise HTTPException(400, "Email subject is too long")

if len(m.msg) > 5000:
raise HTTPException(400, "Email message is too long")

pipeline = [
{"$match": {"eid": event["eid"]}},
{"$unwind": {"path": "$participants"}},
{"$group": {"_id": "$participants.email"}},
]

# Only send mail to confirmed participants if specified
if m.confirmedOnly:
pipeline += [{"$match": {"participants.confirmed": True}}]

participantsToMail = db.events.aggregate(pipeline)
mailingList = [p["_id"] for p in participantsToMail]

if request.app.config.ENV == "production":
for addr in mailingList:
email = MailPayload(
to=[addr],
subject=[m.subject],
content=m.msg,
)
send_mail(email)

return Response(status_code=200)


@router.post('/{id}/confirm', dependencies=[Depends(validate_uuid)])
async def confirmation(request: Request, id: str, m: EventConfirmMessage, token: AccessTokenPayload = Depends(authorize_admin)):
Expand Down
7 changes: 7 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,13 @@ class EventUpdate(BaseModel):
class EventConfirmMessage(BaseModel):
msg: Optional[str] = None


class EventMailMessage(BaseModel):
subject: str
msg: str
confirmedOnly: Optional[bool] = False


class EventDB(Event):
participants: List[Participant]

Expand Down
46 changes: 46 additions & 0 deletions tests/test_endpoints/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,52 @@ def test_confirm_message(client):
response = client.get(f'/api/event/{non_existing_eid}/confirm-message')
assert response.status_code == 404


@admin_required("/api/event/{uuid}/mail", "post")
def test_send_notification_mail(client):
eid = test_events[0]["eid"]

client_login(client, admin_member["email"], admin_member["password"])

payload = {'subject': 'test subject',
'msg': 'test msg', 'confirmedOnly': True}

response = client.post(f'/api/event/{non_existing_eid}/mail', json=payload)
assert response.status_code == 404

# Test confirmed only when none are confirmed
response = client.post(f'/api/event/{eid}/mail', json=payload)
assert response.status_code == 400

# Confirm and retry
response = client.put(
f'/api/event/{eid}', json={"date": f'{future_time_str}', 'maxParticipants': 1, 'public': True})
assert response.status_code == 200

response = client.post(
f'/api/event/{eid}/confirm', json={'msg': 'test message'})
assert response.status_code == 200

response = client.post(f'/api/event/{eid}/mail', json=payload)
assert response.status_code == 200

# Test sending to all
payload["confirmedOnly"] = False
response = client.post(f'/api/event/{eid}/mail', json=payload)
assert response.status_code == 200

# Too long subject
payload["subject"] = "a" * 51
response = client.post(f'/api/event/{eid}/mail', json=payload)
assert response.status_code == 400

# Too long message
payload["subject"] = "test"
payload["msg"] = "a" * 5001
response = client.post(f'/api/event/{eid}/mail', json=payload)
assert response.status_code == 400


@admin_required("/api/event/{uuid}/confirm", "post")
def test_confirm_event(client):
eid = test_events[0]["eid"]
Expand Down

0 comments on commit e1246ef

Please sign in to comment.