1- from django .db import models
1+ # ----------------------
2+ # Database tables
3+ # ----------------------
24
5+ from django .db import models
36
47class SlackBot (models .Model ):
58 client_id = models .TextField (null = False )
@@ -54,3 +57,128 @@ class Meta:
5457class SlackOAuthState (models .Model ):
5558 state = models .TextField (null = False )
5659 expire_at = models .DateTimeField (null = False )
60+
61+
62+ # ----------------------
63+ # Bolt store implementations
64+ # ----------------------
65+
66+
67+ from logging import Logger
68+ from typing import Optional
69+ from uuid import uuid4
70+ from django .db .models import F
71+ from django .utils import timezone
72+ from slack_sdk .oauth import InstallationStore , OAuthStateStore
73+ from slack_sdk .oauth .installation_store import Bot , Installation
74+
75+
76+ class DjangoInstallationStore (InstallationStore ):
77+ client_id : str
78+
79+ def __init__ (
80+ self , client_id : str , logger : Logger ,
81+ ):
82+ self .client_id = client_id
83+ self ._logger = logger
84+
85+ @property
86+ def logger (self ) -> Logger :
87+ return self ._logger
88+
89+ def save (self , installation : Installation ):
90+ i = installation .to_dict ()
91+ i ["client_id" ] = self .client_id
92+ SlackInstallation (** i ).save ()
93+ b = installation .to_bot ().to_dict ()
94+ b ["client_id" ] = self .client_id
95+ SlackBot (** b ).save ()
96+
97+ def find_bot (
98+ self , * , enterprise_id : Optional [str ], team_id : Optional [str ]
99+ ) -> Optional [Bot ]:
100+ rows = (
101+ SlackBot .objects .filter (enterprise_id = enterprise_id )
102+ .filter (team_id = team_id )
103+ .order_by (F ("installed_at" ).desc ())[:1 ]
104+ )
105+ if len (rows ) > 0 :
106+ b = rows [0 ]
107+ return Bot (
108+ app_id = b .app_id ,
109+ enterprise_id = b .enterprise_id ,
110+ team_id = b .team_id ,
111+ bot_token = b .bot_token ,
112+ bot_id = b .bot_id ,
113+ bot_user_id = b .bot_user_id ,
114+ bot_scopes = b .bot_scopes ,
115+ installed_at = b .installed_at .timestamp (),
116+ )
117+ return None
118+
119+
120+ class DjangoOAuthStateStore (OAuthStateStore ):
121+ expiration_seconds : int
122+
123+ def __init__ (
124+ self , expiration_seconds : int , logger : Logger ,
125+ ):
126+ self .expiration_seconds = expiration_seconds
127+ self ._logger = logger
128+
129+ @property
130+ def logger (self ) -> Logger :
131+ return self ._logger
132+
133+ def issue (self ) -> str :
134+ state : str = str (uuid4 ())
135+ expire_at = timezone .now () + timezone .timedelta (seconds = self .expiration_seconds )
136+ row = SlackOAuthState (state = state , expire_at = expire_at )
137+ row .save ()
138+ return state
139+
140+ def consume (self , state : str ) -> bool :
141+ rows = SlackOAuthState .objects .filter (state = state ).filter (
142+ expire_at__gte = timezone .now ()
143+ )
144+ if len (rows ) > 0 :
145+ for row in rows :
146+ row .delete ()
147+ return True
148+ return False
149+
150+ # ----------------------
151+ # Slack App
152+ # ----------------------
153+
154+ import logging
155+ import os
156+ from slack_bolt import App
157+ from slack_bolt .oauth .oauth_settings import OAuthSettings
158+
159+ logger = logging .getLogger (__name__ )
160+ client_id , client_secret , signing_secret = (
161+ os .environ ["SLACK_CLIENT_ID" ],
162+ os .environ ["SLACK_CLIENT_SECRET" ],
163+ os .environ ["SLACK_SIGNING_SECRET" ],
164+ )
165+
166+ app = App (
167+ signing_secret = signing_secret ,
168+ installation_store = DjangoInstallationStore (client_id = client_id , logger = logger ,),
169+ oauth_settings = OAuthSettings (
170+ client_id = client_id ,
171+ client_secret = client_secret ,
172+ state_store = DjangoOAuthStateStore (expiration_seconds = 120 , logger = logger ,),
173+ ),
174+ )
175+
176+
177+ @app .event ("app_mention" )
178+ def event_test (body , say , logger ):
179+ logger .info (body )
180+ say ("What's up?" )
181+
182+ @app .command ("/hello-bolt-python" )
183+ def command (ack ):
184+ ack ("This is a Django app!" )
0 commit comments