Skip to content
Open
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
11 changes: 8 additions & 3 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from starlette.requests import Request
from starlette.responses import JSONResponse

from isabelle.endpoints import HomeEndpoint
from isabelle.endpoints import HomeEndpoint,rsvp_endpoint
from isabelle.piccolo_app import APP_CONFIG
from isabelle.tables import Event
from slack_bolt.adapter.starlette.async_handler import AsyncSlackRequestHandler
Expand Down Expand Up @@ -71,7 +71,11 @@ async def lifespan(app: Starlette):


async def endpoint(req: Request):
return await app_handler.handle(req)
try:
return await app_handler.handle(req)
except Exception as e:
logging.error(f"Error handling Slack request: {e}")
return JSONResponse({"error": str(e)},status_code=500)

api = Starlette(
routes=[
Expand All @@ -86,7 +90,8 @@ async def endpoint(req: Request):
Mount("/static/", StaticFiles(directory="static")),
Mount("/events/", PiccoloCRUD(table=Event,read_only=True,page_size=1000)),
Route("/slack/events",endpoint=endpoint,methods=["POST"]),
Route("/health",endpoint=health,methods=["GET"])
Route("/health",endpoint=health,methods=["GET"]),
Route("/api/rsvp",endpoint=rsvp_endpoint,methods=["POST"])
],
lifespan=lifespan,
)
39 changes: 38 additions & 1 deletion isabelle/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,48 @@
from starlette.endpoints import HTTPEndpoint
from starlette.responses import PlainTextResponse


import json
import logging
from isabelle.utils.env import env
from starlette.responses import JSONResponse
from starlette.requests import Request


class HomeEndpoint(HTTPEndpoint):
async def get(self, request):


return PlainTextResponse("Hello! Isabelle (REST API) here. https://hack.club/gh/isabelle")

async def rsvp_endpoint(request: Request):
if request.method !="POST":
return JSONResponse({"error": "Method not allowed"},status_code=405)
try:
body = await request.json()
except json.JSONDecodeError:
return JSONResponse({"error": "Invalid JSON"},status_code=400)

event_id = body.get("event_id")
user_id = body.get("user_id")

if not event_id:
return JSONResponse({"error":"Missing event_id"},status_code=400)
if not user_id:
return JSONResponse({"error": "Internal server error"},status_code=400)
try:
event = await env.database.toggle_user_interest(event_id,user_id)
except Exception as e:
logging.error(f"Error toggling RSVP: {e}")
return JSONResponse({"error": "Internal server error"},status_code=500)
if not event:
return JSONResponse({"error": "Event not found"},status_code=404)

interested_users = list(event.InterestedUsers or [])
is_interested = user_id in interested_users

