Add initial support for discord threads

This commit is contained in:
Logan Hunt 2023-02-01 18:23:23 -07:00
parent a26256700d
commit fcabcdb5cb
No known key found for this signature in database
GPG Key ID: 8AC6A4B840C0EC49
6 changed files with 80 additions and 15 deletions

View File

@ -17,6 +17,7 @@ SERVER_REDIRECT_URI=http://127.0.0.1:3000/api/oauth/redirect
DISCORD_CLIENT_ID= DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET= DISCORD_CLIENT_SECRET=
DISCORD_USER_AGENT= DISCORD_USER_AGENT=
DISCORD_BOT_TOKEN=
JWT_SECRET=aVerySecretJwtSigningSecret JWT_SECRET=aVerySecretJwtSigningSecret
@ -29,4 +30,4 @@ REDIS_PORT=6379
NEW_GAME_PINGABLE_ROLE_ID=1123232 NEW_GAME_PINGABLE_ROLE_ID=1123232
NEW_GAME_CHANNEL_WEBHOOK=https://discordapp.com/api/webhooks/ NEW_GAME_CHANNEL_WEBHOOK=https://discordapp.com/api/webhooks/
REMIND_MOVE_CHANNEL_WEBHOOK=https://discordapp.com/api/webhooks/ REMIND_MOVE_CHANNEL_ID=

View File

@ -15,7 +15,7 @@ config :chessh, RateLimits,
player_public_keys: 15, player_public_keys: 15,
create_game_ms: 60 * 1000, create_game_ms: 60 * 1000,
create_game_rate: 3, create_game_rate: 3,
discord_notification_rate: 3, discord_notification_rate: 30,
discord_notification_rate_ms: 1000 discord_notification_rate_ms: 1000
config :chessh, Web, config :chessh, Web,

View File

@ -5,8 +5,9 @@ config :chessh,
config :chessh, DiscordNotifications, config :chessh, DiscordNotifications,
looking_for_games_role_mention: "<@&#{System.get_env("NEW_GAME_PINGABLE_ROLE_ID")}>", looking_for_games_role_mention: "<@&#{System.get_env("NEW_GAME_PINGABLE_ROLE_ID")}>",
discord_game_move_notif_webhook: System.get_env("REMIND_MOVE_CHANNEL_WEBHOOK"), remind_move_channel_id: System.get_env("REMIND_MOVE_CHANNEL_ID"),
discord_new_game_notif_webhook: System.get_env("NEW_GAME_CHANNEL_WEBHOOK") discord_bot_token: System.get_env("DISCORD_BOT_TOKEN"),
new_game_channel_id: System.get_env("NEW_GAME_CHANNEL_ID")
config :chessh, Web, config :chessh, Web,
discord_client_id: System.get_env("DISCORD_CLIENT_ID"), discord_client_id: System.get_env("DISCORD_CLIENT_ID"),

View File

