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

Configure Feed

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

Merge branch 'develop'

+890 -189
+3
kefi/config/__init__.py
··· 18 18 PLAZA_DEFAULT_MINUTE: int = 0 19 19 PLAZA_SIZE: int = 4 20 20 LOCALE: str = "es_ES" 21 + KUDOS_PRICE: int = 100 22 + CONGRATS_PRICE: int = 25 23 + HIGH_FIVE_PRICE: int = 5 21 24 22 25 class Config: 23 26 env_file = ".env"
+15 -2
kefi/constants.py
··· 16 16 class ViewType: 17 17 JOIN_MEET: str = "meet_join" 18 18 LEAVE_MEET: str = "meet_leave" 19 + GIVE_KUDOS: str = "give_kudos" 20 + GIVE_CONGRATS: str = "give_congrats" 21 + GIVE_HIGH_FIVE: str = "give_high_five" 19 22 20 23 21 24 class Actions: 22 - LEAVE_MEET: str = "meet_leave" 23 - SHOW_MEETS_MODAL: str = "show_meets_modal" 25 + LEAVE_MEET: str = "action_meet_leave" 26 + SHOW_MEETS_MODAL: str = "action_show_meets_modal" 27 + SHOW_GIVE_KUDOS_MODAL: str = "action_show_give_kudos_modal" 28 + SHOW_GIVE_CONGRATS_MODAL: str = "action_show_give_congrats_modal" 29 + SHOW_GIVE_HIGH_FIVE_MODAL: str = "action_show_give_high_five_modal" 30 + USER_SELECT: str = "action_user_receiver" 31 + PLAIN_TEXT_INPUT: str = "action_message" 24 32 25 33 26 34 class EventBodyType: 27 35 URL_VERIFICATION: str = "url_verification" 28 36 EVENT_CALLBACK: str = "event_callback" 37 + 38 + 39 + class Block: 40 + RECEIVER: str = "block_receiver" 41 + MESSAGE: str = "block_message"
+6 -4
kefi/models/kudos/helpers.py
··· 1 1 from sqlmodel import Session, select 2 2 3 + from kefi.config import settings 3 4 from kefi.constants import Command 5 + from kefi.models.core.exceptions import NotEnoughKefi 4 6 from kefi.models.core.helpers import available_balance 5 7 from kefi.models.database import Action, Transaction, User 6 8 from kefi.routers.responses import ActionResponse ··· 12 14 actions: list[dict[str, int | str]] = [ 13 15 { 14 16 "keyword": Command.KUDOS, 15 - "amount": 100, 17 + "amount": settings.KUDOS_PRICE, 16 18 "header_template": "¡Gracias {receiver_name}!", 17 19 "message_template": "Mensaje de {sender_name}:\n _{message}_", 18 20 "context_template": "*{sender_name}* le da a *{receiver_name}* {amount} kefis.", ··· 21 23 }, 22 24 { 23 25 "keyword": Command.CONGRATS, 24 - "amount": 25, 26 + "amount": settings.CONGRATS_PRICE, 25 27 "header_template": "¡Enhorabuena {receiver_name}!", 26 28 "message_template": "Mensaje de {sender_name}:\n _{message}_", 27 29 "context_template": "*{sender_name}* le da a *{receiver_name}* {amount} kefis.", ··· 30 32 }, 31 33 { 32 34 "keyword": Command.HIGH_FIVE, 33 - "amount": 5, 35 + "amount": settings.HIGH_FIVE_PRICE, 34 36 "header_template": "¡{sender_name} le envía un high five a {receiver_name}!", 35 37 "message_template": "_{message}_", 36 38 "context_template": "*{sender_name}* le da a *{receiver_name}* {amount} kefis.", ··· 57 59 # Checks sender wallet 58 60 balance = available_balance(user=sender, session=session) 59 61 if balance < action.amount: 60 - raise ValueError("The user doesn't have enough balance") 62 + raise NotEnoughKefi("The user doesn't have enough balance") 61 63 # Creates transactions 62 64 sender_transaction = Transaction( 63 65 action=action,
+255 -9
kefi/routers/helpers.py
··· 4 4 5 5 from sqlmodel import Session 6 6 7 - from kefi.constants import Actions, Command, EventBodyType, InteractionType 7 + from kefi.config import settings 8 + from kefi.constants import Actions, Block, Command, EventBodyType, InteractionType 8 9 from kefi.dependencies import EventBody, InteractionParams, SlashCommandParams 9 10 from kefi.models.core.exceptions import NotEnoughKefi 10 11 from kefi.models.core.helpers import ( ··· 27 28 from kefi.models.plazas.helpers import ( 28 29 create_attendance, 29 30 delete_attendance, 31 + get_or_create_current_plaza, 30 32 is_attending, 31 33 ) 32 34 from kefi.routers.messages import ( 33 35 AlreadyAttendingMessage, 34 36 BaseMessage, 37 + CongratsSentMessage, 38 + HighFiveSentMessage, 39 + KudosSentMessage, 35 40 NotAttendingMessage, 36 - NotEnoughKefiMessage, 41 + NotEnoughKefiToGiveMessage, 42 + NotEnoughKefiToJoinMessage, 43 + NotGiveToYourselfMessage, 44 + NotUserToGiveMessage, 37 45 UserJoinedMeetMessage, 38 46 UserLeftMeetMessage, 39 47 ) ··· 45 53 SlackResponse, 46 54 WalletResponse, 47 55 ) 48 - from kefi.routers.views import HomeView, JoinMeetView, LeaveMeetView 56 + from kefi.routers.views import ( 57 + GiveCongratsView, 58 + GiveHighFiveView, 59 + GiveKudosView, 60 + HomeView, 61 + JoinMeetView, 62 + LeaveMeetView, 63 + ) 49 64 from kefi.slack import Slack 50 65 51 66 ··· 114 129 message=message, 115 130 session=self.session, 116 131 ) 117 - except ValueError: 132 + except NotEnoughKefi: 118 133 return SimpleResponse("¡No tienes suficientes kefis! 💸") 119 134 # Notify receiver in private chat 120 135 notify_receiver_user_chat_action( ··· 209 224 handler.handle() 210 225 return [] 211 226 212 - def _view_submission_meet_join(self, view_id: str) -> list | dict: 227 + def _view_submission_meet_join( 228 + self, view_id: str, state: dict | None = None 229 + ) -> list | dict: 213 230 """Joins the plaza.""" 214 231 message: BaseMessage 232 + next_plaza = get_or_create_current_plaza(session=self.session) 215 233 try: 216 234 create_attendance(user=self.user, session=self.session) 217 - message = UserJoinedMeetMessage() 235 + message = UserJoinedMeetMessage(plaza=next_plaza) 218 236 self.slack.post_message_user( 219 237 user_id=self.user.slack_user_id, 220 238 blocks=message.blocks(), 221 239 text=message.text(), 222 240 ) 223 241 except NotEnoughKefi: 224 - message = NotEnoughKefiMessage() 242 + message = NotEnoughKefiToJoinMessage() 225 243 self.slack.post_message_user( 226 244 user_id=self.user.slack_user_id, 227 245 blocks=message.blocks(), ··· 236 254 ) 237 255 return {"response_action": "clear"} 238 256 239 - def _view_submission_meet_leave(self, view_id: str) -> list | dict: 257 + def _view_submission_meet_leave( 258 + self, view_id: str, state: dict | None = None 259 + ) -> list | dict: 240 260 """Leaves the plaza.""" 241 261 message: BaseMessage 242 262 try: ··· 256 276 ) 257 277 return {"response_action": "clear"} 258 278 279 + def _view_submission_give_kudos( 280 + self, view_id: str, state: dict | None = None 281 + ) -> list | dict: 282 + if not state: 283 + return [] 284 + action = get_action(keyword=Command.KUDOS, session=self.session) 285 + if not action: 286 + return [] 287 + slack_user_id = state["values"][Block.RECEIVER][Actions.USER_SELECT][ 288 + "selected_user" 289 + ] 290 + 291 + message = state["values"][Block.MESSAGE][Actions.PLAIN_TEXT_INPUT]["value"] 292 + receiver = find_user_by_slack_user_id( 293 + slack_user_id=slack_user_id, session=self.session 294 + ) 295 + 296 + if not receiver: 297 + not_user_to_give = NotUserToGiveMessage() 298 + self.slack.post_message_user( 299 + user_id=self.user.slack_user_id, 300 + blocks=not_user_to_give.blocks(), 301 + text=not_user_to_give.text(), 302 + ) 303 + return {"response_action": "clear"} 304 + 305 + if self.user.slack_user_id == receiver.id: 306 + not_give_to_yourself_message = NotGiveToYourselfMessage() 307 + self.slack.post_message_user( 308 + user_id=self.user.slack_user_id, 309 + blocks=not_give_to_yourself_message.blocks(), 310 + text=not_give_to_yourself_message.text(), 311 + ) 312 + return {"response_action": "clear"} 313 + 314 + try: 315 + send_action( 316 + sender=self.user, 317 + action=action, 318 + receiver=receiver, 319 + message=message, 320 + session=self.session, 321 + ) 322 + 323 + sent_message = KudosSentMessage( 324 + sender=self.user, 325 + receiver=receiver, 326 + message=message, 327 + amount=settings.KUDOS_PRICE, 328 + ) 329 + self.slack.post_message_user( 330 + user_id=self.user.slack_user_id, 331 + blocks=sent_message.blocks(), 332 + text=sent_message.text(), 333 + ) 334 + 335 + self.slack.post_message_user( 336 + user_id=receiver.slack_user_id, 337 + blocks=sent_message.blocks(), 338 + text=sent_message.text(), 339 + ) 340 + except NotEnoughKefi: 341 + not_enough_message = NotEnoughKefiToGiveMessage() 342 + self.slack.post_message_user( 343 + user_id=self.user.slack_user_id, 344 + blocks=not_enough_message.blocks(), 345 + text=not_enough_message.text(), 346 + ) 347 + return {"response_action": "clear"} 348 + 349 + def _view_submission_give_congrats( 350 + self, view_id: str, state: dict | None = None 351 + ) -> list | dict: 352 + if not state: 353 + return [] 354 + action = get_action(keyword=Command.CONGRATS, session=self.session) 355 + if not action: 356 + return [] 357 + slack_user_id = state["values"][Block.RECEIVER][Actions.USER_SELECT][ 358 + "selected_user" 359 + ] 360 + 361 + message = state["values"][Block.MESSAGE][Actions.PLAIN_TEXT_INPUT]["value"] 362 + receiver = find_user_by_slack_user_id( 363 + slack_user_id=slack_user_id, session=self.session 364 + ) 365 + 366 + if not receiver: 367 + not_user_to_give = NotUserToGiveMessage() 368 + self.slack.post_message_user( 369 + user_id=self.user.slack_user_id, 370 + blocks=not_user_to_give.blocks(), 371 + text=not_user_to_give.text(), 372 + ) 373 + return {"response_action": "clear"} 374 + 375 + if self.user.slack_user_id == receiver.id: 376 + not_give_to_yourself_message = NotGiveToYourselfMessage() 377 + self.slack.post_message_user( 378 + user_id=self.user.slack_user_id, 379 + blocks=not_give_to_yourself_message.blocks(), 380 + text=not_give_to_yourself_message.text(), 381 + ) 382 + return {"response_action": "clear"} 383 + 384 + try: 385 + send_action( 386 + sender=self.user, 387 + action=action, 388 + receiver=receiver, 389 + message=message, 390 + session=self.session, 391 + ) 392 + 393 + sent_message = CongratsSentMessage( 394 + sender=self.user, 395 + receiver=receiver, 396 + message=message, 397 + amount=settings.CONGRATS_PRICE, 398 + ) 399 + self.slack.post_message_user( 400 + user_id=self.user.slack_user_id, 401 + blocks=sent_message.blocks(), 402 + text=sent_message.text(), 403 + ) 404 + 405 + self.slack.post_message_user( 406 + user_id=receiver.slack_user_id, 407 + blocks=sent_message.blocks(), 408 + text=sent_message.text(), 409 + ) 410 + except NotEnoughKefi: 411 + not_enough_message = NotEnoughKefiToGiveMessage() 412 + self.slack.post_message_user( 413 + user_id=self.user.slack_user_id, 414 + blocks=not_enough_message.blocks(), 415 + text=not_enough_message.text(), 416 + ) 417 + return {"response_action": "clear"} 418 + 419 + def _view_submission_give_high_five( 420 + self, view_id: str, state: dict | None = None 421 + ) -> list | dict: 422 + if not state: 423 + return [] 424 + action = get_action(keyword=Command.HIGH_FIVE, session=self.session) 425 + if not action: 426 + return [] 427 + slack_user_id = state["values"][Block.RECEIVER][Actions.USER_SELECT][ 428 + "selected_user" 429 + ] 430 + 431 + message = state["values"][Block.MESSAGE][Actions.PLAIN_TEXT_INPUT]["value"] 432 + receiver = find_user_by_slack_user_id( 433 + slack_user_id=slack_user_id, session=self.session 434 + ) 435 + 436 + if not receiver: 437 + not_user_to_give = NotUserToGiveMessage() 438 + self.slack.post_message_user( 439 + user_id=self.user.slack_user_id, 440 + blocks=not_user_to_give.blocks(), 441 + text=not_user_to_give.text(), 442 + ) 443 + return {"response_action": "clear"} 444 + 445 + if self.user.slack_user_id == receiver.id: 446 + not_give_to_yourself_message = NotGiveToYourselfMessage() 447 + self.slack.post_message_user( 448 + user_id=self.user.slack_user_id, 449 + blocks=not_give_to_yourself_message.blocks(), 450 + text=not_give_to_yourself_message.text(), 451 + ) 452 + return {"response_action": "clear"} 453 + 454 + try: 455 + send_action( 456 + sender=self.user, 457 + action=action, 458 + receiver=receiver, 459 + message=message, 460 + session=self.session, 461 + ) 462 + 463 + sent_message = HighFiveSentMessage( 464 + sender=self.user, 465 + receiver=receiver, 466 + message=message, 467 + amount=settings.HIGH_FIVE_PRICE, 468 + ) 469 + self.slack.post_message_user( 470 + user_id=self.user.slack_user_id, 471 + blocks=sent_message.blocks(), 472 + text=sent_message.text(), 473 + ) 474 + 475 + self.slack.post_message_user( 476 + user_id=receiver.slack_user_id, 477 + blocks=sent_message.blocks(), 478 + text=sent_message.text(), 479 + ) 480 + except NotEnoughKefi: 481 + not_enough_message = NotEnoughKefiToGiveMessage() 482 + self.slack.post_message_user( 483 + user_id=self.user.slack_user_id, 484 + blocks=not_enough_message.blocks(), 485 + text=not_enough_message.text(), 486 + ) 487 + return {"response_action": "clear"} 488 + 259 489 def interaction_view_submission(self) -> list | dict: 260 490 """Handles the submissions from a view.""" 261 491 view_id = self.payload["view"]["id"] 262 492 view_callback_id = self.payload["view"]["callback_id"] 493 + state = self.payload["view"]["state"] 263 494 try: 264 495 return getattr(self, f"_view_submission_{view_callback_id}")( 265 - view_id=view_id 496 + view_id=view_id, state=state 266 497 ) 267 498 except AttributeError: 268 499 ... ··· 286 517 handlers: dict[str, Callable] = { 287 518 Actions.LEAVE_MEET: self.action_leave_meet, 288 519 Actions.SHOW_MEETS_MODAL: self.action_show_meets_modal, 520 + Actions.SHOW_GIVE_KUDOS_MODAL: self.action_show_give_kudos_modal, 521 + Actions.SHOW_GIVE_CONGRATS_MODAL: self.action_show_give_congrats_modal, 522 + Actions.SHOW_GIVE_HIGH_FIVE_MODAL: self.action_show_give_high_five_modal, 289 523 } 290 524 handlers.get(action["action_id"], self.not_found)() 291 525 ··· 321 555 self.slack.open_view( 322 556 trigger_id=trigger_id, view=LeaveMeetView(session=self.session) 323 557 ) 558 + 559 + def action_show_give_kudos_modal(self): 560 + trigger_id = self.payload["trigger_id"] 561 + self.slack.open_view(trigger_id=trigger_id, view=GiveKudosView()) 562 + 563 + def action_show_give_congrats_modal(self): 564 + trigger_id = self.payload["trigger_id"] 565 + self.slack.open_view(trigger_id=trigger_id, view=GiveCongratsView()) 566 + 567 + def action_show_give_high_five_modal(self): 568 + trigger_id = self.payload["trigger_id"] 569 + self.slack.open_view(trigger_id=trigger_id, view=GiveHighFiveView()) 324 570 325 571 326 572 class EventHandler:
+189 -10
kefi/routers/messages.py
··· 1 1 from slack_sdk.models.blocks import ( 2 2 Block, 3 3 ButtonElement, 4 + ContextBlock, 4 5 DividerBlock, 6 + HeaderBlock, 7 + ImageElement, 5 8 MarkdownTextObject, 6 9 PlainTextObject, 7 10 SectionBlock, 8 11 ) 9 12 10 13 from kefi.constants import Actions 14 + from kefi.models.database import Plaza, User 11 15 12 16 13 17 class BaseMessage: ··· 19 23 20 24 21 25 class UserJoinedMeetMessage(BaseMessage): 26 + def __init__(self, plaza: Plaza): 27 + self.plaza = plaza 28 + 22 29 def text(self) -> str: 23 - return ":tada: ¡Genial! ¡Nos vemos el próximo viernes!" 30 + return ":tada: ¡Genial! ¡Nos vemos pronto" 24 31 25 32 def blocks(self) -> list[Block]: 33 + date = self.plaza.local_date() 34 + 26 35 return [ 27 36 SectionBlock( 37 + text=MarkdownTextObject(text=":tada: ¡Genial! ¡Nos vemos pronto!") 38 + ), 39 + DividerBlock(), 40 + SectionBlock( 28 41 text=MarkdownTextObject( 29 - text=":tada: ¡Genial! ¡Nos vemos el próximo viernes!" 30 - ) 42 + text=f"*Próximo encuentro*\n{date.strftime('%A, %-d %B')}\n{date.strftime('%H:%M')}\n" 43 + ), 44 + accessory=ImageElement( 45 + image_url="https://storage.staging.dekaside.com/kefi/static/images/kefi_plaza.png", 46 + alt_text="Kefi Plaza imagen", 47 + ), 31 48 ), 32 49 DividerBlock(), 33 50 SectionBlock( ··· 55 72 ] 56 73 57 74 58 - class NotEnoughKefiMessage(BaseMessage): 75 + class NotEnoughKefiToJoinMessage(BaseMessage): 59 76 def text(self) -> str: 60 - return "NotEnoughKefiMessage" 77 + return ":money_with_wings: ¡Vaya! No tienes suficientes kefis para apuntarte." 61 78 62 79 def blocks(self) -> list[Block]: 63 - return [SectionBlock(text="NotEnoughKefiMessage")] 80 + return [ 81 + SectionBlock( 82 + text=MarkdownTextObject( 83 + text=":money_with_wings: ¡Vaya! No tienes suficientes kefis para apuntarte." 84 + ) 85 + ) 86 + ] 64 87 65 88 66 89 class AlreadyAttendingMessage(BaseMessage): 67 90 def text(self) -> str: 68 - return "AlreadyAttendingMessage" 91 + return "¡Ei! Estás intentando apuntarte al próximo evento pero ya estas apuntado. ¡Nos vemos pronto!" 69 92 70 93 def blocks(self) -> list[Block]: 71 - return [SectionBlock(text="AlreadyAttendingMessage")] 94 + return [ 95 + SectionBlock( 96 + text=MarkdownTextObject( 97 + text="¡Ei! Estás intentando apuntarte al próximo evento pero ya estas apuntado. ¡Nos vemos pronto!" 98 + ) 99 + ) 100 + ] 72 101 73 102 74 103 class NotAttendingMessage(BaseMessage): 75 104 def text(self) -> str: 76 - return "NotAttendingMessage" 105 + return "Has intentado desapuntarte del próximo evento pero ya lo habías hecho antes. ¡Esperamos verte en los próximos eventos!" 106 + 107 + def blocks(self) -> list[Block]: 108 + return [ 109 + SectionBlock( 110 + text=MarkdownTextObject( 111 + text="Has intentado desapuntarte del próximo evento pero ya lo habías hecho antes. ¡Esperamos verte en los próximos eventos!" 112 + ) 113 + ) 114 + ] 115 + 116 + 117 + class KudosSentMessage(BaseMessage): 118 + def __init__(self, sender: User, receiver: User, message: str, amount: int): 119 + self.sender_name = sender.get_short_name() 120 + self.receiver_name = receiver.get_short_name() 121 + self.message = message 122 + self.amount = amount 123 + 124 + def text(self) -> str: 125 + return f"{self.sender_name} le da las gracias a {self.receiver_name}" 126 + 127 + def blocks(self) -> list[Block]: 128 + return [ 129 + HeaderBlock(text=f"¡Gracias {self.receiver_name}!"), 130 + SectionBlock( 131 + text=MarkdownTextObject( 132 + text=f"Mensaje de {self.sender_name}:\n{self.message}" 133 + ), 134 + accessory=ImageElement( 135 + image_url="https://storage.staging.dekaside.com/kefi/static/images/kudos_400.png", 136 + alt_text="Kudos", 137 + ), 138 + ), 139 + ContextBlock( 140 + elements=[ 141 + ImageElement( 142 + image_url="https://storage.staging.dekaside.com/kefi/static/images/coin_70.png", 143 + alt_text="Kefis", 144 + ), 145 + MarkdownTextObject( 146 + text=f"*{self.sender_name}* le da a *{self.receiver_name}* {self.amount} kefis." 147 + ), 148 + ] 149 + ), 150 + ] 151 + 152 + 153 + class CongratsSentMessage(BaseMessage): 154 + def __init__(self, sender: User, receiver: User, message: str, amount: int): 155 + self.sender_name = sender.get_short_name() 156 + self.receiver_name = receiver.get_short_name() 157 + self.message = message 158 + self.amount = amount 159 + 160 + def text(self) -> str: 161 + return f"{self.sender_name} le da la enhorabuena a {self.receiver_name}" 162 + 163 + def blocks(self) -> list[Block]: 164 + return [ 165 + HeaderBlock(text=f"¡Enhorabuena {self.receiver_name}!"), 166 + SectionBlock( 167 + text=MarkdownTextObject( 168 + text=f"Mensaje de {self.sender_name}:\n{self.message}" 169 + ), 170 + accessory=ImageElement( 171 + image_url="https://storage.staging.dekaside.com/kefi/static/images/congrats_400.png", 172 + alt_text="Kudos", 173 + ), 174 + ), 175 + ContextBlock( 176 + elements=[ 177 + ImageElement( 178 + image_url="https://storage.staging.dekaside.com/kefi/static/images/coin_70.png", 179 + alt_text="Kefis", 180 + ), 181 + MarkdownTextObject( 182 + text=f"*{self.sender_name}* le da a *{self.receiver_name}* {self.amount} kefis." 183 + ), 184 + ] 185 + ), 186 + ] 187 + 188 + 189 + class HighFiveSentMessage(BaseMessage): 190 + def __init__(self, sender: User, receiver: User, message: str, amount: int): 191 + self.sender_name = sender.get_short_name() 192 + self.receiver_name = receiver.get_short_name() 193 + self.message = message 194 + self.amount = amount 195 + 196 + def text(self) -> str: 197 + return f"{self.sender_name} le envia un high five a {self.receiver_name}" 198 + 199 + def blocks(self) -> list[Block]: 200 + return [ 201 + HeaderBlock( 202 + text=f"¡{self.sender_name} le envía un high five a {self.receiver_name}!" 203 + ), 204 + SectionBlock( 205 + text=MarkdownTextObject( 206 + text=f"Mensaje de {self.sender_name}:\n{self.message}" 207 + ), 208 + accessory=ImageElement( 209 + image_url="https://storage.staging.dekaside.com/kefi/static/images/highfive_400.png", 210 + alt_text="Kudos", 211 + ), 212 + ), 213 + ContextBlock( 214 + elements=[ 215 + ImageElement( 216 + image_url="https://storage.staging.dekaside.com/kefi/static/images/coin_70.png", 217 + alt_text="Kefis", 218 + ), 219 + MarkdownTextObject( 220 + text=f"*{self.sender_name}* le da a *{self.receiver_name}* {self.amount} kefis." 221 + ), 222 + ] 223 + ), 224 + ] 225 + 226 + 227 + class NotEnoughKefiToGiveMessage(BaseMessage): 228 + def text(self) -> str: 229 + return "¡No tienes suficientes kefis! 💸" 230 + 231 + def blocks(self) -> list[Block]: 232 + return [ 233 + SectionBlock( 234 + text=MarkdownTextObject(text="¡No tienes suficientes kefis! 💸") 235 + ) 236 + ] 237 + 238 + 239 + class NotGiveToYourselfMessage(BaseMessage): 240 + def text(self) -> str: 241 + return "¡No te puedes dar kefis! 🙅" 77 242 78 243 def blocks(self) -> list[Block]: 79 - return [SectionBlock(text="NotAttendingMessage")] 244 + return [ 245 + SectionBlock(text=MarkdownTextObject(text="¡No te puedes dar kefis! 🙅")) 246 + ] 247 + 248 + 249 + class NotUserToGiveMessage(BaseMessage): 250 + def text(self) -> str: 251 + return "No se ha especificado un destinatario" 252 + 253 + def blocks(self) -> list[Block]: 254 + return [ 255 + SectionBlock( 256 + text=MarkdownTextObject(text="No se ha especificado un destinatario") 257 + ) 258 + ]
+142 -8
kefi/routers/views.py
··· 5 5 DividerBlock, 6 6 HeaderBlock, 7 7 ImageElement, 8 + InputBlock, 8 9 MarkdownTextObject, 10 + PlainTextInputElement, 9 11 PlainTextObject, 10 12 SectionBlock, 13 + UserSelectElement, 11 14 ) 12 15 from slack_sdk.models.views import View 13 16 14 17 from kefi.config import settings 15 - from kefi.constants import Actions, ViewType 18 + from kefi.constants import Actions, Block, ViewType 16 19 from kefi.models.plazas.helpers import get_or_create_current_plaza 17 20 18 21 ··· 39 42 text=f"*Próximo encuentro*\n{date.strftime('%A, %-d %B')}\n{date.strftime('%H:%M')}\n" 40 43 ), 41 44 accessory=ImageElement( 42 - image_url="https://api.slack.com/img/blocks/bkb_template_images/notifications.png", 43 - alt_text="calendar thumbnail", 45 + image_url="https://storage.staging.dekaside.com/kefi/static/images/kefi_plaza.png", 46 + alt_text="Kefi Plaza imagen", 44 47 ), 48 + ), 49 + ContextBlock( 50 + elements=[ 51 + PlainTextObject( 52 + text=f"Al apuntarte consumirás {settings.PLAZA_PRICE} kefis." 53 + ) 54 + ] 45 55 ), 46 56 ], 47 57 ) ··· 99 109 HeaderBlock(text=PlainTextObject(text="¡Gracias!")), 100 110 SectionBlock( 101 111 text=MarkdownTextObject( 102 - text="Hazle llegar tu agradecimiento a un compañero por ayudarte en un proyecto." 112 + text=f"Hazle llegar tu agradecimiento a un compañero por ayudarte en un proyecto.\n*Valor:* {settings.KUDOS_PRICE} kefis" 103 113 ), 104 114 accessory=ImageElement( 105 115 image_url="https://storage.staging.dekaside.com/kefi/static/images/kudos.png", 106 116 alt_text="Kudos", 107 117 ), 108 118 ), 119 + ActionsBlock( 120 + elements=[ 121 + ButtonElement( 122 + text=PlainTextObject(text="Dar las gracias"), 123 + action_id=Actions.SHOW_GIVE_KUDOS_MODAL, 124 + ) 125 + ] 126 + ), 109 127 ContextBlock( 110 128 elements=[PlainTextObject(text="/kefi kudos @user [mensaje]")] 111 129 ), ··· 113 131 HeaderBlock(text=PlainTextObject(text="¡Enhorabuena!")), 114 132 SectionBlock( 115 133 text=MarkdownTextObject( 116 - text="Un trabajo bien hecho, una buena idea, la certificación en un nuevo curso... ¡se merecen una enhorabuena!" 134 + text=f"Un trabajo bien hecho, una buena idea, la certificación en un nuevo curso... ¡se merecen una enhorabuena!\n*Valor:* {settings.CONGRATS_PRICE} kefis" 117 135 ), 118 136 accessory=ImageElement( 119 137 image_url="https://storage.staging.dekaside.com/kefi/static/images/congrats.png", 120 138 alt_text="Congrats", 121 139 ), 122 140 ), 141 + ActionsBlock( 142 + elements=[ 143 + ButtonElement( 144 + text=PlainTextObject(text="Dar la enhorabuena"), 145 + action_id=Actions.SHOW_GIVE_CONGRATS_MODAL, 146 + ) 147 + ] 148 + ), 123 149 ContextBlock( 124 150 elements=[PlainTextObject(text="/kefi congrats @user [mensaje]")] 125 151 ), ··· 127 153 HeaderBlock(text=PlainTextObject(text="¡High Five!")), 128 154 SectionBlock( 129 155 text=MarkdownTextObject( 130 - text="Alguien ha sido un buen colega y te ha alegrado el día." 156 + text=f"Alguien ha sido un buen colega y te ha alegrado el día.\n*Valor:* {settings.HIGH_FIVE_PRICE} kefis" 131 157 ), 132 158 accessory=ImageElement( 133 159 image_url="https://storage.staging.dekaside.com/kefi/static/images/highfive.png", 134 160 alt_text="High five", 135 161 ), 136 162 ), 163 + ActionsBlock( 164 + elements=[ 165 + ButtonElement( 166 + text=PlainTextObject(text="Chocar los cinco"), 167 + action_id=Actions.SHOW_GIVE_HIGH_FIVE_MODAL, 168 + ) 169 + ] 170 + ), 137 171 ContextBlock( 138 172 elements=[PlainTextObject(text="/kefi highfive @user [mensaje]")] 139 173 ), ··· 141 175 HeaderBlock(text=PlainTextObject(text="Kefi Plaza")), 142 176 SectionBlock( 143 177 text=MarkdownTextObject( 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?" 178 + text=f"Cada encuentro 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?\nCoste: {settings.PLAZA_PRICE} k" 145 179 ), 146 180 accessory=ImageElement( 147 181 image_url="https://storage.staging.dekaside.com/kefi/static/images/kefi_plaza.png", ··· 151 185 ActionsBlock( 152 186 elements=[ 153 187 ButtonElement( 154 - text=PlainTextObject(text="¡Me Apunto!"), 188 + text=PlainTextObject(text="¡Me apunto!"), 155 189 action_id=Actions.SHOW_MEETS_MODAL, 190 + style="primary", 156 191 ) 157 192 ] 158 193 ), ··· 174 209 ContextBlock(elements=[PlainTextObject(text="/kefi help")]), 175 210 ], 176 211 ) 212 + 213 + 214 + class GiveKudosView(View): 215 + def __init__(self, *args, **kwargs): 216 + super().__init__( 217 + callback_id=ViewType.GIVE_KUDOS, 218 + type="modal", 219 + title=PlainTextObject(text="¡Gracias!"), 220 + close=PlainTextObject(text="Cancelar"), 221 + submit=PlainTextObject(text="Dar las gracias"), 222 + blocks=[ 223 + SectionBlock( 224 + block_id=Block.RECEIVER, 225 + text=MarkdownTextObject(text="¿A quien quieres felicitar?"), 226 + accessory=UserSelectElement( 227 + placeholder=PlainTextObject(text="Selecciona un usuario"), 228 + action_id=Actions.USER_SELECT, 229 + ), 230 + ), 231 + InputBlock( 232 + block_id=Block.MESSAGE, 233 + element=PlainTextInputElement( 234 + multiline=True, action_id=Actions.PLAIN_TEXT_INPUT 235 + ), 236 + label="Déjale un mensaje", 237 + ), 238 + ContextBlock( 239 + elements=[ 240 + PlainTextObject(text=f"Valor: {settings.KUDOS_PRICE} kefis") 241 + ] 242 + ), 243 + ], 244 + ) 245 + 246 + 247 + class GiveCongratsView(View): 248 + def __init__(self, *args, **kwargs): 249 + super().__init__( 250 + callback_id=ViewType.GIVE_CONGRATS, 251 + type="modal", 252 + title=PlainTextObject(text="¡Enhorabuena!"), 253 + close=PlainTextObject(text="Cancelar"), 254 + submit=PlainTextObject(text="Dar la enhorabuena"), 255 + blocks=[ 256 + SectionBlock( 257 + block_id=Block.RECEIVER, 258 + text=MarkdownTextObject(text="¿A quien quieres felicitar?"), 259 + accessory=UserSelectElement( 260 + placeholder=PlainTextObject(text="Selecciona un usuario"), 261 + action_id=Actions.USER_SELECT, 262 + ), 263 + ), 264 + InputBlock( 265 + block_id=Block.MESSAGE, 266 + element=PlainTextInputElement( 267 + multiline=True, action_id=Actions.PLAIN_TEXT_INPUT 268 + ), 269 + label="Déjale un mensaje", 270 + ), 271 + ContextBlock( 272 + elements=[ 273 + PlainTextObject(text=f"Valor: {settings.CONGRATS_PRICE} kefis") 274 + ] 275 + ), 276 + ], 277 + ) 278 + 279 + 280 + class GiveHighFiveView(View): 281 + def __init__(self, *args, **kwargs): 282 + super().__init__( 283 + callback_id=ViewType.GIVE_HIGH_FIVE, 284 + type="modal", 285 + title=PlainTextObject(text="¡High Five!"), 286 + close=PlainTextObject(text="Cancelar"), 287 + submit=PlainTextObject(text="Chocar los cinco"), 288 + blocks=[ 289 + SectionBlock( 290 + block_id=Block.RECEIVER, 291 + text=MarkdownTextObject(text="¿A quien quieres felicitar?"), 292 + accessory=UserSelectElement( 293 + placeholder=PlainTextObject(text="Selecciona un usuario"), 294 + action_id=Actions.USER_SELECT, 295 + ), 296 + ), 297 + InputBlock( 298 + block_id=Block.MESSAGE, 299 + element=PlainTextInputElement( 300 + multiline=True, action_id=Actions.PLAIN_TEXT_INPUT 301 + ), 302 + label="Déjale un mensaje", 303 + ), 304 + ContextBlock( 305 + elements=[ 306 + PlainTextObject(text=f"Valor: {settings.HIGH_FIVE_PRICE} kefis") 307 + ] 308 + ), 309 + ], 310 + )
+244
kefi/tests/mocks.py
··· 1 + INTERACTIVITY_VIEW_ACTION_KUDOS = { 2 + "type": "view_submission", 3 + "team": {"id": "T0RS507QX", "domain": "dekalabs"}, 4 + "user": { 5 + "id": "user_1", 6 + "username": "javichaques", 7 + "name": "javichaques", 8 + "team_id": "T0RS507QX", 9 + }, 10 + "api_app_id": "A0499FQH7V3", 11 + "token": "7n993LRqLRydOnIkEhymVcYD", 12 + "trigger_id": "4327568797879.25889007847.0f6a80604ac4fac92933e384a7792030", 13 + "view": { 14 + "id": "V04ARPPKCU8", 15 + "team_id": "T0RS507QX", 16 + "type": "modal", 17 + "blocks": [ 18 + { 19 + "type": "section", 20 + "block_id": "block_receiver", 21 + "text": { 22 + "type": "mrkdwn", 23 + "text": "\u00bfA quien quieres felicitar?", 24 + "verbatim": False, 25 + }, 26 + "accessory": { 27 + "type": "users_select", 28 + "action_id": "action_user_receiver", 29 + "placeholder": { 30 + "type": "plain_text", 31 + "text": "Selecciona un usuario", 32 + "emoji": True, 33 + }, 34 + }, 35 + }, 36 + { 37 + "type": "input", 38 + "block_id": "block_message", 39 + "label": { 40 + "type": "plain_text", 41 + "text": "D\u00e9jale un mensaje", 42 + "emoji": True, 43 + }, 44 + "optional": False, 45 + "dispatch_action": False, 46 + "element": { 47 + "type": "plain_text_input", 48 + "action_id": "action_message", 49 + "multiline": True, 50 + "dispatch_action_config": { 51 + "trigger_actions_on": ["on_enter_pressed"] 52 + }, 53 + }, 54 + }, 55 + { 56 + "type": "context", 57 + "block_id": "pYpG", 58 + "elements": [ 59 + {"type": "plain_text", "text": "Valor: 100 kefis", "emoji": True} 60 + ], 61 + }, 62 + ], 63 + "private_metadata": "", 64 + "callback_id": "give_kudos", 65 + "state": { 66 + "values": { 67 + "block_receiver": { 68 + "action_user_receiver": { 69 + "type": "users_select", 70 + "selected_user": "user_2", 71 + } 72 + }, 73 + "block_message": { 74 + "action_message": {"type": "plain_text_input", "value": "Test"} 75 + }, 76 + } 77 + }, 78 + "hash": "1667939174.QSF9AysY", 79 + "title": {"type": "plain_text", "text": "\u00a1Gracias!", "emoji": True}, 80 + "clear_on_close": False, 81 + "notify_on_close": False, 82 + "close": {"type": "plain_text", "text": "Cancelar", "emoji": True}, 83 + "submit": {"type": "plain_text", "text": "Enviar kefis", "emoji": True}, 84 + "previous_view_id": None, 85 + "root_view_id": "V04ARPPKCU8", 86 + "app_id": "A0499FQH7V3", 87 + "external_id": "", 88 + "app_installed_team_id": "T0RS507QX", 89 + "bot_id": "B0495T0Q0S2", 90 + }, 91 + "response_urls": [], 92 + "is_enterprise_install": False, 93 + "enterprise": None, 94 + } 95 + 96 + INTERACTIVITY_VIEW_ACTION_LEAVE = { 97 + "type": "view_submission", 98 + "team": {"id": "T0RS507QX", "domain": "dekalabs"}, 99 + "user": { 100 + "id": "UCBKX2GQ4", 101 + "username": "marcos", 102 + "name": "marcos", 103 + "team_id": "T0RS507QX", 104 + }, 105 + "api_app_id": "A0499FQH7V3", 106 + "token": "7n993LRqLRydOnIkEhymVcYD", 107 + "trigger_id": "4338017757538.25889007847.877c730e79e8a4b1917de09d38a8daa0", 108 + "view": { 109 + "id": "V04AMLW580G", 110 + "team_id": "T0RS507QX", 111 + "type": "modal", 112 + "blocks": [ 113 + { 114 + "type": "section", 115 + "block_id": "9n+9", 116 + "text": { 117 + "type": "mrkdwn", 118 + "text": "*:wave: \\u00a1Hola! \\u00bfTe vienes a la Kefi Plaza?*", 119 + "verbatim": False, 120 + }, 121 + }, 122 + {"type": "divider", "block_id": "MSUNF"}, 123 + { 124 + "type": "section", 125 + "block_id": "IbY", 126 + "text": { 127 + "type": "mrkdwn", 128 + "text": "*Pr\\u00f3ximo encuentro*\\nFriday, 11 November\\n10:00\\n", 129 + "verbatim": False, 130 + }, 131 + "accessory": { 132 + "type": "image", 133 + "image_url": "https:\\/\\/api.slack.com\\/img\\/blocks\\/bkb_template_images\\/notifications.png", 134 + "alt_text": "calendar thumbnail", 135 + }, 136 + }, 137 + ], 138 + "private_metadata": "", 139 + "callback_id": "meet_leave", 140 + "state": {"values": {}}, 141 + "hash": "1667896295.Ry45BkuV", 142 + "title": {"type": "plain_text", "text": "Kefi", "emoji": True}, 143 + "clear_on_close": False, 144 + "notify_on_close": False, 145 + "close": {"type": "plain_text", "text": "Cancelar", "emoji": True}, 146 + "submit": { 147 + "type": "plain_text", 148 + "text": "\\u00a1Me apunto!", 149 + "emoji": True, 150 + }, 151 + "previous_view_id": None, 152 + "root_view_id": "V04AMLW580G", 153 + "app_id": "A0499FQH7V3", 154 + "external_id": "", 155 + "app_installed_team_id": "T0RS507QX", 156 + "bot_id": "B0495T0Q0S2", 157 + }, 158 + "response_urls": [], 159 + "is_enterprise_install": False, 160 + "enterprise": None, 161 + } 162 + 163 + INTERACTIVITY_VIEW_ACTION_JOIN = { 164 + "type": "view_submission", 165 + "team": {"id": "T0RS507QX", "domain": "dekalabs"}, 166 + "user": { 167 + "id": "UCBKX2GQ4", 168 + "username": "marcos", 169 + "name": "marcos", 170 + "team_id": "T0RS507QX", 171 + }, 172 + "api_app_id": "A0499FQH7V3", 173 + "token": "7n993LRqLRydOnIkEhymVcYD", 174 + "trigger_id": "4338017757538.25889007847.877c730e79e8a4b1917de09d38a8daa0", 175 + "view": { 176 + "id": "V04AMLW580G", 177 + "team_id": "T0RS507QX", 178 + "type": "modal", 179 + "blocks": [ 180 + { 181 + "type": "section", 182 + "block_id": "9n+9", 183 + "text": { 184 + "type": "mrkdwn", 185 + "text": "*:wave: \\u00a1Hola! \\u00bfTe vienes a la Kefi Plaza?*", 186 + "verbatim": False, 187 + }, 188 + }, 189 + {"type": "divider", "block_id": "MSUNF"}, 190 + { 191 + "type": "section", 192 + "block_id": "IbY", 193 + "text": { 194 + "type": "mrkdwn", 195 + "text": "*Pr\\u00f3ximo encuentro*\\nFriday, 11 November\\n10:00\\n", 196 + "verbatim": False, 197 + }, 198 + "accessory": { 199 + "type": "image", 200 + "image_url": "https:\\/\\/api.slack.com\\/img\\/blocks\\/bkb_template_images\\/notifications.png", 201 + "alt_text": "calendar thumbnail", 202 + }, 203 + }, 204 + ], 205 + "private_metadata": "", 206 + "callback_id": "meet_join", 207 + "state": {"values": {}}, 208 + "hash": "1667896295.Ry45BkuV", 209 + "title": {"type": "plain_text", "text": "Kefi", "emoji": True}, 210 + "clear_on_close": False, 211 + "notify_on_close": False, 212 + "close": {"type": "plain_text", "text": "Cancelar", "emoji": True}, 213 + "submit": { 214 + "type": "plain_text", 215 + "text": "\\u00a1Me apunto!", 216 + "emoji": True, 217 + }, 218 + "previous_view_id": None, 219 + "root_view_id": "V04AMLW580G", 220 + "app_id": "A0499FQH7V3", 221 + "external_id": "", 222 + "app_installed_team_id": "T0RS507QX", 223 + "bot_id": "B0495T0Q0S2", 224 + }, 225 + "response_urls": [], 226 + "is_enterprise_install": False, 227 + "enterprise": None, 228 + } 229 + 230 + INTERACTIVITY_SHORTCUT = { 231 + "type": "shortcut", 232 + "token": "7n993LRqLRydOnIkEhymVcYD", 233 + "action_ts": "1667577118.758775", 234 + "team": {"id": "T0RS507QX", "domain": "dekalabs"}, 235 + "user": { 236 + "id": "UCBKX2GQ4", 237 + "username": "marcos", 238 + "team_id": "T0RS507QX", 239 + }, 240 + "is_enterprise_install": False, 241 + "enterprise": None, 242 + "callback_id": "kefi_meets", 243 + "trigger_id": "4322087874981.25889007847.4301795f6ef2096cbc96f70c5d7bd48b", 244 + }
+35 -155
kefi/tests/test_interactivity.py
··· 3 3 from fastapi.testclient import TestClient 4 4 from pytest_mock import MockerFixture 5 5 from slack_sdk.web.client import WebClient 6 + from sqlmodel import Session 7 + 8 + from kefi.config import settings 9 + from kefi.models.core.helpers import received_balance, reset_wallets 10 + from kefi.models.database import User 11 + from kefi.tests.mocks import ( 12 + INTERACTIVITY_SHORTCUT, 13 + INTERACTIVITY_VIEW_ACTION_JOIN, 14 + INTERACTIVITY_VIEW_ACTION_KUDOS, 15 + INTERACTIVITY_VIEW_ACTION_LEAVE, 16 + ) 6 17 7 18 8 19 def test_default_interactivity(client: TestClient, mocker: MockerFixture): ··· 11 22 views_open.side_effect = [views_open_response] 12 23 response = client.post( 13 24 "/interactivity/", 14 - data={ 15 - "payload": json.dumps( 16 - { 17 - "type": "shortcut", 18 - "token": "7n993LRqLRydOnIkEhymVcYD", 19 - "action_ts": "1667577118.758775", 20 - "team": {"id": "T0RS507QX", "domain": "dekalabs"}, 21 - "user": { 22 - "id": "UCBKX2GQ4", 23 - "username": "marcos", 24 - "team_id": "T0RS507QX", 25 - }, 26 - "is_enterprise_install": False, 27 - "enterprise": None, 28 - "callback_id": "kefi_meets", 29 - "trigger_id": "4322087874981.25889007847.4301795f6ef2096cbc96f70c5d7bd48b", 30 - } 31 - ) 32 - }, 25 + data={"payload": json.dumps(INTERACTIVITY_SHORTCUT)}, 33 26 ) 34 27 assert response.status_code == 200 35 28 ··· 41 34 post_message_user = mocker.patch.object(WebClient, "chat_postMessage") 42 35 post_message_user_response: dict = {} # Adds expected response here 43 36 post_message_user.side_effect = [post_message_user_response] 44 - payload = json.dumps( 45 - { 46 - "type": "view_submission", 47 - "team": {"id": "T0RS507QX", "domain": "dekalabs"}, 48 - "user": { 49 - "id": "UCBKX2GQ4", 50 - "username": "marcos", 51 - "name": "marcos", 52 - "team_id": "T0RS507QX", 53 - }, 54 - "api_app_id": "A0499FQH7V3", 55 - "token": "7n993LRqLRydOnIkEhymVcYD", 56 - "trigger_id": "4338017757538.25889007847.877c730e79e8a4b1917de09d38a8daa0", 57 - "view": { 58 - "id": "V04AMLW580G", 59 - "team_id": "T0RS507QX", 60 - "type": "modal", 61 - "blocks": [ 62 - { 63 - "type": "section", 64 - "block_id": "9n+9", 65 - "text": { 66 - "type": "mrkdwn", 67 - "text": "*:wave: \\u00a1Hola! \\u00bfTe vienes a la Kefi Plaza?*", 68 - "verbatim": False, 69 - }, 70 - }, 71 - {"type": "divider", "block_id": "MSUNF"}, 72 - { 73 - "type": "section", 74 - "block_id": "IbY", 75 - "text": { 76 - "type": "mrkdwn", 77 - "text": "*Pr\\u00f3ximo encuentro*\\nFriday, 11 November\\n10:00\\n", 78 - "verbatim": False, 79 - }, 80 - "accessory": { 81 - "type": "image", 82 - "image_url": "https:\\/\\/api.slack.com\\/img\\/blocks\\/bkb_template_images\\/notifications.png", 83 - "alt_text": "calendar thumbnail", 84 - }, 85 - }, 86 - ], 87 - "private_metadata": "", 88 - "callback_id": "meet_join", 89 - "state": {"values": {}}, 90 - "hash": "1667896295.Ry45BkuV", 91 - "title": {"type": "plain_text", "text": "Kefi", "emoji": True}, 92 - "clear_on_close": False, 93 - "notify_on_close": False, 94 - "close": {"type": "plain_text", "text": "Cancelar", "emoji": True}, 95 - "submit": { 96 - "type": "plain_text", 97 - "text": "\\u00a1Me apunto!", 98 - "emoji": True, 99 - }, 100 - "previous_view_id": None, 101 - "root_view_id": "V04AMLW580G", 102 - "app_id": "A0499FQH7V3", 103 - "external_id": "", 104 - "app_installed_team_id": "T0RS507QX", 105 - "bot_id": "B0495T0Q0S2", 106 - }, 107 - "response_urls": [], 108 - "is_enterprise_install": False, 109 - "enterprise": None, 110 - } 111 - ) 37 + payload = json.dumps(INTERACTIVITY_VIEW_ACTION_JOIN) 112 38 response = client.post("/interactivity/", data={"payload": payload}) 113 39 assert response.status_code == 200 114 40 ··· 120 46 post_message_user = mocker.patch.object(WebClient, "chat_postMessage") 121 47 post_message_user_response: dict = {} # Adds expected response here 122 48 post_message_user.side_effect = [post_message_user_response] 123 - payload = json.dumps( 124 - { 125 - "type": "view_submission", 126 - "team": {"id": "T0RS507QX", "domain": "dekalabs"}, 127 - "user": { 128 - "id": "UCBKX2GQ4", 129 - "username": "marcos", 130 - "name": "marcos", 131 - "team_id": "T0RS507QX", 132 - }, 133 - "api_app_id": "A0499FQH7V3", 134 - "token": "7n993LRqLRydOnIkEhymVcYD", 135 - "trigger_id": "4338017757538.25889007847.877c730e79e8a4b1917de09d38a8daa0", 136 - "view": { 137 - "id": "V04AMLW580G", 138 - "team_id": "T0RS507QX", 139 - "type": "modal", 140 - "blocks": [ 141 - { 142 - "type": "section", 143 - "block_id": "9n+9", 144 - "text": { 145 - "type": "mrkdwn", 146 - "text": "*:wave: \\u00a1Hola! \\u00bfTe vienes a la Kefi Plaza?*", 147 - "verbatim": False, 148 - }, 149 - }, 150 - {"type": "divider", "block_id": "MSUNF"}, 151 - { 152 - "type": "section", 153 - "block_id": "IbY", 154 - "text": { 155 - "type": "mrkdwn", 156 - "text": "*Pr\\u00f3ximo encuentro*\\nFriday, 11 November\\n10:00\\n", 157 - "verbatim": False, 158 - }, 159 - "accessory": { 160 - "type": "image", 161 - "image_url": "https:\\/\\/api.slack.com\\/img\\/blocks\\/bkb_template_images\\/notifications.png", 162 - "alt_text": "calendar thumbnail", 163 - }, 164 - }, 165 - ], 166 - "private_metadata": "", 167 - "callback_id": "meet_leave", 168 - "state": {"values": {}}, 169 - "hash": "1667896295.Ry45BkuV", 170 - "title": {"type": "plain_text", "text": "Kefi", "emoji": True}, 171 - "clear_on_close": False, 172 - "notify_on_close": False, 173 - "close": {"type": "plain_text", "text": "Cancelar", "emoji": True}, 174 - "submit": { 175 - "type": "plain_text", 176 - "text": "\\u00a1Me apunto!", 177 - "emoji": True, 178 - }, 179 - "previous_view_id": None, 180 - "root_view_id": "V04AMLW580G", 181 - "app_id": "A0499FQH7V3", 182 - "external_id": "", 183 - "app_installed_team_id": "T0RS507QX", 184 - "bot_id": "B0495T0Q0S2", 185 - }, 186 - "response_urls": [], 187 - "is_enterprise_install": False, 188 - "enterprise": None, 189 - } 190 - ) 49 + payload = json.dumps(INTERACTIVITY_VIEW_ACTION_LEAVE) 50 + response = client.post("/interactivity/", data={"payload": payload}) 51 + assert response.status_code == 200 52 + 53 + 54 + def test_view_action_kudos(client: TestClient, mocker: MockerFixture, session: Session): 55 + users = [User(slack_user_id="user_1"), User(slack_user_id="user_2")] 56 + for user in users: 57 + session.add(user) 58 + reset_wallets(session=session) 59 + views_open = mocker.patch.object(WebClient, "views_open") 60 + views_open_response: dict = {} # Adds expected response here 61 + views_open.side_effect = [views_open_response] 62 + post_message_user = mocker.patch.object(WebClient, "chat_postMessage") 63 + post_message_user_response: dict = {} # Adds expected response here 64 + post_message_user.side_effect = [ 65 + post_message_user_response, 66 + post_message_user_response, 67 + ] 68 + payload = json.dumps(INTERACTIVITY_VIEW_ACTION_KUDOS) 191 69 response = client.post("/interactivity/", data={"payload": payload}) 192 70 assert response.status_code == 200 71 + receiver_balance = received_balance(user=users[1], session=session) 72 + assert receiver_balance == settings.KUDOS_PRICE
+1 -1
pyproject.toml
··· 1 1 [tool.poetry] 2 2 name = "Kefi" 3 - version = "2.0.1" 3 + version = "2.1.0" 4 4 description = "An awesome project from Dekalabs" 5 5 authors = ["Deka <backend@dekalabs.com>"] 6 6