return JSONResponse({
"event_id": str(event.id),
"user_id": user_id,
"is_interested": is_interested,
"interest_count": event.InterestCount,
})
2 changes: 1 addition & 1 deletion isabelle/events/reaction_added.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async def handle_reaction_added(body, client: AsyncWebClient):
text='Error RSVPing to the event. :('
)
return
if str(body["event"]["user"]) not in event.get("InterestedUsers", []):
if str(body["event"]["user"]) not in event.get("InterestedUsers",[]):
try:
await client.chat_postEphemeral(
channel=body["event"]["item"]["channel"],
Expand Down
2 changes: 1 addition & 1 deletion isabelle/events/reaction_removed.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async def handle_reaction_removed(body, client: AsyncWebClient):
text='Error disabling RSVPing to the event. :('
)
return
if str(body["event"]["user"]) not in event.get("InterestedUsers", []):
if str(body["event"]["user"]) not in event.get("InterestedUsers",[]):
try:
await client.chat_postEphemeral(
channel=body["event"]["item"]["channel"],
Expand Down
5 changes: 2 additions & 3 deletions isabelle/events/views/create_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@
from slack_gfm import rich_text_to_gfm

from isabelle.views.app_home import get_home
from datetime import datetime


async def handle_create_event_view(ack: Callable, body: dict[str, Any], client: AsyncWebClient):
await ack()
view = body["view"]
values = view["state"]["values"]
title = (values["title"]["title"]["value"],)
title = (values["title"]["title"]["value"])
description = values["description"]["description"]["rich_text_value"]["elements"]
md = rich_text_to_md(description)
start_time = datetime.fromtimestamp(values["start_time"]["start_time"]["selected_date_time"])
Expand Down Expand Up @@ -60,7 +59,7 @@ async def handle_create_event_view(ack: Callable, body: dict[str, Any], client:
await client.chat_postEphemeral(
user=body["user"]["id"],
channel=body["user"]["id"],
text=f'An error occurred whilst creating the event "{title[0]}".',
text=(f'Could not create "{title[0]}\n' f'An event with the same title and start time may already exist\n' f'Please check exiting events or edit them instead')
)
return

Expand Down
21 changes: 11 additions & 10 deletions isabelle/events/views/rsvp_msg_set_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ async def handle_rsvp_msg_set_response(ack: callable, body, view, client: AsyncW
emoji_name = extract_emoji_name(view)
chosen_event_id = view["state"]["values"]["chosen_event"]["event_select"]["selected_option"]["value"]
(message_ts, channel_id) = tuple(view["private_metadata"].split("-"))
try:
await client.reactions_add(
channel=channel_id,
timestamp=message_ts,
name=emoji_name
)
except Exception:
logging.warning("Error adding reaction in handle_rsvp_msg_set_response", exc_info=True)
if emoji_name:
try:
await client.reactions_add(
channel=channel_id,
timestamp=message_ts,
name=emoji_name
)
except Exception:
logging.warning("Error adding reaction in handle_rsvp_msg_set_response", exc_info=True)

ev = await env.database.set_rsvp_msg(chosen_event_id, message_ts, channel_id, emoji_name)

Expand Down Expand Up @@ -61,12 +62,12 @@ async def rsvp_previous_reactions(client: AsyncWebClient, message_ts: str, chann
if not res.get("ok"):
return

reactions: list = res.get("message").get("reactions")

# Holy ternary shenanigans. I'm so sorry for this, seems like the python way
reactions: list = res.get("message",{}).get("reactions") or []
reactions = [i for i in reactions if i.get("name") == reaction_name] if reaction_name else reactions

users = [user for reaction in reactions for user in reaction["users"]]
users = [user for reaction in reactions for user in reaction.get["users",[]]]

users = set(users)

Expand Down
2 changes: 1 addition & 1 deletion isabelle/utils/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ async def toggle_user_interest(self, event_id: str, user_slack_id: str, forced_s


if set(interested_users) == unupdated_users_set:
return event
return await Event.select().where(Event.id == event_uuid).first()

await Event.update(
InterestedUsers=interested_users,
Expand Down
6 changes: 5 additions & 1 deletion isabelle/utils/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def __init__(self):

unset = [key for key, value in self.__dict__.items() if value == "unset"]

if self.environemnt == "development":
unset = [key for key in unset if key not in ("airtable_api_key", "airtable_base_id")]


if unset:
raise ValueError(f"Missing environment variables: {', '.join(unset)}")

Expand All @@ -45,7 +49,7 @@ def __init__(self):
"U06QST7V0J2", # Eesha
"U097UCZE2BB", # Aishaani
"U072PTA5BNG", # Victorio
"U09Q8MLTE58" # EPS
"U09Q8MLTE58", # EPS
]

self.event_tags = [
Expand Down
2 changes: 1 addition & 1 deletion isabelle/views/app_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ async def get_home(user_id: str, client: AsyncWebClient):
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"{'*[UNAPPROVED]:* ' if not event["Approved"] else ''}*{event["Title"]}* - <@{event["LeaderSlackID"]}>\n{mrkdwn}\n*{formatted_time}*",
"text": f"{'*[UNAPPROVED]:* ' if not event["Approved"] else ''}*{event["Title"]}* - <@{event["LeaderSlackID"]}>\n{mrkdwn}\n*{formatted_time}*\nInterest: {event.get('InterestCount',0)}",
},
"accessory": {
"type": "image",
Expand Down