@ -50,9 +50,9 @@ defmodule Chessh.DiscordNotifier do
end end
defp send_notification({:move_reminder, game_id}) do defp send_notification({:move_reminder, game_id}) do
[min_delta_t, discord_game_move_notif_webhook] = [min_delta_t, remind_move_channel_id] =
Application.get_env(:chessh, DiscordNotifications) Application.get_env(:chessh, DiscordNotifications)
|> Keyword.take([:game_move_notif_delay_ms, :discord_game_move_notif_webhook]) |> Keyword.take([:game_move_notif_delay_ms, :remind_move_channel_id])
|> Keyword.values() |> Keyword.values()
case Repo.get(Game, game_id) |> Repo.preload([:dark_player, :light_player]) do case Repo.get(Game, game_id) |> Repo.preload([:dark_player, :light_player]) do
@ -62,13 +62,22 @@ defmodule Chessh.DiscordNotifier do
turn: turn, turn: turn,
updated_at: last_updated, updated_at: last_updated,
moves: move_count, moves: move_count,
status: :continue status: :continue,
} -> discord_thread_id: discord_thread_id
} = game ->
if is_nil(discord_thread_id) do
{:ok, game} =
Game.changeset(game, %{
discord_thread_id: make_private_discord_thread_id(remind_move_channel_id, game)
})
|> Repo.update()
end
delta_t = NaiveDateTime.diff(NaiveDateTime.utc_now(), last_updated, :millisecond) delta_t = NaiveDateTime.diff(NaiveDateTime.utc_now(), last_updated, :millisecond)
if delta_t >= min_delta_t do if delta_t >= min_delta_t do
post_discord( post_discord(
discord_game_move_notif_webhook, game.discord_thread_id,
"<@#{if turn == :light, do: light_player_discord_id, else: dark_player_discord_id}> it is your move in Game #{game_id} (move #{move_count})." "<@#{if turn == :light, do: light_player_discord_id, else: dark_player_discord_id}> it is your move in Game #{game_id} (move #{move_count})."
) )
end end
@ -79,9 +88,9 @@ defmodule Chessh.DiscordNotifier do
end end
defp send_notification({:game_created, game_id}) do defp send_notification({:game_created, game_id}) do
[pingable_mention, discord_game_created_notif_webhook] = [pingable_mention, new_game_channel_id] =
Application.get_env(:chessh, DiscordNotifications) Application.get_env(:chessh, DiscordNotifications)
|> Keyword.take([:looking_for_games_role_mention, :discord_new_game_notif_webhook]) |> Keyword.take([:looking_for_games_role_mention, :new_game_channel_id])
|> Keyword.values() |> Keyword.values()
case Repo.get(Game, game_id) do case Repo.get(Game, game_id) do
@ -107,16 +116,16 @@ defmodule Chessh.DiscordNotifier do
end end
if message do if message do
post_discord(discord_game_created_notif_webhook, message) post_discord(new_game_channel_id, message)
end end
end end
end end
defp post_discord(webhook, message) do defp post_discord(channel_id, message) do
:httpc.request( :httpc.request(
:post, :post,
{ {
String.to_charlist(webhook), 'https://discord.com/api/channels/#{channel_id}/messages',
[], [],
'application/json', 'application/json',
%{content: message} |> Jason.encode!() |> String.to_charlist() %{content: message} |> Jason.encode!() |> String.to_charlist()
@ -125,4 +134,48 @@ defmodule Chessh.DiscordNotifier do
[] []
) )
end end
defp make_private_discord_thread_id(channel_id, %Game{
dark_player: %Player{discord_id: dark_player_discord_id},
light_player: %Player{discord_id: light_player_discord_id}
}) do
%{"id" => thread_id} =
:httpc.request(
:post,
{
'https://discord.com/api/channels/#{channel_id}/threads',
[
make_authorization_header()
],
'application/json',
%{
# Private thread
type: 12
}
|> Jason.encode!()
|> String.to_charlist()
},
[],
[]
)
|> Jason.decode!()
[light_player_discord_id, dark_player_discord_id]
|> Enum.map(fn id ->
:httpc.request(
:post,
{
'https://discord.com/api/channels/#{thread_id}/thread-members/#{id}',
[]
}
)
end)
thread_id
end
defp make_authorization_header() do
bot_token = Application.get_env(:chessh, DiscordNotifications)[:discord_bot_token]
{'Authorization', 'Bot #{bot_token}'}
end
end end

View File

@ -15,6 +15,8 @@ defmodule Chessh.Game do
belongs_to(:light_player, Player, foreign_key: :light_player_id) belongs_to(:light_player, Player, foreign_key: :light_player_id)
belongs_to(:dark_player, Player, foreign_key: :dark_player_id) belongs_to(:dark_player, Player, foreign_key: :dark_player_id)
field(:discord_thread_id, :string)
timestamps() timestamps()
end end
@ -28,7 +30,8 @@ defmodule Chessh.Game do
:status, :status,
:last_move, :last_move,
:light_player_id, :light_player_id,
:dark_player_id :dark_player_id,
:discord_thread_id
]) ])
end end
end end

View File

@ -0,0 +1,7 @@
defmodule Chessh.Repo.Migrations.AddDiscordThreadId do
use Ecto.Migration
def change do
end
end