Skip to content

Commit 6154054

Browse files
committedSep 4, 2024··
feat: discord functions for using private threads
They're not actually used anywhere yet, but they can be used to create threads for sessions, add members and send messages/notify members.
1 parent 4535f16 commit 6154054

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ To get started you need to set up a discord bot, and then create a
4141
:discord/client-id "..."
4242
:discord/public-key "..."
4343
:discord/server-id "..."
44+
:discord/session-channel-id "..." ;; ID of the channel where session threads will be created
4445
:discord/ticket-holder-role "role-id"
4546
:discord/ticket-roles
4647
{"release-slug" "role-id"}}

‎src/co/gaiwan/compass/db/schema.clj

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
[:session/ticket-required? :boolean "If this session requires a ticket"]
5858
[:session/published? :boolean "If this session is published/visible?"]
5959
[:session/participants :ref "reference points to the user" :many]
60+
[:session/thread-id :string "ID of the Discord thread associated with the session, if any"]
6061

6162
[:session.type/name :string "Type of session, e.g. talk, activity"]
6263
[:session.type/color :string "CSS color or var reference used for rendering"]

‎src/co/gaiwan/compass/services/discord.clj

+79-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
[clojure.string :as str]
55
[co.gaiwan.compass.config :as config]
66
[hato.client :as hato]
7-
[io.pedestal.log :as log]))
7+
[io.pedestal.log :as log]
8+
[co.gaiwan.compass.db :as db]))
89

910
(def discord-api-endpoint "https://discord.com/api/v10")
1011

@@ -23,7 +24,7 @@
2324
:as :auto
2425
:headers (bot-auth-headers)}
2526
body (assoc :content-type :json :form-params body)))]
26-
(log/trace :discord/request (:request response) :discord/response (dissoc response :request))
27+
(log/trace :discord/request (-> response :request (update :headers dissoc "Authorization")) :discord/response (dissoc response :request))
2728
response)))
2829

2930
(defn fetch-user-info [token]
@@ -71,3 +72,79 @@
7172
"late-conference"
7273
"student"} slug)
7374
(conj "regular-ticket")))))
75+
76+
(defn create-session-thread
77+
"Create private thread for session in channel configured by `:discord/session-channel-id`."
78+
[session]
79+
(let [{:keys [status] thread :body :as response}
80+
(discord-bot-request
81+
:post
82+
(str "/channels/" (config/value :discord/session-channel-id) "/threads")
83+
{:name (->> session :session/title (take 100) str/join)
84+
:type 12 ;; PRIVATE_THREAD
85+
:invitable true})]
86+
(case status
87+
201
88+
(do
89+
(db/transact [[:db/add (:db/id session) :session/thread-id (:id thread)]])
90+
thread)
91+
(log/error :discord/thread-create-failed "Failed to create session thread"
92+
:session session
93+
:response (dissoc response :request)))))
94+
95+
(defn get-session-thread
96+
"Get existing thread for session (or `nil`)."
97+
[session]
98+
(let [id (:session/thread-id session)
99+
{channel :body :keys [status] :as response} (discord-bot-request :get (str "/channels/" id))]
100+
(case status
101+
;; thread already exists
102+
200 channel
103+
;; thread does not exist
104+
404 nil
105+
;; something else?
106+
(log/error
107+
:discord/thread-fetch-failed (str "Unhandled status code " status " for getting session thread")
108+
:session session
109+
:response (dissoc response :request)))))
110+
111+
(defn user-mention
112+
"Discord ID -> text that pings user"
113+
[user-id]
114+
(str "<@" user-id ">"))
115+
116+
(defn send-session-thread-message
117+
"Send a message to the session thread belonging to `session-id`.
118+
119+
Returns `nil`.
120+
A `message` containing @everyone will send a notification to all thread members.
121+
A `message` mentioning one or more individual users ([[user-mention]]) will notify and add those users to the thread.
122+
Will fail if there is no session thread (yet) or if the sending the message fails.
123+
In both cases, an error message is logged."
124+
[session-id message]
125+
(if-let [{:keys [id] :as _thread} (get-session-thread (db/entity session-id))]
126+
(let [{:keys [status] :as response}
127+
(discord-bot-request
128+
:post
129+
(str "/channels/" id "/messages")
130+
{:content message
131+
:allowed_mentions {:parse ["users" "everyone"]}})]
132+
(when-not (= status 200)
133+
(log/error
134+
:discord/message-send-fail "Failed to send message to session thread"
135+
:session (db/entity session-id)
136+
:response (dissoc response :request))))
137+
(log/error :discord/missing-session-thread "Tried to send message to session thread that doesn't exist")))
138+
139+
(defn add-to-session-thread
140+
"Add user with `user-id` to session thread of session with `session-id`.
141+
142+
Returns `nil`. In case of failure, an error message is logged."
143+
[session-id user-id]
144+
(let [session (db/entity session-id)
145+
{:keys [status] :as response} (discord-bot-request :put (str "/channels/" (:session/thread-id session) "/thread-members/" user-id))]
146+
(when-not (= status 204)
147+
(log/error
148+
:discord/thread-member-add-failed "Failed to add member to session thread"
149+
:session session
150+
:response (dissoc response :request)))))

0 commit comments

Comments
 (0)
Please sign in to comment.