Python backend for a Slack's kudos plugin.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: merge

+74 -33
+1 -1
kefi/config/__init__.py
··· 16 16 PLAZA_PRICE: int = 10 17 17 PLAZA_DEFAULT_HOUR: int = 10 18 18 PLAZA_DEFAULT_MINUTE: int = 0 19 - PLAZA_SIZE: int = 3 19 + PLAZA_SIZE: int = 4 20 20 LOCALE: str = "es_ES" 21 21 22 22 class Config:
+5
kefi/constants.py
··· 21 21 class Actions: 22 22 LEAVE_MEET: str = "meet_leave" 23 23 SHOW_MEETS_MODAL: str = "show_meets_modal" 24 + 25 + 26 + class EventBodyType: 27 + URL_VERIFICATION: str = "url_verification" 28 + EVENT_CALLBACK: str = "event_callback"
+7 -7
kefi/dependencies.py
··· 5 5 from kefi.models.database import engine 6 6 7 7 8 - class InteractionParams: 9 - def __init__(self, payload: str = Form(...)): 10 - self.payload = payload 11 - 12 - 13 - class EventType(BaseModel): 8 + class Event(BaseModel): 14 9 type: str 15 10 user: str 16 11 ··· 19 14 token: str 20 15 challenge: str | None 21 16 type: str 22 - event: EventType | None 17 + event: Event | None 18 + 19 + 20 + class InteractionParams: 21 + def __init__(self, payload: str = Form(...)): 22 + self.payload = payload 23 23 24 24 25 25 class SlashCommandParams:
+4 -1
kefi/main.py
··· 14 14 app.include_router(interactivity.router) 15 15 app.include_router(events.router) 16 16 17 - locale.setlocale(locale.LC_TIME, settings.LOCALE) 17 + try: 18 + locale.setlocale(locale.LC_TIME, settings.LOCALE) 19 + except locale.Error: 20 + ... 18 21 19 22 20 23 @app.on_event("startup")
+12 -1
kefi/models/core/helpers.py
··· 2 2 from sqlmodel import Session, func, or_, select 3 3 4 4 from kefi.config import settings 5 - from kefi.dependencies import SlashCommandParams 5 + from kefi.dependencies import Event, SlashCommandParams 6 6 from kefi.models.database import Transaction, User 7 7 from kefi.routers.responses import ResetResponse 8 8 from kefi.slack import Slack 9 + 10 + 11 + def get_or_create_from_event(event: Event, session: Session) -> tuple["User", bool]: 12 + """Gets or create the user from the given command.""" 13 + query = select(User).filter(User.slack_user_id == event.user) 14 + user = session.exec(query).one_or_none() 15 + created = not user 16 + if not user: 17 + user = User(slack_user_id=event.user) 18 + session.add(user) 19 + return (user, created) 9 20 10 21 11 22 def get_or_create_from_command(
+5 -13
kefi/routers/events.py
··· 1 1 from fastapi import APIRouter, Depends 2 2 from sqlmodel import Session 3 3 4 - from kefi.dependencies import EventBody, InteractionParams, get_session 5 - from kefi.routers.helpers import InteractionHandler 6 - from kefi.routers.views import HomeView 7 - from kefi.slack import Slack 4 + from kefi.dependencies import EventBody, get_session 5 + from kefi.routers.helpers import EventHandler 8 6 9 7 router = APIRouter() 10 8 11 9 12 10 @router.post("/events/", tags=["events"]) 13 - def handle_events( 14 - body: EventBody, 15 - ): 11 + def handle_events(event_body: EventBody, session: Session = Depends(get_session)): 16 12 """Calls the events handler and gets the response.""" 17 - slack = Slack() 18 - if body.challenge: 19 - return {"challenge": body.challenge} 20 - elif body.event: 21 - slack.publish_view(user_id=body.event.user, view=HomeView()) 22 - return {} 13 + event_handler = EventHandler(event_body=event_body, session=session) 14 + return event_handler.response()
+34 -4
kefi/routers/helpers.py
··· 4 4 5 5 from sqlmodel import Session 6 6 7 - from kefi.constants import Actions, Command, InteractionType 8 - from kefi.dependencies import InteractionParams, SlashCommandParams 7 + from kefi.constants import Actions, Command, EventBodyType, InteractionType 8 + from kefi.dependencies import EventBody, InteractionParams, SlashCommandParams 9 9 from kefi.models.core.exceptions import NotEnoughKefi 10 10 from kefi.models.core.helpers import ( 11 11 available_balance, 12 12 find_user_by_slack_user_id, 13 13 get_all_users, 14 14 get_or_create_from_command, 15 + get_or_create_from_event, 15 16 get_or_create_from_interactivity, 16 17 received_balance, 17 18 send_admin_amount, ··· 44 45 SlackResponse, 45 46 WalletResponse, 46 47 ) 47 - from kefi.routers.views import JoinMeetView, LeaveMeetView 48 + from kefi.routers.views import HomeView, JoinMeetView, LeaveMeetView 48 49 from kefi.slack import Slack 49 50 50 51 ··· 258 259 def interaction_view_submission(self) -> list | dict: 259 260 """Handles the submissions from a view.""" 260 261 view_id = self.payload["view"]["id"] 261 - user_id = self.payload["user"]["id"] 262 262 view_callback_id = self.payload["view"]["callback_id"] 263 263 try: 264 264 return getattr(self, f"_view_submission_{view_callback_id}")( ··· 321 321 self.slack.open_view( 322 322 trigger_id=trigger_id, view=LeaveMeetView(session=self.session) 323 323 ) 324 + 325 + 326 + class EventHandler: 327 + def __init__(self, event_body: EventBody, session: Session): 328 + self.event_body = event_body 329 + self.session = session 330 + self.slack = Slack() 331 + if self.event_body.event: 332 + self.user, _ = get_or_create_from_event( 333 + event=self.event_body.event, session=session 334 + ) 335 + 336 + def response(self) -> list | dict: 337 + handlers: dict[str, Callable] = { 338 + EventBodyType.URL_VERIFICATION: self.handle_url_verification, 339 + EventBodyType.EVENT_CALLBACK: self.handle_event_callback, 340 + } 341 + response = handlers.get(self.event_body.type, self.not_found)() 342 + return response 343 + 344 + def not_found(self) -> list: 345 + return [] 346 + 347 + def handle_url_verification(self) -> dict: 348 + """Handles the endpoint verification.""" 349 + return {"challenge": self.event_body.challenge} 350 + 351 + def handle_event_callback(self) -> list: 352 + self.slack.publish_view(user_id=self.user.slack_user_id, view=HomeView()) 353 + return []
-2
kefi/routers/messages.py
··· 1 1 from slack_sdk.models.blocks import ( 2 2 Block, 3 3 ButtonElement, 4 - ContextBlock, 5 4 DividerBlock, 6 - ImageElement, 7 5 MarkdownTextObject, 8 6 PlainTextObject, 9 7 SectionBlock,
-2
kefi/routers/responses.py
··· 1 - from slack_sdk.models.blocks import Block 2 - 3 1 from kefi.models.database import Action, User 4 2 from kefi.models.outputs import ( 5 3 Context,
+2 -1
kefi/routers/views.py
··· 11 11 ) 12 12 from slack_sdk.models.views import View 13 13 14 + from kefi.config import Settings 14 15 from kefi.constants import Actions, ViewType 15 16 from kefi.models.plazas.helpers import get_or_create_current_plaza 16 17 ··· 140 141 HeaderBlock(text=PlainTextObject(text="Kefi Plaza")), 141 142 SectionBlock( 142 143 text=MarkdownTextObject( 143 - text="Cada viernes se asignan aleatoriamente grupos de 4 personas en una sala virtual para compartir un Kefi online y hablar de los que más os guste. ¿Te unes?" 144 + text=f"Cada viernes se asignan aleatoriamente grupos de {Settings.PLAZA_SIZE} personas en una sala virtual para compartir un Kefi online y hablar de los que más os guste. ¿Te unes?" 144 145 ), 145 146 accessory=ImageElement( 146 147 image_url="https://storage.staging.dekaside.com/kefi/static/images/kefi_plaza.png",
+4 -1
manage.py
··· 22 22 engine, 23 23 ) 24 24 25 - locale.setlocale(locale.LC_TIME, settings.LOCALE) 25 + try: 26 + locale.setlocale(locale.LC_TIME, settings.LOCALE) 27 + except locale.Error: 28 + ... 26 29 session = Session(engine) 27 30 return { 28 31 "Action": Action,