diff --git a/lib/mocks/nostrum_api.ex b/lib/mocks/nostrum_api.ex index 188561d..9f2ac05 100644 --- a/lib/mocks/nostrum_api.ex +++ b/lib/mocks/nostrum_api.ex @@ -4,4 +4,5 @@ defmodule PlantIdDiscordBotTest.Mocks.Nostrum.Api do """ def create_interaction_response(_interaction, response), do: {:ok, response} + def get_application_info(), do: {:ok, %{name: "Test Bot", owner: %{username: "Test User"}}} end diff --git a/lib/plantid_discord_bot.ex b/lib/plantid_discord_bot.ex index fbe870a..9c645d5 100644 --- a/lib/plantid_discord_bot.ex +++ b/lib/plantid_discord_bot.ex @@ -34,4 +34,19 @@ defmodule PlantIdDiscordBot do def handle_event({:INTERACTION_CREATE, %{data: %{name: "source"}} = interaction, _ws_state}) do Cog.Info.source(interaction) end + + # Handle /invite command + def handle_event({:INTERACTION_CREATE, %{data: %{name: "invite"}} = interaction, _ws_state}) do + Cog.Info.invite(interaction) + end + + # Handle /help command + def handle_event({:INTERACTION_CREATE, %{data: %{name: "help"}} = interaction, _ws_state}) do + Cog.Info.help(interaction) + end + + # Handle /info command + def handle_event({:INTERACTION_CREATE, %{data: %{name: "info"}} = interaction, _ws_state}) do + Cog.Info.info(interaction) + end end diff --git a/lib/plantid_discord_bot/cogs/info.ex b/lib/plantid_discord_bot/cogs/info.ex index 117e21d..607bc29 100644 --- a/lib/plantid_discord_bot/cogs/info.ex +++ b/lib/plantid_discord_bot/cogs/info.ex @@ -1,8 +1,11 @@ defmodule PlantIdDiscordBot.Cog.Info do use Nostrum.Consumer + import Nostrum.Struct.Embed + alias PlantIdDiscordBot.Utils @api Application.compile_env(:plantid_discord_bot, :api) @source Application.compile_env(:plantid_discord_bot, :source) + @invite Application.compile_env(:plantid_discord_bot, :invite) @doc """ Sends a link to the source code for this bot. @@ -10,4 +13,60 @@ defmodule PlantIdDiscordBot.Cog.Info do def source(interaction) do @api.create_interaction_response(interaction, %{type: 4, data: %{content: @source}}) end + + @doc """ + Sends an invite link for this bot. + """ + def invite(interaction) do + message = "Invite the bot to your server:\n\n[Click Here](#{@invite})" + @api.create_interaction_response(interaction, %{type: 4, data: %{content: message}}) + end + + @doc """ + Help menu for the bot. + """ + def help(interaction) do + embed = + %Nostrum.Struct.Embed{} + |> put_title("Let's break this down a bit") + |> put_description("Use the `/id` command and add up to 5 photos\n\n") + |> put_author( + "Plant ID Bot", + "https://discordapp.com", + "https://cdn.discordapp.com/embed/avatars/0.png" + ) + |> put_footer( + "Powered by Pl@ntNet API", + "https://www.iona.edu/sites/default/files/2021-04/ancillary-images/green-flower.jpg" + ) + |> put_field( + "For best results:", + "- all photos should be of the same plant\n- take photos of organs, not the whole plant\n- best results will be achieved by using a mixture of organs\n- use images at least 600x600px\n\n", + true + ) + |> put_field("/info", "for more commands") + + response = %{type: 4, data: %{embeds: [embed]}} + @api.create_interaction_response(interaction, response) + end + + @doc """ + Information about the bot. + """ + def info(interaction) do + {:ok, app_info} = @api.get_application_information() + + embed = + %Nostrum.Struct.Embed{} + |> put_title(app_info.name) + |> put_description("Stats etc.") + |> put_color(0x1AAAE5) + |> put_field("Server Count", app_info.approximate_guild_count, true) + |> put_field("Uptime", Utils.get_uptime(), true) + |> put_field("Latency", Utils.get_shard_latency(), true) + |> put_footer("Made by #{app_info.owner.username}") + + response = %{type: 4, data: %{embeds: [embed]}} + @api.create_interaction_response(interaction, response) + end end diff --git a/lib/plantid_discord_bot/cogs/plantnet.ex b/lib/plantid_discord_bot/cogs/plantnet.ex new file mode 100644 index 0000000..bb14b67 --- /dev/null +++ b/lib/plantid_discord_bot/cogs/plantnet.ex @@ -0,0 +1,3 @@ +defmodule PlantIdDiscordBot.Cog.PlantNet do + use Nostrum.Consumer +end diff --git a/lib/utils.ex b/lib/utils.ex new file mode 100644 index 0000000..baf6c7b --- /dev/null +++ b/lib/utils.ex @@ -0,0 +1,15 @@ +defmodule PlantIdDiscordBot.Utils do + @start_time Application.compile_env(:plantid_discord_bot, :start_time) + + def get_uptime() do + DateTime.diff(DateTime.utc_now(), @start_time) + |> PlantIdDiscordBot.Utils.Duration.sec_to_str() + end + + def get_shard_latency() do + Nostrum.Util.get_all_shard_latencies() + |> Map.get(0) + |> to_string() + |> Kernel.<>("ms") + end +end diff --git a/lib/utils/duration.ex b/lib/utils/duration.ex new file mode 100644 index 0000000..8bf9a8f --- /dev/null +++ b/lib/utils/duration.ex @@ -0,0 +1,19 @@ +# https://rosettacode.org/wiki/Convert_seconds_to_compound_duration +defmodule PlantIdDiscordBot.Utils.Duration do + @minute 60 + @hour @minute * 60 + @day @hour * 24 + @week @day * 7 + @divisor [@week, @day, @hour, @minute, 1] + + def sec_to_str(sec) do + {_, [s, m, h, d, w]} = + Enum.reduce(@divisor, {sec, []}, fn divisor, {n, acc} -> + {rem(n, divisor), [div(n, divisor) | acc]} + end) + + ["#{w}w", "#{d}d", "#{h}h", "#{m}m", "#{s}s"] + |> Enum.reject(fn str -> String.starts_with?(str, "0") end) + |> Enum.join(" ") + end +end diff --git a/test/cogs_test.exs b/test/cogs_test.exs new file mode 100644 index 0000000..f31b887 --- /dev/null +++ b/test/cogs_test.exs @@ -0,0 +1,5 @@ +defmodule PlantIdDiscordBotTest.Cog do + use ExUnit.Case + doctest PlantIdDiscordBot.Cog.Info + doctest PlantIdDiscordBot.Cog.PlantNet +end diff --git a/test/commands/help_test.exs b/test/commands/help_test.exs new file mode 100644 index 0000000..2dd3729 --- /dev/null +++ b/test/commands/help_test.exs @@ -0,0 +1,9 @@ +defmodule PlantIdDiscordBotTest.Cog.Help do + use ExUnit.Case + + test "/help" do + {:ok, response} = PlantIdDiscordBot.Cog.Info.help(%{data: %{name: "help"}}) + [embed] = response[:data][:embeds] + assert match?(%Nostrum.Struct.Embed{}, embed) + end +end diff --git a/test/commands/invite_test.exs b/test/commands/invite_test.exs new file mode 100644 index 0000000..2d2ceea --- /dev/null +++ b/test/commands/invite_test.exs @@ -0,0 +1,17 @@ +defmodule PlantIdDiscordBotTest.Cog.Invite do + use ExUnit.Case + + @invite Application.compile_env(:plantid_discord_bot, :invite) + + test "/invite" do + {:ok, response} = PlantIdDiscordBot.Cog.Info.invite(%{data: %{name: "invite"}}) + message = "Invite the bot to your server:\n\n[Click Here](#{@invite})" + + expected_response = %{ + type: 4, + data: %{content: message} + } + + assert response == expected_response + end +end diff --git a/test/commands/source_test.exs b/test/commands/source_test.exs index 400c676..6381f18 100644 --- a/test/commands/source_test.exs +++ b/test/commands/source_test.exs @@ -3,14 +3,14 @@ defmodule PlantIdDiscordBotTest.Cog.Source do @source Application.compile_env(:plantid_discord_bot, :source) - test "source" do - interaction = %{data: %{name: "source"}} + test "/source" do + {:ok, response} = PlantIdDiscordBot.Cog.Info.source(%{data: %{name: "source"}}) expected_response = %{ type: 4, data: %{content: @source} } - assert PlantIdDiscordBot.Cog.Info.source(interaction) == {:ok, expected_response} + assert response == expected_response end end