Skip to content

Commit 4b53bd0

Browse files
authored
Production (#26)
* Feature multiple workspaces (#24) (#25) * add app registration manifest and piazza icon * install instructions * readme formatting and clarity * add missing install instructions * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * temp contributing.md * update contributing and add venv to gitignore * bugfix: threaded message replies * install script * update readme * update readme * remove git conflict * update instructions to include install script * Feature reply in thread (#16) * Update issue templates * Delete CONTRIBUTING.md moving to .github * Revert "Update issue templates" This reverts commit 43cd34f. * Revert "Delete CONTRIBUTING.md" This reverts commit 25384ed. * Update issue templates * Create pull_request_template.md * Create pull_request_template.md * Update README.md * Update README.md * Update issue templates * Update feature_request.md * broadcast replies to unthreaded messages * delte test file * Feature update course (#21) * Develop (#19) * add app registration manifest and piazza icon * install instructions * readme formatting and clarity * add missing install instructions * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * temp contributing.md * update contributing and add venv to gitignore * bugfix: threaded message replies * install script * update readme * update readme * remove git conflict * update instructions to include install script * Feature reply in thread (#16) * Update issue templates * Delete CONTRIBUTING.md moving to .github * Revert "Update issue templates" This reverts commit 43cd34f. * Revert "Delete CONTRIBUTING.md" This reverts commit 25384ed. * Update issue templates * Create pull_request_template.md * Create pull_request_template.md * Update README.md * Update README.md * Update issue templates * Update feature_request.md * broadcast replies to unthreaded messages * delte test file * install tinydb and add slash command to upsert forum ids * remove course id from example .eng * store forum id in tinydb * move error message construction * formatting * formatting * update readme * get forum id for each message sent * add cache, rename Course -> Q (for query), move post_url building to message (#22) * update gitignore * add test message and remove dotenv * remove unnecessary requirements * add DB setup * update DB setup * update DB setup * escape db password * try pymysql * change port back to 443 default * add scopes * change test message to only mention. trying to figure out multimessage thing * change test message to only mention. trying to figure out multimessage thing * debug command * debug command * debug command * fix logging * try a merge * warm the cache * formatting, also save the cache before quitting * update logging level * whoops
1 parent 9c142e5 commit 4b53bd0

File tree

2 files changed

+112
-34
lines changed

2 files changed

+112
-34
lines changed

app.py

Lines changed: 110 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,139 @@
11
import os
2-
from dotenv import load_dotenv
32
from signal import signal, SIGINT
43
from sys import exit
54

65
from slack_bolt import App
7-
from slack_bolt.adapter.socket_mode import SocketModeHandler
8-
import logging
6+
from slack_bolt.oauth.oauth_settings import OAuthSettings
7+
from slack_sdk.oauth.installation_store.sqlalchemy import SQLAlchemyInstallationStore
8+
from slack_sdk.oauth.state_store.sqlalchemy import SQLAlchemyOAuthStateStore
9+
10+
import sqlalchemy
11+
from sqlalchemy.engine import Engine
12+
from sqlalchemy.ext.declarative import declarative_base
13+
from sqlalchemy import Column, String
14+
from sqlalchemy.orm import Session
15+
from sqlalchemy import select
16+
from urllib import parse
917

1018
import re
11-
from tinydb import TinyDB, Query
1219

13-
# Make the app
14-
logging.basicConfig(level=logging.ERROR)
20+
import logging
21+
logger = logging.getLogger(__name__)
22+
23+
# Set up DB
24+
db_host, db_user, db_pass, db_name = (
25+
os.environ.get("DB_HOST"),
26+
os.environ.get("DB_USER"),
27+
parse.quote_plus(os.environ.get("DB_PASS")),
28+
os.environ.get("DB_NAME")
29+
)
30+
client_id, client_secret, signing_secret = (
31+
os.environ["SLACK_CLIENT_ID"],
32+
os.environ["SLACK_CLIENT_SECRET"],
33+
os.environ["SLACK_SIGNING_SECRET"],
34+
)
35+
connection = f"mysql+pymysql://{db_user}:{db_pass}@{db_host}/{db_name}"
36+
engine: Engine = sqlalchemy.create_engine(connection)
37+
38+
# Set up Oauth backend
39+
installation_store = SQLAlchemyInstallationStore(
40+
client_id=client_id,
41+
engine=engine,
42+
logger=logger
43+
)
44+
oauth_state_store = SQLAlchemyOAuthStateStore(
45+
expiration_seconds=120,
46+
engine=engine,
47+
logger=logger
48+
)
49+
50+
try:
51+
engine.execute("select count(*) from slack_bots")
52+
except Exception as e:
53+
installation_store.metadata.create_all(engine)
54+
oauth_state_store.metadata.create_all(engine)
55+
56+
# Set up custom table
57+
Base = declarative_base()
58+
59+
60+
class Course(Base):
61+
__tablename__ = 'courses'
62+
__table_args__ = {'schema': db_name}
63+
64+
workspace = Column("workspace", String(32), nullable=False, primary_key=True)
65+
forum = Column("forum", String(32), nullable=False)
66+
67+
def __repr__(self):
68+
return "Course({0}, {1})".format(self.workspace, self.forum)
1569

70+
71+
Base.metadata.create_all(engine)
72+
73+
# Set up app
1674
app = App(
1775
token=os.environ.get("SLACK_BOT_TOKEN"),
18-
signing_secret=os.environ.get("SLACK_SIGNING_SECRET")
76+
signing_secret=signing_secret,
77+
installation_store=installation_store,
78+
oauth_settings=OAuthSettings(
79+
client_id=client_id,
80+
client_secret=client_secret,
81+
state_store=oauth_state_store,
82+
scopes=[
83+
"chat:write.public",
84+
"chat:write",
85+
"channels:history",
86+
"groups:history",
87+
"im:history",
88+
"mpim:history",
89+
"commands"
90+
]
91+
)
1992
)
2093

21-
db = TinyDB('data/db.json')
22-
Q = Query()
23-
cache = {}
24-
2594
error = "Sorry, the forum id hasn't been set! "
2695
error += "You can set it via slash command:\n"
2796
error += "`/piazza-update-id [course_id]`\n"
2897
error += "You can find the course id in any url on your piazza forum. "
2998
error += "it'll be the long alphanumeric string."
3099

100+
cache = {}
31101
base_url = "https://piazza.com/class/"
32102

33103

34104
# Provides a means of setting the forum ID from a running app.
35105
@app.command("/piazza-update-id")
36106
def update_forum_id(ack, respond, command, context):
107+
logging.warning("in command handler.")
37108
global cache
38109
ack()
39110

40-
workspace = context['team_id']
111+
workspace_id = context['team_id']
41112
forum_id = command['text']
42113

43114
# update in mem
44-
cache[workspace] = forum_id
45-
46-
# update in file
47-
db.upsert(
48-
{'workspace': workspace, 'forum': forum_id},
49-
Q.workspace == workspace
50-
)
115+
cache[workspace_id] = forum_id
116+
logging.info(f"after cache insert. cache[{workspace_id}] should be {forum_id}, is {cache[workspace_id]}")
117+
c = Course(workspace=workspace_id, forum=forum_id)
118+
with Session(engine) as session:
119+
logging.info(f"in session thing. course is: {c}")
120+
session.merge(c)
121+
session.commit()
122+
logging.info("after commit")
51123

52124
respond(f"Updated forum! new id is {forum_id}", )
53125

54-
@app.message("thunder")
55-
def post_link(say, context, event, client):
56-
say("lightning")
57-
58126

59127
# Listens for any message with a piazza tag in it. Piazza tags take the form
60128
# "@123", where the number is the id of a post on Piazza.
61-
#
129+
#
62130
# https://regex101.com/r/eMmguY/1
63131
@app.message(re.compile(r"@(\d+\b)"))
64132
def post_link(say, context, event, client):
65133
global cache
66134
forum_id = cache.get(context["team_id"], None)
67135

68-
if forum_id == None:
136+
if forum_id is None:
69137
client.chat_postEphemeral(
70138
text=error,
71139
channel=context["channel_id"],
@@ -83,7 +151,7 @@ def post_link(say, context, event, client):
83151

84152
# send the message
85153
thread_ts = event.get("thread_ts", None)
86-
if thread_ts == None:
154+
if thread_ts is None:
87155
say(
88156
text=text.strip("\n"),
89157
thread_ts=event.get("ts"),
@@ -98,17 +166,27 @@ def post_link(say, context, event, client):
98166

99167
# exit handler
100168
def cleanup(signal_received, frame):
101-
print("\nShutting down PiazzaBot...")
102-
db.close()
103-
print("goodbye!")
169+
logging.info("Shutting down PiazzaBot...")
170+
171+
global cache
172+
global engine
173+
with Session(engine) as session:
174+
for workspace in cache:
175+
course = Course(workspace=workspace, forum=cache[workspace])
176+
session.merge(course)
177+
session.commit()
178+
179+
logging.info("goodbye!")
104180
exit(0)
105181

106182

107183
# Run the app
108184
if __name__ == "__main__":
109185
signal(SIGINT, cleanup)
110186

111-
for record in db:
112-
cache[record['workspace']] = record['forum']
187+
with Session(engine) as session:
188+
courses = session.query(Course)
189+
for course in courses:
190+
cache[course.workspace] = course.forum
113191

114-
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
192+
app.start(port=int(os.environ.get("PORT", 443)))

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
slack_bolt
2-
python-dotenv
3-
tinydb
2+
pymysql
3+
SQLAlchemy

0 commit comments

Comments
 (0)