From 121e2530742b8c95a5cc03c1e1ad29f7548323fd Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 13:29:45 +0200 Subject: [PATCH 01/30] Avoid showing menu for other bots --- lib/bot/benvolios.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bot/benvolios.ex b/lib/bot/benvolios.ex index a1d2814..76a507a 100644 --- a/lib/bot/benvolios.ex +++ b/lib/bot/benvolios.ex @@ -56,7 +56,7 @@ defmodule Bot.Benvolios do end # Prints out help message. - def on_message(<<"help"::utf8>>, _channel, _sender) do + def on_message(<<"help"::utf8>>, @channel, _sender) do res = """ ``` order : Order something. From 4d2e0d3fe2393366423d0f50656087954aa7e73e Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 13:31:42 +0200 Subject: [PATCH 02/30] Fix warnings for unused arguments --- lib/bot/misc.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bot/misc.ex b/lib/bot/misc.ex index 28d95a5..2d386fd 100644 --- a/lib/bot/misc.ex +++ b/lib/bot/misc.ex @@ -7,7 +7,7 @@ defmodule Bot.Misc do {:ok,"My owner is #{@owner}"} end - def on_message(<<"!bug "::utf8, target::bitstring>>, channel, from) do + def on_message(<<"!bug "::utf8, target::bitstring>>, _channel, _from) do {:ok, "#{target}, seems like are not happy with the current operations of the bot. If you feel like this hinders you in any way, feel free to write a patch and submit it on GitHub. You can find the repository at #{@github}"} end From 21e32ead529ad005c269fecf0f6f4846ac4c6f0d Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 13:32:32 +0200 Subject: [PATCH 03/30] Update dependencies to avoid warning on Elixir 1.5 --- mix.exs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mix.exs b/mix.exs index 6a20a75..73be5b6 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Slackbot.Mixfile do def project do [app: Slackbot, version: "0.0.1", - elixir: "~> 1.4", + elixir: "~> 1.5", deps: deps()] end @@ -26,12 +26,13 @@ defmodule Slackbot.Mixfile do # # Type `mix help deps` for more examples and options defp deps do - [{:exgenius, "~> 0.0.2"}, + [ +# {:exgenius, "~> 0.0.5"}, {:slack, "~> 0.12.0"}, - {:poison, "~> 3.0"}, - {:timex, "~> 3.1.7"}, - {:feeder_ex, "~> 1.0"}, - {:html_entities, "~> 0.3"} + {:poison, "~> 3.1.0"}, + {:timex, "~> 3.1.24"}, + {:feeder_ex, "~> 1.1"}, + {:html_entities, "~> 0.4.0"} ] end end From b0d7bfc1f0e2cce42dec6965328fbbca197b52c8 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 13:33:37 +0200 Subject: [PATCH 04/30] Add initial version of the dishwasher-manager bot --- lib/bot/diswasher_manager.ex | 112 +++++++++++++++++++ lib/brain/dishwasher_manager.ex | 190 ++++++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+) create mode 100644 lib/bot/diswasher_manager.ex create mode 100644 lib/brain/dishwasher_manager.ex diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex new file mode 100644 index 0000000..8c23319 --- /dev/null +++ b/lib/bot/diswasher_manager.ex @@ -0,0 +1,112 @@ +defmodule Bot.DiswasherManager do + require Logger + use Plugin + + @boss Application.fetch_env!(:slack, :diswasher_duties_owner) + @channel Application.fetch_env!(:slack, :diswasher_duties_channel) + + # The message "swap_with @x" is used to swap weekly duties with the user `x`. + def on_message(<<"swap_with"::utf8, user::bitstring>>, @channel, sender) do + case Brain.DishwasherManager.swap_duties(sender, user) do + :ok -> {:ok, "Duties swapped!"} + {:error, msg} -> {:ok, msg} + end + end + + # The message "who_is?" return the name uf the current dishwasher manager + def on_message(<<"manager?"::utf8, _rest::bitstring>>, @channel, _sender) do + Logger.debug "bot -> manager?" + {:ok, manager} = Brain.DishwasherManager.manager?() + + case manager do + :no_specified -> {:ok, "The schedule has not been created. Use the command 'help' for more information."} + name -> {:ok, "The current dishwasher manager is `#{manager}`"} + end + + + end + + # Prints out all the outstanding orders. + # Restricted to admins only. + def on_message(<<"schedule"::utf8, _::bitstring>>, @channel, _sender) do + {:ok, schedule} = Brain.DishwasherManager.schedule() + build_schedule_list(schedule) + end + + # Prints out all the outstanding orders. + # Restricted to admins only. + def on_message(<<"create_schedule"::utf8, startDate::bitstring>>, @channel, @boss) do + {:ok, schedule} = Brain.DishwasherManager.create_schedule(startDate) + build_schedule_list(schedule) + end + + def on_message(<<"users"::utf8, _::bitstring>>, @channel, _sender) do + {:ok, users} = Brain.DishwasherManager.users() + build_user_list(users) + end + + def on_message(<<"add_user"::utf8, userDetails::bitstring>>, @channel, @boss) do + case String.split(userDetails) do + [] -> {:noreply} + [user| fullname] -> :ok = Brain.DishwasherManager.add_user(user, fullname) + {:ok, "The user {#{user}, #{fullname}} has been saved."} + end + end + + def on_message(<<"remove_user"::utf8, user::bitstring>>, @channel, @boss) do + :ok = Brain.DishwasherManager.remove_user(user) + {:ok, "The user #{user} has been removed."} + end + + # Prints out help message. + def on_message(<<"help"::utf8>>, @channel, _sender) do + res = """ + ``` + swap_with : Swaps weekly duties with another person. + Example: "swap_with @cdtroye". + manager? : Shows the current dishwasher manager. + Example: "manager?" + schedule : Shows the current dishwasher schedule. + Example: "schedule" + create_schedule : Creates a dishwasher schedule starting from the date specified. + Example: "create_schedule 2017-09-07" + users : Shows the current list of users. + Example: "users" + add_user : Add a new user. The first argument is the "slack user name", + followed by its fullname. + Example: "add_user @humberto Humberto Rodriguez Avila" + add_user : Remove an user. + Example: "remove_user @humberto" + ``` + Ps: Only the admin can execute `create_schedule`, `add_user`, and `remove_user` + + """ + {:ok, res} + end + + def on_message(_text, _hannel, _sender) do + {:noreply} + end + + defp build_schedule_list(%{}), do: {:ok, "There is no schedule ready. Use the command 'help' for more information."} + + defp build_schedule_list(schedule) do + resp = schedule + |> Enum.map(fn {_k,{fullname, date}} -> "- #{fullname} -> #{date}-#{Date.add(date, 4)}" end) + |> Enum.join("\n") + + {:ok, "```#{resp}```"} + end + + defp build_user_list(%{}), do: {:ok, "The list of user is empty. Use the command 'help' for more information."} + + defp build_user_list(users) do + resp = users + |> Enum.map(fn {user, fullname} -> "- #{fullname} (#{user})" end) + |> Enum.join("\n") + + {:ok, "```#{resp}```"} + end + + +end diff --git a/lib/brain/dishwasher_manager.ex b/lib/brain/dishwasher_manager.ex new file mode 100644 index 0000000..737e965 --- /dev/null +++ b/lib/brain/dishwasher_manager.ex @@ -0,0 +1,190 @@ +defmodule Brain.DishwasherManager do + require Logger + use GenServer + + @users_file "data/dishwasher_manager/users.dat" + @schedule_file "data/dishwasher_manager/schedule.dat" + + def start_link(initial_state \\ []) do + GenServer.start_link __MODULE__, [initial_state], name: __MODULE__ + end + + def init([[]]) do + Logger.debug "No orders provided. Reading from disk." + case restore_state() do + {:ok, state} -> + {:ok, state} + _ -> + Logger.warn "No initial orders and can't read backup, starting with empty order." + {:ok, {%{}, %{}, :no_specified}} + end + end + + def init([state]) do + {:ok, state} + + end + + ############# + # Interface # + ############# + + def swap_duties(userA, userB) do + GenServer.call __MODULE__, {:swap, userA, userB} + end + + def manager?() do + GenServer.call __MODULE__, :manager? + end + + def schedule() do + GenServer.call __MODULE__, :schedule + end + + def create_schedule(startDate) do + GenServer.call __MODULE__, {:create_schedule, startDate} + end + + def users() do + GenServer.call __MODULE__, :users + end + + def add_user(user, fullname) do + GenServer.call __MODULE__, {:add_user, user, fullname} + end + + def remove_user(user) do + GenServer.call __MODULE__, {:remove_user, user} + end + + + ######### + # Calls # + ######### + + def handle_call(:users, _from, {_, users, _} = state) do + Logger.debug "brain -> users" + {:reply, {:ok, users}, state} + end + + def handle_call(:manager?, _from, {_, _, manager} = state) do + Logger.debug "brain -> manager?" + {:reply, {:ok, manager}, state} + end + + def handle_call(:schedule, _from, {schedule, _,_} = state) do + Logger.debug "brain -> schedule" + {:reply, {:ok, schedule}, state} + end + + def handle_call({:create_schedule, startDate}, _from, {_, users, }) do + Logger.debug "brain -> create_schedule" + usersList = Map.to_list users + {_, manager} = List.first(usersList) + schedule = build_schedule(usersList, startDate) + {:reply, {:ok, schedule}, {schedule, users, manager}} + end + + def handle_call({:add_user, user, fullname}, _from, {schedule, users, manager}) do + Logger.debug "brain -> add_user #{user}" + fullname = buildFullName(fullname) + users = Map.put_new(users, user, fullname) + schedule = add_to_schedule(schedule, user, fullname) + save_state(users, @users_file) + {:reply, :ok, {schedule, users, manager}} + end + + + def handle_call({:remove_user, user}, _from, {schedule, users, manager}) do + Logger.debug "brain -> remove_user #{user}" + users = Map.delete(users, user) + save_state(users, @users_file) + {:reply, :ok, {schedule, users, manager}} + end + + def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) do + Logger.debug "brain -> swap order for duties of user #{userA} with #{userB}" + + case validate_user_names([userA, userB], users) do + true -> + {_, dateA} = Map.get(users, userA) + {_, dateB} = Map.get(users, userB) + + schedule = schedule + |> Map.replace!(userA, dateB) + |> Map.replace!(userB, dateA) + + save_state(schedule, @schedule_file) + {:reply, :ok, {schedule, users, manager}} + + msg -> {:reply, {:error, msg}, {schedule, users, manager}} + + end + end + + + + ########### + # Private # + ########### + + defp save_state(data, file) do + content = :io_lib.format("~tp.~n", [data]) + :ok = :file.write_file(file, content) + end + + defp restore_state() do + usersData = :file.consult(@users_file) + scheduleData = :file.consult(@schedule_file) + + users = case usersData do + {:ok, [values]} -> values + _ -> {:error} + end + + schedule = case scheduleData do + {:ok, [values]} -> values + _ -> {:error} + end + + {schedule, users} + end + + defp buildFullName(fullName, acc \\ "") + defp buildFullName([], acc) do + String.trim(acc) + end + defp buildFullName([h|rest], acc) do + acc = acc <> " " <> h + buildFullName rest, acc + end + + defp add_to_schedule(%{} = schedule, _user, _fullName) do + schedule + end + + defp add_to_schedule(schedule, user, fullName) do + {_, {_, lastDate}} = schedule + |> Enum.to_list + |> List.last + Map.put(schedule, user, {fullName, Date.add(lastDate, 7)}) + end + + defp validate_user_names([user| rest], users) do + case Map.has_key?(users, user) do + false -> "Invalid username! The user #{user} is not a registered." + _ -> validate_user_names(rest, users) + end + end + + defp build_schedule(list, startDate, schedule \\ %{}) + + defp build_schedule([], _startDate, schedule), do: schedule + + defp build_schedule([{k, v} | rest], startDate, schedule) do + schedule = Map.put(schedule, k, {v, startDate} ) + nextDate = Date.add(startDate, 7) + build_schedule(rest,nextDate, schedule ) + end + +end From 4a7fd8686a3de945e681db7795ad41961cf2f23b Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 13:34:24 +0200 Subject: [PATCH 05/30] Add dishwasher-manager bot workers --- lib/supervisor/bot.ex | 15 ++++++++------- lib/supervisor/brain.ex | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/supervisor/bot.ex b/lib/supervisor/bot.ex index 0f34434..eec9270 100644 --- a/lib/supervisor/bot.ex +++ b/lib/supervisor/bot.ex @@ -7,13 +7,14 @@ defmodule Supervisor.Bot do def init(opts) do children = [ - worker(Bot.Karma, [opts]), - worker(Bot.ChuckNorris, [opts]), - worker(Bot.Resto, [opts]), - worker(Bot.Cronjob, [opts]), - worker(Bot.Rss, [opts]), - worker(Bot.Benvolios, [opts]), - worker(Bot.Misc, [opts]) + worker(Bot.Karma, [opts]), + worker(Bot.ChuckNorris, [opts]), + worker(Bot.Resto, [opts]), + worker(Bot.Cronjob, [opts]), + worker(Bot.Rss, [opts]), + worker(Bot.Benvolios, [opts]), + worker(Bot.DiswasherManager, [opts]), + worker(Bot.Misc, [opts]) ] supervise(children, strategy: :one_for_one) end diff --git a/lib/supervisor/brain.ex b/lib/supervisor/brain.ex index bc69476..65a5a3d 100644 --- a/lib/supervisor/brain.ex +++ b/lib/supervisor/brain.ex @@ -8,7 +8,8 @@ defmodule Supervisor.Brain do def init(_state) do children = [ worker(Brain.Karma, []), - worker(Brain.Benvolios, []) + worker(Brain.Benvolios, []), + worker(Brain.DishwasherManager, []) ] supervise children, strategy: :one_for_one end From dc2c120a66f4787bd97e2665f7d74339458a1be4 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 13:47:01 +0200 Subject: [PATCH 06/30] Update dependencies --- mix.lock | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/mix.lock b/mix.lock index 201238b..e98d8aa 100644 --- a/mix.lock +++ b/mix.lock @@ -1,21 +1,21 @@ -%{"certifi": {:hex, :certifi, "1.2.1", "c3904f192bd5284e5b13f20db3ceac9626e14eeacfbb492e19583cf0e37b22be", [:rebar3], [], "hexpm"}, - "combine": {:hex, :combine, "0.9.6", "8d1034a127d4cbf6924c8a5010d3534d958085575fa4d9b878f200d79ac78335", [:mix], [], "hexpm"}, - "exgenius": {:hex, :exgenius, "0.0.5", "bf486cffa31c4add0b600193939438b9a4936540435880ba08066e0dafcf2226", [:mix], [{:exjsx, "~> 3.1", [hex: :exjsx, repo: "hexpm", optional: false]}, {:httpoison, "~> 0.5", [hex: :httpoison, repo: "hexpm", optional: false]}], "hexpm"}, - "exjsx": {:hex, :exjsx, "3.2.1", "1bc5bf1e4fd249104178f0885030bcd75a4526f4d2a1e976f4b428d347614f0f", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"}, - "feeder": {:hex, :feeder, "2.2.1", "9b1236d32cf971a049968b4c3955fa4808bd132b347af6e30a06fc2093751796", [:make], [], "hexpm"}, - "feeder_ex": {:hex, :feeder_ex, "1.1.0", "0be3732255cdb45dec949e0ede6852b5261c9ff173360e8274a6ac65183b2b55", [:mix], [{:feeder, "~> 2.2", [hex: :feeder, repo: "hexpm", optional: false]}], "hexpm"}, - "gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [:mix], [], "hexpm"}, - "hackney": {:hex, :hackney, "1.8.6", "21a725db3569b3fb11a6af17d5c5f654052ce9624219f1317e8639183de4a423", [:rebar3], [{:certifi, "1.2.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.0.2", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, - "html_entities": {:hex, :html_entities, "0.3.0", "2f278ffc69c3f0cbd5996628fef37cf922fa715f3e04b9f38924c8adced3f25a", [:mix], [], "hexpm"}, - "httpoison": {:hex, :httpoison, "0.12.0", "8fc3d791c5afe6beb0093680c667dd4ce712a49d89c38c3fe1a43100dd76cf90", [:mix], [{:hackney, "~> 1.8.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, - "idna": {:hex, :idna, "5.0.2", "ac203208ada855d95dc591a764b6e87259cb0e2a364218f215ad662daa8cd6b4", [:rebar3], [{:unicode_util_compat, "0.2.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, - "jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], [], "hexpm"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, - "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, - "slack": {:hex, :slack, "0.12.0", "a305f87adca043e056a86f92151d085a8c359718f9c4ca7f1d1012d67b75db8a", [:mix], [{:httpoison, "~> 0.11", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}, {:websocket_client, "~> 1.2.4", [hex: :websocket_client, repo: "hexpm", optional: false]}], "hexpm"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"}, - "timex": {:hex, :timex, "3.1.21", "7d1ec0f73c4668bea71f38af6357d75992f356a7e032c69620c5e87ca4b95c66", [:mix], [{:combine, "~> 0.7", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, - "tzdata": {:hex, :tzdata, "0.5.12", "1c17b68692c6ba5b6ab15db3d64cc8baa0f182043d5ae9d4b6d35d70af76f67b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], [], "hexpm"}, - "websocket_client": {:hex, :websocket_client, "1.2.4", "14ec1ca4b6d247b44ccd9a80af8f6ca98328070f6c1d52a5cb00bc9d939d63b8", [:rebar3], [], "hexpm"}} +%{"certifi": {:hex, :certifi, "1.2.1", "c3904f192bd5284e5b13f20db3ceac9626e14eeacfbb492e19583cf0e37b22be", [:rebar3], []}, + "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], []}, + "exgenius": {:hex, :exgenius, "0.0.5", "bf486cffa31c4add0b600193939438b9a4936540435880ba08066e0dafcf2226", [:mix], [{:exjsx, "~> 3.1", [hex: :exjsx, optional: false]}, {:httpoison, "~> 0.5", [hex: :httpoison, optional: false]}]}, + "exjsx": {:hex, :exjsx, "3.2.1", "1bc5bf1e4fd249104178f0885030bcd75a4526f4d2a1e976f4b428d347614f0f", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, optional: false]}]}, + "feeder": {:hex, :feeder, "2.2.1", "9b1236d32cf971a049968b4c3955fa4808bd132b347af6e30a06fc2093751796", [:make], []}, + "feeder_ex": {:hex, :feeder_ex, "1.1.0", "0be3732255cdb45dec949e0ede6852b5261c9ff173360e8274a6ac65183b2b55", [:mix], [{:feeder, "~> 2.2", [hex: :feeder, optional: false]}]}, + "gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [:mix], []}, + "hackney": {:hex, :hackney, "1.8.6", "21a725db3569b3fb11a6af17d5c5f654052ce9624219f1317e8639183de4a423", [:rebar3], [{:certifi, "1.2.1", [hex: :certifi, optional: false]}, {:idna, "5.0.2", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]}, + "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], []}, + "httpoison": {:hex, :httpoison, "0.12.0", "8fc3d791c5afe6beb0093680c667dd4ce712a49d89c38c3fe1a43100dd76cf90", [:mix], [{:hackney, "~> 1.8.0", [hex: :hackney, optional: false]}]}, + "idna": {:hex, :idna, "5.0.2", "ac203208ada855d95dc591a764b6e87259cb0e2a364218f215ad662daa8cd6b4", [:rebar3], [{:unicode_util_compat, "0.2.0", [hex: :unicode_util_compat, optional: false]}]}, + "jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], []}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []}, + "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []}, + "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []}, + "slack": {:hex, :slack, "0.12.0", "a305f87adca043e056a86f92151d085a8c359718f9c4ca7f1d1012d67b75db8a", [:mix], [{:httpoison, "~> 0.11", [hex: :httpoison, optional: false]}, {:poison, "~> 3.0", [hex: :poison, optional: false]}, {:websocket_client, "~> 1.2.4", [hex: :websocket_client, optional: false]}]}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []}, + "timex": {:hex, :timex, "3.1.24", "d198ae9783ac807721cca0c5535384ebdf99da4976be8cefb9665a9262a1e9e3", [:mix], [{:combine, "~> 0.7", [hex: :combine, optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, optional: false]}]}, + "tzdata": {:hex, :tzdata, "0.5.12", "1c17b68692c6ba5b6ab15db3d64cc8baa0f182043d5ae9d4b6d35d70af76f67b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], []}, + "websocket_client": {:hex, :websocket_client, "1.2.4", "14ec1ca4b6d247b44ccd9a80af8f6ca98328070f6c1d52a5cb00bc9d939d63b8", [:rebar3], []}} From 73978c60bbb6c94a996a596a830843a07f71f38b Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 14:00:16 +0200 Subject: [PATCH 07/30] Add beta dishwasher-manager bot --- lib/bot/diswasher_manager.ex | 4 ++-- lib/slack/slack_manager.ex | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index 8c23319..e0de406 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -20,7 +20,7 @@ defmodule Bot.DiswasherManager do case manager do :no_specified -> {:ok, "The schedule has not been created. Use the command 'help' for more information."} - name -> {:ok, "The current dishwasher manager is `#{manager}`"} + name -> {:ok, "The current dishwasher manager is `#{name}`"} end @@ -75,7 +75,7 @@ defmodule Bot.DiswasherManager do add_user : Add a new user. The first argument is the "slack user name", followed by its fullname. Example: "add_user @humberto Humberto Rodriguez Avila" - add_user : Remove an user. + remove_user : Remove an user. Example: "remove_user @humberto" ``` Ps: Only the admin can execute `create_schedule`, `add_user`, and `remove_user` diff --git a/lib/slack/slack_manager.ex b/lib/slack/slack_manager.ex index fc167db..95b920f 100644 --- a/lib/slack/slack_manager.ex +++ b/lib/slack/slack_manager.ex @@ -67,7 +67,11 @@ defmodule SlackManager do """ def handle_call({:dealias, m}, _from, state) do dealiased = ~r/\<@([a-zA-Z0-9]+)\>/ - |> Regex.replace(m, fn _, x -> dealias_userhash("#{x}", state) end) + |> Regex.replace(m, + fn _, x -> + {:ok, username} = dealias_userhash("#{x}", state) + username + end) {:reply, {:ok, dealiased}, state} end From bd2aab7a1249f0136098ecbbcae0135b38180c77 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 23:29:08 +0200 Subject: [PATCH 08/30] Add support for individual message responses --- lib/behaviours/plugin.ex | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/behaviours/plugin.ex b/lib/behaviours/plugin.ex index 715febb..d37d16e 100644 --- a/lib/behaviours/plugin.ex +++ b/lib/behaviours/plugin.ex @@ -24,18 +24,29 @@ defmodule Plugin do GenServer.start_link(__MODULE__, [args], [{:name, __MODULE__}]) end + # "Handling indidual messages" + def handle_info(message = %{channel: nil, type: "message", text: text, user: from}, state) do + reply = on_message(text, :dishwasher_app, from) + + case reply do + {:ok, reply} -> SlackManager.send_private_message("#{reply}", from) + {:error, reason} -> IO.puts "Error in plugin #{reason}" + {:noreply} -> :noop + end + + {:noreply, state} + end + def handle_info(message = %{type: "message", text: text, user: from}, state) do reply = on_message(text, message.channel, from) case reply do {:ok, reply} -> SlackManager.send_message("#{reply}", message.channel) - {:error, reason} -> - IO.puts "Error in plugin #{reason}" - {:noreply} -> - :noop + {:error, reason} -> IO.puts "Error in plugin #{reason}" + {:noreply} -> :noop end - + {:noreply, state} end From b88baa5ca7dbe1d86fde63801e55218a6826e6fb Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 23:33:10 +0200 Subject: [PATCH 09/30] Add support for multiple help menus based on user's role --- lib/bot/diswasher_manager.ex | 102 ++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index e0de406..4057ac4 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -6,16 +6,15 @@ defmodule Bot.DiswasherManager do @channel Application.fetch_env!(:slack, :diswasher_duties_channel) # The message "swap_with @x" is used to swap weekly duties with the user `x`. - def on_message(<<"swap_with"::utf8, user::bitstring>>, @channel, sender) do - case Brain.DishwasherManager.swap_duties(sender, user) do + def on_message(<<"swap_with"::utf8, user::bitstring>>, _channel, sender) do + case Brain.DishwasherManager.swap_duties(sender, String.trim(user)) do :ok -> {:ok, "Duties swapped!"} {:error, msg} -> {:ok, msg} end end # The message "who_is?" return the name uf the current dishwasher manager - def on_message(<<"manager?"::utf8, _rest::bitstring>>, @channel, _sender) do - Logger.debug "bot -> manager?" + def on_message(<<"manager?"::utf8, _rest::bitstring>>, _channel, _sender) do {:ok, manager} = Brain.DishwasherManager.manager?() case manager do @@ -28,24 +27,25 @@ defmodule Bot.DiswasherManager do # Prints out all the outstanding orders. # Restricted to admins only. - def on_message(<<"schedule"::utf8, _::bitstring>>, @channel, _sender) do + def on_message(<<"schedule"::utf8, _::bitstring>>, _channel, _sender) do {:ok, schedule} = Brain.DishwasherManager.schedule() build_schedule_list(schedule) end # Prints out all the outstanding orders. # Restricted to admins only. - def on_message(<<"create_schedule"::utf8, startDate::bitstring>>, @channel, @boss) do + def on_message(<<"create_schedule"::utf8, startDate::bitstring>>, _channel, @boss) do {:ok, schedule} = Brain.DishwasherManager.create_schedule(startDate) build_schedule_list(schedule) end - def on_message(<<"users"::utf8, _::bitstring>>, @channel, _sender) do + def on_message(<<"users"::utf8, _::bitstring>>, _channel, @boss) do {:ok, users} = Brain.DishwasherManager.users() build_user_list(users) end - def on_message(<<"add_user"::utf8, userDetails::bitstring>>, @channel, @boss) do + def on_message(<<"add_user"::utf8, userDetails::bitstring>>, _channel, @boss) do + IO.puts "----> add_user" case String.split(userDetails) do [] -> {:noreply} [user| fullname] -> :ok = Brain.DishwasherManager.add_user(user, fullname) @@ -53,42 +53,41 @@ defmodule Bot.DiswasherManager do end end - def on_message(<<"remove_user"::utf8, user::bitstring>>, @channel, @boss) do + def on_message(<<"remove_user"::utf8, user::bitstring>>, _channel, @boss) do :ok = Brain.DishwasherManager.remove_user(user) {:ok, "The user #{user} has been removed."} end + # Prints out help message. + def on_message(<<"help"::utf8>>, @channel, @boss) do + res = boss_help_menu() + {:ok, res} + end + # Prints out help message. def on_message(<<"help"::utf8>>, @channel, _sender) do - res = """ - ``` - swap_with : Swaps weekly duties with another person. - Example: "swap_with @cdtroye". - manager? : Shows the current dishwasher manager. - Example: "manager?" - schedule : Shows the current dishwasher schedule. - Example: "schedule" - create_schedule : Creates a dishwasher schedule starting from the date specified. - Example: "create_schedule 2017-09-07" - users : Shows the current list of users. - Example: "users" - add_user : Add a new user. The first argument is the "slack user name", - followed by its fullname. - Example: "add_user @humberto Humberto Rodriguez Avila" - remove_user : Remove an user. - Example: "remove_user @humberto" - ``` - Ps: Only the admin can execute `create_schedule`, `add_user`, and `remove_user` + res = user_help_menu() + {:ok, res} + end - """ + # Prints out help message. + def on_message(<<"help"::utf8>>, :dishwasher_app, @boss) do + res = boss_help_menu() {:ok, res} end + def on_message(<<"help"::utf8>>, :dishwasher_app, _sender) do + res = user_help_menu() + {:ok, res} + end + + + def on_message(_text, _hannel, _sender) do {:noreply} end - defp build_schedule_list(%{}), do: {:ok, "There is no schedule ready. Use the command 'help' for more information."} + defp build_schedule_list(schedule) when schedule == %{} , do: {:ok, "There is no schedule ready. Use the command 'help' for more information."} defp build_schedule_list(schedule) do resp = schedule @@ -98,15 +97,54 @@ defmodule Bot.DiswasherManager do {:ok, "```#{resp}```"} end - defp build_user_list(%{}), do: {:ok, "The list of user is empty. Use the command 'help' for more information."} + defp build_user_list(users) when users == %{} , do: {:ok, "The list of user is empty. Use the command 'help' for more information."} defp build_user_list(users) do resp = users - |> Enum.map(fn {user, fullname} -> "- #{fullname} (#{user})" end) + |> Enum.map(fn {user, fullname} -> "- #{fullname} (@#{user})" end) |> Enum.join("\n") {:ok, "```#{resp}```"} end + defp user_help_menu do + """ + ``` + swap_with : Swaps weekly duties with another person. + Example: "swap_with @cdtroye". + manager? : Shows the current dishwasher manager. + Example: "manager?" + schedule : Shows the current dishwasher schedule. + Example: "schedule" + users : Shows the current list of users. + Example: "users" + ``` + + """ + end + + defp boss_help_menu do + """ + ``` + swap_with : Swaps weekly duties with another person. + Example: "swap_with @cdtroye". + manager? : Shows the current dishwasher manager. + Example: "manager?" + schedule : Shows the current dishwasher schedule. + Example: "schedule" + create_schedule : Creates a dishwasher schedule starting from the date specified. + Example: "create_schedule 2017-09-07" + users : Shows the current list of users. + Example: "users" + add_user : Add a new user. The first argument is the "slack user name", + followed by its fullname. + Example: "add_user @humberto Humberto Rodriguez Avila" + remove_user : Remove an user. + Example: "remove_user @humberto" + ``` + + """ + end + end From bf821e615e1d5b6afbce9ac154e2f69d71f79fe7 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 23:34:18 +0200 Subject: [PATCH 10/30] Fix minor bugs --- lib/brain/dishwasher_manager.ex | 34 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/lib/brain/dishwasher_manager.ex b/lib/brain/dishwasher_manager.ex index 737e965..b5b466a 100644 --- a/lib/brain/dishwasher_manager.ex +++ b/lib/brain/dishwasher_manager.ex @@ -63,22 +63,18 @@ defmodule Brain.DishwasherManager do ######### def handle_call(:users, _from, {_, users, _} = state) do - Logger.debug "brain -> users" {:reply, {:ok, users}, state} end def handle_call(:manager?, _from, {_, _, manager} = state) do - Logger.debug "brain -> manager?" {:reply, {:ok, manager}, state} end def handle_call(:schedule, _from, {schedule, _,_} = state) do - Logger.debug "brain -> schedule" {:reply, {:ok, schedule}, state} end def handle_call({:create_schedule, startDate}, _from, {_, users, }) do - Logger.debug "brain -> create_schedule" usersList = Map.to_list users {_, manager} = List.first(usersList) schedule = build_schedule(usersList, startDate) @@ -86,7 +82,6 @@ defmodule Brain.DishwasherManager do end def handle_call({:add_user, user, fullname}, _from, {schedule, users, manager}) do - Logger.debug "brain -> add_user #{user}" fullname = buildFullName(fullname) users = Map.put_new(users, user, fullname) schedule = add_to_schedule(schedule, user, fullname) @@ -96,19 +91,21 @@ defmodule Brain.DishwasherManager do def handle_call({:remove_user, user}, _from, {schedule, users, manager}) do - Logger.debug "brain -> remove_user #{user}" - users = Map.delete(users, user) - save_state(users, @users_file) - {:reply, :ok, {schedule, users, manager}} + user = String.trim(user) + userList = Map.delete(users, user) + save_state(userList, @users_file) + {:reply, :ok, {schedule, userList, manager}} end - def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) do - Logger.debug "brain -> swap order for duties of user #{userA} with #{userB}" + def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) when schedule == %{} do + {:reply, {:error, "There is no schedule ready. Use the command 'help' for more information."}, {schedule, users, manager}} + end + def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) do case validate_user_names([userA, userB], users) do true -> - {_, dateA} = Map.get(users, userA) - {_, dateB} = Map.get(users, userB) + {_, dateA} = Map.get(schedule, userA) + {_, dateB} = Map.get(schedule, userB) schedule = schedule |> Map.replace!(userA, dateB) @@ -123,7 +120,6 @@ defmodule Brain.DishwasherManager do end - ########### # Private # ########### @@ -139,15 +135,15 @@ defmodule Brain.DishwasherManager do users = case usersData do {:ok, [values]} -> values - _ -> {:error} + _ -> %{} end schedule = case scheduleData do {:ok, [values]} -> values - _ -> {:error} + _ -> %{} end - {schedule, users} + {:ok, {schedule, users, :not_specified}} end defp buildFullName(fullName, acc \\ "") @@ -159,7 +155,7 @@ defmodule Brain.DishwasherManager do buildFullName rest, acc end - defp add_to_schedule(%{} = schedule, _user, _fullName) do + defp add_to_schedule(%{} = schedule, _user, _fullName) when schedule == %{} do schedule end @@ -170,6 +166,7 @@ defmodule Brain.DishwasherManager do Map.put(schedule, user, {fullName, Date.add(lastDate, 7)}) end + defp validate_user_names([], _users), do: true defp validate_user_names([user| rest], users) do case Map.has_key?(users, user) do false -> "Invalid username! The user #{user} is not a registered." @@ -178,7 +175,6 @@ defmodule Brain.DishwasherManager do end defp build_schedule(list, startDate, schedule \\ %{}) - defp build_schedule([], _startDate, schedule), do: schedule defp build_schedule([{k, v} | rest], startDate, schedule) do From 9284cbbca149c3c323f6cc8cda3b22725be776f1 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 23:34:48 +0200 Subject: [PATCH 11/30] Add support for private messages --- lib/slack/slack_manager.ex | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/slack/slack_manager.ex b/lib/slack/slack_manager.ex index 95b920f..105bfc8 100644 --- a/lib/slack/slack_manager.ex +++ b/lib/slack/slack_manager.ex @@ -57,6 +57,14 @@ defmodule SlackManager do {:noreply, state} end + @doc """ + Sends a message over Slack to the given user. + """ + def handle_cast({:send_private_msg, msg, user}, state) do + send(state.client, {:send_private_msg, msg, user}) + {:noreply, state} + end + ######### # Calls # ######### @@ -189,4 +197,8 @@ defmodule SlackManager do def send_message(m, channel) do GenServer.cast(SlackManager, {:send_msg, m, channel}) end + + def send_private_message(m, user) do + GenServer.cast(SlackManager, {:send_private_msg, m, user}) + end end From 757ff2f2257bf08796adfa0d6d75b975a02077b9 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Mon, 11 Sep 2017 23:35:26 +0200 Subject: [PATCH 12/30] Add support for private messages --- lib/slack/slacklogic.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/slack/slacklogic.ex b/lib/slack/slacklogic.ex index d93e4ea..a615db8 100644 --- a/lib/slack/slacklogic.ex +++ b/lib/slack/slacklogic.ex @@ -26,7 +26,7 @@ defmodule SlackLogic do which are in the form of some-sort of hashes. """ def handle_event(message = %{type: "message", text: text, user: from}, slack, state) do - Logger.debug ">> #{text}" + Logger.debug ">>> #{text}" {:ok, sender} = SlackManager.dealias_userhash(from) {:ok, m} = SlackManager.dealias_message(text) {:ok, {_, chan}} = SlackManager.dehash_channel(message.channel) @@ -70,6 +70,16 @@ defmodule SlackLogic do {:ok, state} end + @doc """ + Info's come from the outside. IT allows us to send messages to the Slack + process. + """ + def handle_info({:send_private_msg, text, user}, slack, state) do + Logger.debug "<< #{user}: #{text}" + send_message(text, "@#{user}", slack) + {:ok, state} + end + def handle_info(_,_, state) do {:ok, state} end From 6d0fb1ee35de8a1e1fcd7305c088897b93f6ff7d Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Wed, 13 Sep 2017 22:44:14 +0200 Subject: [PATCH 13/30] Full beta version --- lib/bot/diswasher_manager.ex | 101 ++++++++++++++++++++--- lib/brain/dishwasher_manager.ex | 141 ++++++++++++++++++++++++++++---- 2 files changed, 215 insertions(+), 27 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index 4057ac4..4656885 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -7,22 +7,34 @@ defmodule Bot.DiswasherManager do # The message "swap_with @x" is used to swap weekly duties with the user `x`. def on_message(<<"swap_with"::utf8, user::bitstring>>, _channel, sender) do - case Brain.DishwasherManager.swap_duties(sender, String.trim(user)) do - :ok -> {:ok, "Duties swapped!"} + user = String.trim(user) + case Brain.DishwasherManager.swap_duties(sender, user) do + :ok -> SlackManager.send_private_message("You swapped your dishwasher duties with @#{sender}.", user) + {:ok, "Duties swapped!"} {:error, msg} -> {:ok, msg} end end - # The message "who_is?" return the name uf the current dishwasher manager - def on_message(<<"manager?"::utf8, _rest::bitstring>>, _channel, _sender) do - {:ok, manager} = Brain.DishwasherManager.manager?() + # The message "manager?" return the name uf the current dishwasher manager + def on_message(<<"manager?"::utf8>>, _channel, _sender) do + {:ok, manager, fullname} = Brain.DishwasherManager.manager?() case manager do :no_specified -> {:ok, "The schedule has not been created. Use the command 'help' for more information."} - name -> {:ok, "The current dishwasher manager is `#{name}`"} + name -> {:ok, "The current dishwasher manager is `#{fullname}`"} end - + end + + def on_message(<<"when?"::utf8>>, _channel, sender) do + {:ok, fullname, startDate} = Brain.DishwasherManager.when?(sender) + case fullname do + :invalid_user -> {:ok, "The schedule has not been created. Use the command 'help' for more information."} + + _ -> from = Date.to_string(startDate) + to = startDate |> Date.add(4) |> Date.to_string() + {:ok, "Your next dishwasher duties will be from `#{from}` to `#{to}`"} + end end # Prints out all the outstanding orders. @@ -45,8 +57,7 @@ defmodule Bot.DiswasherManager do end def on_message(<<"add_user"::utf8, userDetails::bitstring>>, _channel, @boss) do - IO.puts "----> add_user" - case String.split(userDetails) do + case String.split(userDetails) do [] -> {:noreply} [user| fullname] -> :ok = Brain.DishwasherManager.add_user(user, fullname) {:ok, "The user {#{user}, #{fullname}} has been saved."} @@ -58,6 +69,51 @@ defmodule Bot.DiswasherManager do {:ok, "The user #{user} has been removed."} end + def on_message(<<"remove_users"::utf8>>, _channel, @boss) do + :ok = Brain.DishwasherManager.remove_users() + {:ok, "The user list was removed."} + end + + def on_message(<<"remove_schedule"::utf8>>, _channel, @boss) do + :ok = Brain.DishwasherManager.remove_schedule() + {:ok, "The schedule was removed."} + end + + def on_message(<<"set_manager"::utf8>>, _channel, @boss) do + {:ok, manager} = Brain.DishwasherManager.set_manager_of_the_week() + case manager do + :no_specified -> {:ok, "The schedule has not been created. Use the command 'help' for more information."} + name -> {:ok, "The current dishwasher manager is `#{name}`"} + end + end + + def on_message(<<"wave"::utf8>>, :dishwasher_app, _sender) do + wave_dishwasher_manager() + end + + def on_message(<<"wave"::utf8>>, :channel, _sender) do + wave_dishwasher_manager() + end + + def on_message(<<":wave:"::utf8>>, :dishwasher_app, _sender) do + wave_dishwasher_manager() + end + + + def on_message(<<":wave:"::utf8>>, :channel, _sender) do + wave_dishwasher_manager() + end + + defp wave_dishwasher_manager do + {:ok, manager, fullname} = Brain.DishwasherManager.manager?() + + case manager do + :no_specified -> {:ok, "As the schedule has not been created, there is not Dishwasher Manager."} + name -> SlackManager.send_private_message(":wave: Hey Dishwasher Manager! Please do your dishwasher duties as soon as you can.", manager) + {:ok, "The current dishwasher manager `#{fullname}` was :wave:"} + end + end + # Prints out help message. def on_message(<<"help"::utf8>>, @channel, @boss) do res = boss_help_menu() @@ -82,16 +138,31 @@ defmodule Bot.DiswasherManager do end +# def on_message(_text, @channel, _sender) do +# {:ok, general_msg()} +# end +# +# def on_message(_text, :dishwasher_app, _sender) do +# {:ok, general_msg()} +# end - def on_message(_text, _hannel, _sender) do + def on_message(_text, _channel, _sender) do {:noreply} end + +# defp general_msg do +# """ +# Hello Softie! Please use the command `help` for more information. +# """ +# end + defp build_schedule_list(schedule) when schedule == %{} , do: {:ok, "There is no schedule ready. Use the command 'help' for more information."} defp build_schedule_list(schedule) do resp = schedule - |> Enum.map(fn {_k,{fullname, date}} -> "- #{fullname} -> #{date}-#{Date.add(date, 4)}" end) + |> Enum.map(fn {_k,{fullname, from}} -> + "- #{fullname} -> from: #{from} to: #{Date.add(from, 4)}" end) |> Enum.join("\n") {:ok, "```#{resp}```"} @@ -116,8 +187,10 @@ defmodule Bot.DiswasherManager do Example: "manager?" schedule : Shows the current dishwasher schedule. Example: "schedule" - users : Shows the current list of users. - Example: "users" + wave : Sends a notification to the current diswasher manager. + Example: "wave" or ":wave:" + when? : Shows the dates of your the next diswasher duties. + Example: "when? " ``` """ @@ -141,6 +214,8 @@ defmodule Bot.DiswasherManager do Example: "add_user @humberto Humberto Rodriguez Avila" remove_user : Remove an user. Example: "remove_user @humberto" + set_manager : Set the manager for the current week. + Example: "set_manager" ``` """ diff --git a/lib/brain/dishwasher_manager.ex b/lib/brain/dishwasher_manager.ex index b5b466a..d4f8073 100644 --- a/lib/brain/dishwasher_manager.ex +++ b/lib/brain/dishwasher_manager.ex @@ -4,6 +4,7 @@ defmodule Brain.DishwasherManager do @users_file "data/dishwasher_manager/users.dat" @schedule_file "data/dishwasher_manager/schedule.dat" + @holidays [~D[2017-12-25], ~D[2018-01-01] ] def start_link(initial_state \\ []) do GenServer.start_link __MODULE__, [initial_state], name: __MODULE__ @@ -37,6 +38,14 @@ defmodule Brain.DishwasherManager do GenServer.call __MODULE__, :manager? end + defp next_manager do + GenServer.call __MODULE__, :next_manager + end + + def when?(user) do + GenServer.call __MODULE__, {:when?, user} + end + def schedule() do GenServer.call __MODULE__, :schedule end @@ -57,6 +66,18 @@ defmodule Brain.DishwasherManager do GenServer.call __MODULE__, {:remove_user, user} end + def set_manager_of_the_week() do + GenServer.call __MODULE__, :set_manager_of_the_week + end + + def remove_users() do + GenServer.call __MODULE__, :remove_users + end + + def remove_schedule() do + GenServer.call __MODULE__, :remove_schedule + end + ######### # Calls # @@ -66,18 +87,56 @@ defmodule Brain.DishwasherManager do {:reply, {:ok, users}, state} end - def handle_call(:manager?, _from, {_, _, manager} = state) do + def handle_call(:manager?, _from, {_, users, manager} = state) do + fullName = Map.get(users, manager, :no_specified) + {:reply, {:ok, manager, fullName}, state} + end + + def handle_call(:next_manager, _from, {schedule, users, _} = state) do + manager = + case get_next_manager(schedule) do + :no_specified -> {user, _} =List.first Map.to_list users + user + user -> user + end + {:reply, {:ok, manager}, state} end + def handle_call({:when?, user }, _from, {schedule, _, _} = state) do + {fullName, startDate} = Map.get(schedule, user, {:invalid_user, :no_specified}) + {:reply, {:ok, fullName, startDate}, state} + end + + + def handle_call(:set_manager_of_the_week, _from, {schedule, users, _} ) do + {schedule, manager} = + case get_manager_of_week(schedule) do + :no_specified -> usersList = Map.to_list users + sch = build_schedule(usersList, Date.utc_today) + man = get_manager_of_week(sch) + {sch, man} + manager -> {schedule, manager} + end + fullName = Map.get(users, manager, :no_specified) + {:reply, {:ok, fullName}, {schedule, users, manager}} + end + def handle_call(:schedule, _from, {schedule, _,_} = state) do {:reply, {:ok, schedule}, state} end - def handle_call({:create_schedule, startDate}, _from, {_, users, }) do + def handle_call({:create_schedule, startDate}, _from, {_, users, _}) do + IO.puts "brain.create_schedule" usersList = Map.to_list users - {_, manager} = List.first(usersList) + + {:ok, startDate} = startDate + |> String.trim() + |> Date.from_iso8601() + + schedule = build_schedule(usersList, startDate) + manager = get_manager_of_week(schedule) {:reply, {:ok, schedule}, {schedule, users, manager}} end @@ -97,28 +156,40 @@ defmodule Brain.DishwasherManager do {:reply, :ok, {schedule, userList, manager}} end - def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) when schedule == %{} do + def handle_call({:swap, _userA, _userB}, _from, {schedule, users, manager}) when schedule == %{} do {:reply, {:error, "There is no schedule ready. Use the command 'help' for more information."}, {schedule, users, manager}} end def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) do case validate_user_names([userA, userB], users) do true -> - {_, dateA} = Map.get(schedule, userA) - {_, dateB} = Map.get(schedule, userB) + {nameA, dateA} = Map.get(schedule, userA) + {nameB, dateB} = Map.get(schedule, userB) - schedule = schedule - |> Map.replace!(userA, dateB) - |> Map.replace!(userB, dateA) + newSchedule = schedule + |> Map.replace!(userA, {nameA, dateB}) + |> Map.replace!(userB, {nameB, dateA}) - save_state(schedule, @schedule_file) - {:reply, :ok, {schedule, users, manager}} + save_state(newSchedule, @schedule_file) + manager = get_manager_of_week(newSchedule) + {:reply, :ok, {newSchedule, users, manager}} msg -> {:reply, {:error, msg}, {schedule, users, manager}} end end + def handle_call(:remove_users, _from, _state) do + save_state(%{}, @users_file) + save_state(%{}, @schedule_file) + {:reply, :ok, {%{}, %{}, :no_specified}} + end + + def handle_call(:remove_schedule, _from, {_, users, _}) do + save_state(%{}, @schedule_file) + {:reply, :ok, {%{}, users, :no_specified}} + end + ########### # Private # @@ -143,7 +214,9 @@ defmodule Brain.DishwasherManager do _ -> %{} end - {:ok, {schedule, users, :not_specified}} + manager = get_manager_of_week(schedule) + + {:ok, {schedule, users, manager}} end defp buildFullName(fullName, acc \\ "") @@ -163,7 +236,7 @@ defmodule Brain.DishwasherManager do {_, {_, lastDate}} = schedule |> Enum.to_list |> List.last - Map.put(schedule, user, {fullName, Date.add(lastDate, 7)}) + Map.put(schedule, user, {fullName, get_next_valid_date(Date.add(lastDate, 7))}) end defp validate_user_names([], _users), do: true @@ -178,9 +251,49 @@ defmodule Brain.DishwasherManager do defp build_schedule([], _startDate, schedule), do: schedule defp build_schedule([{k, v} | rest], startDate, schedule) do + startDate = get_next_valid_date(startDate) schedule = Map.put(schedule, k, {v, startDate} ) - nextDate = Date.add(startDate, 7) + nextDate = get_next_valid_date(Date.add(startDate, 7)) build_schedule(rest,nextDate, schedule ) end + defp get_next_valid_date(date) do + holiday? = Enum.find(@holidays, fn(x) -> Date.compare(date, x) == :eq end) + case holiday? do + nil -> get_start_date(date) + _ -> get_next_valid_date(Date.add(date, 7)) + end + end + + defp get_manager_of_week(schedule) when schedule == %{}, do: :no_specified + defp get_manager_of_week(schedule) do + startDate = get_start_date() + result = Enum.find(schedule, fn({k, {_, date}}) -> Date.compare(startDate, date) == :eq end) + case result do + nil -> :no_specified + {user,_} -> user + end + + end + + + defp get_next_manager(schedule) when schedule == %{}, do: :no_specified + defp get_next_manager(schedule) do + startDate = Date.add(get_start_date, 7) + result = Enum.find(schedule, fn({k, {_, date}}) -> Date.compare(startDate, date) == :eq end) + case result do + nil -> :no_specified + {user,_} -> user + end + + end + + defp get_start_date( date \\ Date.utc_today) do + + case Date.day_of_week(date) do + 1 -> date + value -> Date.add(date, -(value-1)) + end + end + end From 8c72396159ceefb0f80be9876c2cabc5a260401c Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Wed, 13 Sep 2017 22:44:56 +0200 Subject: [PATCH 14/30] Add dishwasher scheduler --- lib/scheduler/dishwasher_scheduler.ex | 52 +++++++++++++++++++++++++++ lib/supervisor/scheduler.ex | 17 +++++++++ 2 files changed, 69 insertions(+) create mode 100644 lib/scheduler/dishwasher_scheduler.ex create mode 100644 lib/supervisor/scheduler.ex diff --git a/lib/scheduler/dishwasher_scheduler.ex b/lib/scheduler/dishwasher_scheduler.ex new file mode 100644 index 0000000..1d45a2e --- /dev/null +++ b/lib/scheduler/dishwasher_scheduler.ex @@ -0,0 +1,52 @@ +defmodule Scheduler.DishwasherScheduler do + @moduledoc false + + use Cronex.Scheduler + + require Logger + + every :monday, at: "09:00" do + msg = "Good morning! Enjoy your week as dishwasher manager and don't forget your duties." + send_notification(msg) + end + + every :wednesday, at: "09:00" do + msg = "Good morning! Don't forget your dishwasher duties." + send_notification(msg) + end + + every :wednesday, at: "17:00" do + msg = "Hey Dishwasher Manager! I hope you did your duties today :slightly_smiling_face:" + send_notification(msg) + end + + every :friday, at: "09:00" do + msg = "Good morning! Don't forget your dishwasher duties." + send_notification(msg) + end + + every :friday, at: "17:00" do + msg = """ + We hope you did all your dishwasher duties this week :stuck_out_tongue_winking_eye: + Have a nice weekend! + """ + send_notification(msg) + end + + every :thursday, at: "10:00" do + msg = """ + Hello! Next week you will our Dishwasher Managger :tada: + If you will be out next week please change your turn with another person using the `swap_with` command. + e.g. `swap_with @cdetroye` + """ + {:ok, manager} = Brain.DishwasherManager.get_next_manager() + SlackManager.send_private_message(msg, manager) + end + + defp send_notification(msg) do + {:ok, manager} = Brain.DishwasherManager.manager?() + SlackManager.send_private_message(msg, manager) + end + + +end diff --git a/lib/supervisor/scheduler.ex b/lib/supervisor/scheduler.ex new file mode 100644 index 0000000..7213480 --- /dev/null +++ b/lib/supervisor/scheduler.ex @@ -0,0 +1,17 @@ +defmodule Supervisor.Scheduler do + @moduledoc false + + use Supervisor + + def start_link(state \\ []) do + {:ok, _pid} = Supervisor.start_link(__MODULE__, state, [{:name, __MODULE__}]) + end + + def init(_state) do + children = [ + worker(Scheduler.DishwasherScheduler, []) + ] + supervise children, strategy: :one_for_one + end + +end From 1afd693a980d789f32dd39f25ba3ef15a7429c18 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Wed, 13 Sep 2017 22:45:30 +0200 Subject: [PATCH 15/30] Add scheduler supervisor --- lib/slackbot.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/slackbot.ex b/lib/slackbot.ex index 5a59159..8f262f9 100644 --- a/lib/slackbot.ex +++ b/lib/slackbot.ex @@ -10,6 +10,7 @@ defmodule Slackbot do supervisor(Supervisor.Connection, []), # - The data of the bot (karma etc) supervisor(Supervisor.Brain, []), + supervisor(Supervisor.Scheduler, []), ] # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html From ef21e279d594fe215b078b9518481de8d9477e97 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Wed, 13 Sep 2017 22:46:14 +0200 Subject: [PATCH 16/30] Add timezone parameter for cronex --- config/config.exs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/config.exs b/config/config.exs index 370867c..fb22fe2 100644 --- a/config/config.exs +++ b/config/config.exs @@ -6,4 +6,7 @@ config :logger, handle_otp_reports: true, handle_sasl_reports: true +config :cronex, + timezone: "Europe/Copenhagen" + import_config "#{Mix.env}.secret.exs" From c391c563d37f10560160fdf97c86bf3d7f3dcf5a Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Wed, 13 Sep 2017 22:47:03 +0200 Subject: [PATCH 17/30] Update dependencies --- mix.exs | 4 ++-- mix.lock | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mix.exs b/mix.exs index 73be5b6..58d79cc 100644 --- a/mix.exs +++ b/mix.exs @@ -27,12 +27,12 @@ defmodule Slackbot.Mixfile do # Type `mix help deps` for more examples and options defp deps do [ -# {:exgenius, "~> 0.0.5"}, {:slack, "~> 0.12.0"}, {:poison, "~> 3.1.0"}, {:timex, "~> 3.1.24"}, {:feeder_ex, "~> 1.1"}, - {:html_entities, "~> 0.4.0"} + {:html_entities, "~> 0.4.0"}, + {:cronex, git: "https://github.com/rhumbertgz/cronex.git"} ] end end diff --git a/mix.lock b/mix.lock index e98d8aa..2358093 100644 --- a/mix.lock +++ b/mix.lock @@ -1,15 +1,13 @@ -%{"certifi": {:hex, :certifi, "1.2.1", "c3904f192bd5284e5b13f20db3ceac9626e14eeacfbb492e19583cf0e37b22be", [:rebar3], []}, +%{"certifi": {:hex, :certifi, "2.0.0", "a0c0e475107135f76b8c1d5bc7efb33cd3815cb3cf3dea7aefdd174dabead064", [:rebar3], []}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], []}, - "exgenius": {:hex, :exgenius, "0.0.5", "bf486cffa31c4add0b600193939438b9a4936540435880ba08066e0dafcf2226", [:mix], [{:exjsx, "~> 3.1", [hex: :exjsx, optional: false]}, {:httpoison, "~> 0.5", [hex: :httpoison, optional: false]}]}, - "exjsx": {:hex, :exjsx, "3.2.1", "1bc5bf1e4fd249104178f0885030bcd75a4526f4d2a1e976f4b428d347614f0f", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, optional: false]}]}, - "feeder": {:hex, :feeder, "2.2.1", "9b1236d32cf971a049968b4c3955fa4808bd132b347af6e30a06fc2093751796", [:make], []}, + "cronex": {:git, "https://github.com/rhumbertgz/cronex.git", "5500b9f57975751ed0c997c0677f9fabb8fb0ab4", []}, + "feeder": {:hex, :feeder, "2.2.4", "56ec535cf2f79719bc53b5c2abe5f6cf481fc01e5ae6229ab7cc829644f039ec", [:make], []}, "feeder_ex": {:hex, :feeder_ex, "1.1.0", "0be3732255cdb45dec949e0ede6852b5261c9ff173360e8274a6ac65183b2b55", [:mix], [{:feeder, "~> 2.2", [hex: :feeder, optional: false]}]}, "gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [:mix], []}, - "hackney": {:hex, :hackney, "1.8.6", "21a725db3569b3fb11a6af17d5c5f654052ce9624219f1317e8639183de4a423", [:rebar3], [{:certifi, "1.2.1", [hex: :certifi, optional: false]}, {:idna, "5.0.2", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]}, + "hackney": {:hex, :hackney, "1.9.0", "51c506afc0a365868469dcfc79a9d0b94d896ec741cfd5bd338f49a5ec515bfe", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, optional: false]}, {:idna, "5.1.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], []}, - "httpoison": {:hex, :httpoison, "0.12.0", "8fc3d791c5afe6beb0093680c667dd4ce712a49d89c38c3fe1a43100dd76cf90", [:mix], [{:hackney, "~> 1.8.0", [hex: :hackney, optional: false]}]}, - "idna": {:hex, :idna, "5.0.2", "ac203208ada855d95dc591a764b6e87259cb0e2a364218f215ad662daa8cd6b4", [:rebar3], [{:unicode_util_compat, "0.2.0", [hex: :unicode_util_compat, optional: false]}]}, - "jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], []}, + "httpoison": {:hex, :httpoison, "0.13.0", "bfaf44d9f133a6599886720f3937a7699466d23bb0cd7a88b6ba011f53c6f562", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, optional: false]}]}, + "idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, optional: false]}]}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []}, "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []}, @@ -17,5 +15,5 @@ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []}, "timex": {:hex, :timex, "3.1.24", "d198ae9783ac807721cca0c5535384ebdf99da4976be8cefb9665a9262a1e9e3", [:mix], [{:combine, "~> 0.7", [hex: :combine, optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, optional: false]}]}, "tzdata": {:hex, :tzdata, "0.5.12", "1c17b68692c6ba5b6ab15db3d64cc8baa0f182043d5ae9d4b6d35d70af76f67b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.2.0", "dbbccf6781821b1c0701845eaf966c9b6d83d7c3bfc65ca2b78b88b8678bfa35", [:rebar3], []}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], []}, "websocket_client": {:hex, :websocket_client, "1.2.4", "14ec1ca4b6d247b44ccd9a80af8f6ca98328070f6c1d52a5cb00bc9d939d63b8", [:rebar3], []}} From 7d3fdfda65e366c593479fd39f6fbe8f5d820c32 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 11:33:04 +0200 Subject: [PATCH 18/30] Update internal data structure for users and schedule --- lib/bot/diswasher_manager.ex | 4 +- lib/brain/dishwasher_manager.ex | 97 ++++++++++++++------------- lib/scheduler/dishwasher_scheduler.ex | 8 ++- 3 files changed, 61 insertions(+), 48 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index 4656885..52f09b0 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -160,6 +160,8 @@ defmodule Bot.DiswasherManager do defp build_schedule_list(schedule) when schedule == %{} , do: {:ok, "There is no schedule ready. Use the command 'help' for more information."} defp build_schedule_list(schedule) do + IO.puts "sdfsdf-->" + IO.inspect schedule resp = schedule |> Enum.map(fn {_k,{fullname, from}} -> "- #{fullname} -> from: #{from} to: #{Date.add(from, 4)}" end) @@ -187,7 +189,7 @@ defmodule Bot.DiswasherManager do Example: "manager?" schedule : Shows the current dishwasher schedule. Example: "schedule" - wave : Sends a notification to the current diswasher manager. + wave : Sends a notification to the current diswasher manager in case he has to do his duties. Example: "wave" or ":wave:" when? : Shows the dates of your the next diswasher duties. Example: "when? " diff --git a/lib/brain/dishwasher_manager.ex b/lib/brain/dishwasher_manager.ex index d4f8073..711b33c 100644 --- a/lib/brain/dishwasher_manager.ex +++ b/lib/brain/dishwasher_manager.ex @@ -88,23 +88,23 @@ defmodule Brain.DishwasherManager do end def handle_call(:manager?, _from, {_, users, manager} = state) do - fullName = Map.get(users, manager, :no_specified) - {:reply, {:ok, manager, fullName}, state} + fullName = Keyword.get(users, manager, :no_specified) + {:reply, {:ok, Atom.to_string(manager), fullName}, state} end def handle_call(:next_manager, _from, {schedule, users, _} = state) do manager = case get_next_manager(schedule) do - :no_specified -> {user, _} =List.first Map.to_list users + :no_specified -> {user, _} = List.first users user user -> user end - {:reply, {:ok, manager}, state} + {:reply, {:ok, Atom.to_string(manager)}, state} end - def handle_call({:when?, user }, _from, {schedule, _, _} = state) do - {fullName, startDate} = Map.get(schedule, user, {:invalid_user, :no_specified}) + def handle_call({:when?, user}, _from, {schedule, _, _} = state) do + {fullName, startDate} = Keyword.get(schedule, String.to_atom(user), {:invalid_user, :no_specified}) {:reply, {:ok, fullName, startDate}, state} end @@ -112,13 +112,12 @@ defmodule Brain.DishwasherManager do def handle_call(:set_manager_of_the_week, _from, {schedule, users, _} ) do {schedule, manager} = case get_manager_of_week(schedule) do - :no_specified -> usersList = Map.to_list users - sch = build_schedule(usersList, Date.utc_today) + :no_specified -> sch = build_schedule(users, Date.utc_today) man = get_manager_of_week(sch) {sch, man} manager -> {schedule, manager} end - fullName = Map.get(users, manager, :no_specified) + fullName = Keyword.get(users, manager, :no_specified) {:reply, {:ok, fullName}, {schedule, users, manager}} end @@ -127,48 +126,63 @@ defmodule Brain.DishwasherManager do end def handle_call({:create_schedule, startDate}, _from, {_, users, _}) do - IO.puts "brain.create_schedule" - usersList = Map.to_list users {:ok, startDate} = startDate |> String.trim() |> Date.from_iso8601() - - schedule = build_schedule(usersList, startDate) + schedule = build_schedule(users, startDate) + save_state(schedule, @schedule_file) manager = get_manager_of_week(schedule) {:reply, {:ok, schedule}, {schedule, users, manager}} end def handle_call({:add_user, user, fullname}, _from, {schedule, users, manager}) do fullname = buildFullName(fullname) - users = Map.put_new(users, user, fullname) + user = user + |> String.trim() + |> String.to_atom() + + users = Keyword.put_new(users, user, fullname) schedule = add_to_schedule(schedule, user, fullname) + save_state(schedule, @schedule_file) save_state(users, @users_file) {:reply, :ok, {schedule, users, manager}} end def handle_call({:remove_user, user}, _from, {schedule, users, manager}) do - user = String.trim(user) - userList = Map.delete(users, user) + user = user + |> String.trim() + |> String.to_atom() + + userList = Keyword.delete(users, user) save_state(userList, @users_file) + {:reply, :ok, {schedule, userList, manager}} end - def handle_call({:swap, _userA, _userB}, _from, {schedule, users, manager}) when schedule == %{} do + def handle_call({:swap, _userA, _userB}, _from, {[], users, manager}) do {:reply, {:error, "There is no schedule ready. Use the command 'help' for more information."}, {schedule, users, manager}} end def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) do + userA = userA + |> String.trim() + |> String.to_atom() + + userB = userB + |> String.trim() + |> String.to_atom() + case validate_user_names([userA, userB], users) do true -> - {nameA, dateA} = Map.get(schedule, userA) - {nameB, dateB} = Map.get(schedule, userB) + {nameA, dateA} = Keyword.get(schedule, userA) + {nameB, dateB} = Keyword.get(schedule, userB) newSchedule = schedule - |> Map.replace!(userA, {nameA, dateB}) - |> Map.replace!(userB, {nameB, dateA}) + |> Keyword.replace!(userA, {nameA, dateB}) + |> Keyword.replace!(userB, {nameB, dateA}) save_state(newSchedule, @schedule_file) manager = get_manager_of_week(newSchedule) @@ -180,14 +194,14 @@ defmodule Brain.DishwasherManager do end def handle_call(:remove_users, _from, _state) do - save_state(%{}, @users_file) - save_state(%{}, @schedule_file) - {:reply, :ok, {%{}, %{}, :no_specified}} + save_state([], @users_file) + save_state([], @schedule_file) + {:reply, :ok, {[], [], :no_specified}} end def handle_call(:remove_schedule, _from, {_, users, _}) do - save_state(%{}, @schedule_file) - {:reply, :ok, {%{}, users, :no_specified}} + save_state([], @schedule_file) + {:reply, :ok, {[], users, :no_specified}} end @@ -206,12 +220,12 @@ defmodule Brain.DishwasherManager do users = case usersData do {:ok, [values]} -> values - _ -> %{} - end + _ -> [] + end schedule = case scheduleData do {:ok, [values]} -> values - _ -> %{} + _ -> [] end manager = get_manager_of_week(schedule) @@ -228,31 +242,27 @@ defmodule Brain.DishwasherManager do buildFullName rest, acc end - defp add_to_schedule(%{} = schedule, _user, _fullName) when schedule == %{} do - schedule - end + defp add_to_schedule([] = schedule, _user, _fullName), do: schedule defp add_to_schedule(schedule, user, fullName) do - {_, {_, lastDate}} = schedule - |> Enum.to_list - |> List.last - Map.put(schedule, user, {fullName, get_next_valid_date(Date.add(lastDate, 7))}) + {_, {_, lastDate}} = Enum.max_by(schedule, fn({u, {f, date}}) -> date end) + Keyword.put(schedule, user, {fullName, get_next_valid_date(Date.add(lastDate, 7))}) end defp validate_user_names([], _users), do: true defp validate_user_names([user| rest], users) do - case Map.has_key?(users, user) do + case Keyword.has_key?(users, user) do false -> "Invalid username! The user #{user} is not a registered." _ -> validate_user_names(rest, users) end end - defp build_schedule(list, startDate, schedule \\ %{}) - defp build_schedule([], _startDate, schedule), do: schedule + defp build_schedule(list, startDate, schedule \\ []) + defp build_schedule([], _startDate, schedule), do: Enum.reverse(schedule) defp build_schedule([{k, v} | rest], startDate, schedule) do startDate = get_next_valid_date(startDate) - schedule = Map.put(schedule, k, {v, startDate} ) + schedule = Keyword.put_new(schedule, k, {v, startDate}) nextDate = get_next_valid_date(Date.add(startDate, 7)) build_schedule(rest,nextDate, schedule ) end @@ -265,7 +275,7 @@ defmodule Brain.DishwasherManager do end end - defp get_manager_of_week(schedule) when schedule == %{}, do: :no_specified + defp get_manager_of_week([]), do: :no_specified defp get_manager_of_week(schedule) do startDate = get_start_date() result = Enum.find(schedule, fn({k, {_, date}}) -> Date.compare(startDate, date) == :eq end) @@ -276,8 +286,7 @@ defmodule Brain.DishwasherManager do end - - defp get_next_manager(schedule) when schedule == %{}, do: :no_specified + defp get_next_manager([]), do: :no_specified defp get_next_manager(schedule) do startDate = Date.add(get_start_date, 7) result = Enum.find(schedule, fn({k, {_, date}}) -> Date.compare(startDate, date) == :eq end) @@ -285,11 +294,9 @@ defmodule Brain.DishwasherManager do nil -> :no_specified {user,_} -> user end - end defp get_start_date( date \\ Date.utc_today) do - case Date.day_of_week(date) do 1 -> date value -> Date.add(date, -(value-1)) diff --git a/lib/scheduler/dishwasher_scheduler.ex b/lib/scheduler/dishwasher_scheduler.ex index 1d45a2e..0df8aa1 100644 --- a/lib/scheduler/dishwasher_scheduler.ex +++ b/lib/scheduler/dishwasher_scheduler.ex @@ -5,7 +5,11 @@ defmodule Scheduler.DishwasherScheduler do require Logger - every :monday, at: "09:00" do + every :monday, at: "07:00" do + Brain.DishwasherManager.set_manager_of_the_week() + end + + every :monday, at: "08:00" do msg = "Good morning! Enjoy your week as dishwasher manager and don't forget your duties." send_notification(msg) end @@ -33,7 +37,7 @@ defmodule Scheduler.DishwasherScheduler do send_notification(msg) end - every :thursday, at: "10:00" do + every :thursday, at: "14:00" do msg = """ Hello! Next week you will our Dishwasher Managger :tada: If you will be out next week please change your turn with another person using the `swap_with` command. From 23077cfb77fde5facc114ec90ee87a7b746f3a42 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 11:34:16 +0200 Subject: [PATCH 19/30] Add initial values to users and schedule file --- data/dishwasher_manager/schedule.dat | 85 ++++++++++++++++++++++++++++ data/dishwasher_manager/users.dat | 28 +++++++++ 2 files changed, 113 insertions(+) create mode 100644 data/dishwasher_manager/schedule.dat create mode 100644 data/dishwasher_manager/users.dat diff --git a/data/dishwasher_manager/schedule.dat b/data/dishwasher_manager/schedule.dat new file mode 100644 index 0000000..e7c64ed --- /dev/null +++ b/data/dishwasher_manager/schedule.dat @@ -0,0 +1,85 @@ +[{cderoove,{<<"Coen De Roover">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 11,month => 9,year => 2017}}}, + {mathsaey,{<<"Mathijs Saey">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 18,month => 9,year => 2017}}}, + {thierry,{<<"Thierry Renaux">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 25,month => 9,year => 2017}}}, + {kevin,{<<"Kevin Pinte">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 2,month => 10,year => 2017}}}, + {fmyter,{<<"Florian Myter">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 9,month => 10,year => 2017}}}, + {tmoldere,{<<"Tim Molderez">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 16,month => 10,year => 2017}}}, + {joeri,{<<"Joeri De Koster">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 23,month => 10,year => 2017}}}, + {simon,{<<"Simon Van de Water">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 30,month => 10,year => 2017}}}, + {nathalie,{<<"Nathalie Oostvogels">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 6,month => 11,year => 2017}}}, + {jswalens,{<<"Janwillem Swalens">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 13,month => 11,year => 2017}}}, + {eljenso,{<<"Jens Nicolay">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 20,month => 11,year => 2017}}}, + {kennedy,{<<"Kennedy Kambona">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 27,month => 11,year => 2017}}}, + {qstieven,{<<"Quentin Stievenart">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 4,month => 12,year => 2017}}}, + {dirk,{<<"Dirk van Deun">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 11,month => 12,year => 2017}}}, + {jbsartor,{<<"Jennifer Sartor">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 18,month => 12,year => 2017}}}, + {jdeblese,{<<"Jonas De Bleser">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 8,month => 1,year => 2018}}}, + {nvgeele,{<<"Nils Van Geele">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 15,month => 1,year => 2018}}}, + {ascullpu,{<<"Angel Luis Scull Pupo">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 22,month => 1,year => 2018}}}, + {carmen,{<<"Carmen Torres Lopez">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 29,month => 1,year => 2018}}}, + {jezaman,{<<"Jesse Zaman">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 5,month => 2,year => 2018}}}, + {mvdcamme,{<<"Maarten Vandercammen">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 12,month => 2,year => 2018}}}, + {lachrist,{<<"Laurent Christophe">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 19,month => 2,year => 2018}}}, + {marmat,{<<"Matteo Marra">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 26,month => 2,year => 2018}}}, + {noah,{<<"Noah Van Es">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 5,month => 3,year => 2018}}}, + {svdvonde,{<<"Sam Van den Vonder">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 12,month => 3,year => 2018}}}, + {humberto,{<<"Humberto Rodriguez">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 19,month => 3,year => 2018}}}, + {cdetroye,{<<"Christophe De Troyer">>, + #{'__struct__' => 'Elixir.Date',calendar => 'Elixir.Calendar.ISO', + day => 26,month => 3,year => 2018}}}, + {elisagboix,{<<"Elisa Gonzalez">>, + #{'__struct__' => 'Elixir.Date', + calendar => 'Elixir.Calendar.ISO',day => 2,month => 4, + year => 2018}}}]. diff --git a/data/dishwasher_manager/users.dat b/data/dishwasher_manager/users.dat new file mode 100644 index 0000000..f1f8e01 --- /dev/null +++ b/data/dishwasher_manager/users.dat @@ -0,0 +1,28 @@ +[{cderoove,<<"Coen De Roover">>}, + {mathsaey,<<"Mathijs Saey">>}, + {thierry,<<"Thierry Renaux">>}, + {kevin,<<"Kevin Pinte">>}, + {fmyter,<<"Florian Myter">>}, + {tmoldere,<<"Tim Molderez">>}, + {joeri,<<"Joeri De Koster">>}, + {simon,<<"Simon Van de Water">>}, + {nathalie,<<"Nathalie Oostvogels">>}, + {jswalens,<<"Janwillem Swalens">>}, + {eljenso,<<"Jens Nicolay">>}, + {kennedy,<<"Kennedy Kambona">>}, + {qstieven,<<"Quentin Stievenart">>}, + {dirk,<<"Dirk van Deun">>}, + {jbsartor,<<"Jennifer Sartor">>}, + {jdeblese,<<"Jonas De Bleser">>}, + {nvgeele,<<"Nils Van Geele">>}, + {ascullpu,<<"Angel Luis Scull Pupo">>}, + {carmen,<<"Carmen Torres Lopez">>}, + {jezaman,<<"Jesse Zaman">>}, + {mvdcamme,<<"Maarten Vandercammen">>}, + {lachrist,<<"Laurent Christophe">>}, + {marmat,<<"Matteo Marra">>}, + {noah,<<"Noah Van Es">>}, + {svdvonde,<<"Sam Van den Vonder">>}, + {humberto,<<"Humberto Rodriguez">>}, + {cdetroye,<<"Christophe De Troyer">>}, + {elisagboix,<<"Elisa Gonzalez">>}]. From 214b7710171d65043c8dd3c5ab6d156407217dab Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 11:35:43 +0200 Subject: [PATCH 20/30] Remove print trace --- lib/bot/diswasher_manager.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index 52f09b0..b0394dc 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -160,8 +160,6 @@ defmodule Bot.DiswasherManager do defp build_schedule_list(schedule) when schedule == %{} , do: {:ok, "There is no schedule ready. Use the command 'help' for more information."} defp build_schedule_list(schedule) do - IO.puts "sdfsdf-->" - IO.inspect schedule resp = schedule |> Enum.map(fn {_k,{fullname, from}} -> "- #{fullname} -> from: #{from} to: #{Date.add(from, 4)}" end) From c29bf137e6fd0a75142abd174328602f1532c507 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 12:28:46 +0200 Subject: [PATCH 21/30] Format code --- lib/slack/slack_manager.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/slack/slack_manager.ex b/lib/slack/slack_manager.ex index 105bfc8..d985051 100644 --- a/lib/slack/slack_manager.ex +++ b/lib/slack/slack_manager.ex @@ -75,7 +75,7 @@ defmodule SlackManager do """ def handle_call({:dealias, m}, _from, state) do dealiased = ~r/\<@([a-zA-Z0-9]+)\>/ - |> Regex.replace(m, + |> Regex.replace(m, fn _, x -> {:ok, username} = dealias_userhash("#{x}", state) username From 6a3d52f7b96a8553fa13bcee96a7ddf0e20967b8 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 12:32:05 +0200 Subject: [PATCH 22/30] Add dishwasher settings --- config/prod.secret.exs.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/prod.secret.exs.example b/config/prod.secret.exs.example index 9a56869..c06f657 100644 --- a/config/prod.secret.exs.example +++ b/config/prod.secret.exs.example @@ -8,5 +8,7 @@ config :slack, owner: "cdetroye", benvolios_owner: "cdetroye", benvolios_channel: "benvolios", + diswasher_duties_owner: "humberto", + diswasher_duties_channel: "dishwasher_duties", rss_channel: "bots" From 816c2f69881bcf5d87155b907abb05884525f289 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 12:35:15 +0200 Subject: [PATCH 23/30] Add github settings --- config/prod.secret.exs.example | 1 + 1 file changed, 1 insertion(+) diff --git a/config/prod.secret.exs.example b/config/prod.secret.exs.example index c06f657..a071519 100644 --- a/config/prod.secret.exs.example +++ b/config/prod.secret.exs.example @@ -6,6 +6,7 @@ use Mix.Config config :slack, token: "xoxb", owner: "cdetroye", + github: "https://github.com/m1dnight/slackbot", benvolios_owner: "cdetroye", benvolios_channel: "benvolios", diswasher_duties_owner: "humberto", From 838f6c9784da1e1b586ac72a77ce682a693df21a Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 12:38:07 +0200 Subject: [PATCH 24/30] Update scheduler messages --- lib/scheduler/dishwasher_scheduler.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/dishwasher_scheduler.ex b/lib/scheduler/dishwasher_scheduler.ex index 0df8aa1..edf844b 100644 --- a/lib/scheduler/dishwasher_scheduler.ex +++ b/lib/scheduler/dishwasher_scheduler.ex @@ -31,7 +31,7 @@ defmodule Scheduler.DishwasherScheduler do every :friday, at: "17:00" do msg = """ - We hope you did all your dishwasher duties this week :stuck_out_tongue_winking_eye: + Hi Dishwasher Manager! We hope you did all your dishwasher duties this week :stuck_out_tongue_winking_eye: Have a nice weekend! """ send_notification(msg) @@ -39,7 +39,7 @@ defmodule Scheduler.DishwasherScheduler do every :thursday, at: "14:00" do msg = """ - Hello! Next week you will our Dishwasher Managger :tada: + Hello! Next week you will be our Dishwasher Managger :tada: If you will be out next week please change your turn with another person using the `swap_with` command. e.g. `swap_with @cdetroye` """ From 3ceaa05d8de798f464df4d436699c66910a25bd9 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 12:44:45 +0200 Subject: [PATCH 25/30] Fix next manager functionality bug --- lib/brain/dishwasher_manager.ex | 4 ++-- lib/scheduler/dishwasher_scheduler.ex | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/brain/dishwasher_manager.ex b/lib/brain/dishwasher_manager.ex index 711b33c..8791e3f 100644 --- a/lib/brain/dishwasher_manager.ex +++ b/lib/brain/dishwasher_manager.ex @@ -38,7 +38,7 @@ defmodule Brain.DishwasherManager do GenServer.call __MODULE__, :manager? end - defp next_manager do + def next_manager do GenServer.call __MODULE__, :next_manager end @@ -288,7 +288,7 @@ defmodule Brain.DishwasherManager do defp get_next_manager([]), do: :no_specified defp get_next_manager(schedule) do - startDate = Date.add(get_start_date, 7) + startDate = Date.add(get_start_date(), 7) result = Enum.find(schedule, fn({k, {_, date}}) -> Date.compare(startDate, date) == :eq end) case result do nil -> :no_specified diff --git a/lib/scheduler/dishwasher_scheduler.ex b/lib/scheduler/dishwasher_scheduler.ex index edf844b..fde0199 100644 --- a/lib/scheduler/dishwasher_scheduler.ex +++ b/lib/scheduler/dishwasher_scheduler.ex @@ -43,7 +43,7 @@ defmodule Scheduler.DishwasherScheduler do If you will be out next week please change your turn with another person using the `swap_with` command. e.g. `swap_with @cdetroye` """ - {:ok, manager} = Brain.DishwasherManager.get_next_manager() + {:ok, manager} = Brain.DishwasherManager.next_manager() SlackManager.send_private_message(msg, manager) end From 1c44e3d0551b737f48017f35291995e01ee0b718 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 13:10:25 +0200 Subject: [PATCH 26/30] Fix warnings --- lib/bot/diswasher_manager.ex | 24 +++++++++++++----------- lib/brain/dishwasher_manager.ex | 10 +++++----- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index b0394dc..d083492 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -21,7 +21,7 @@ defmodule Bot.DiswasherManager do case manager do :no_specified -> {:ok, "The schedule has not been created. Use the command 'help' for more information."} - name -> {:ok, "The current dishwasher manager is `#{fullname}`"} + _name -> {:ok, "The current dishwasher manager is `#{fullname}`"} end end @@ -104,16 +104,6 @@ defmodule Bot.DiswasherManager do wave_dishwasher_manager() end - defp wave_dishwasher_manager do - {:ok, manager, fullname} = Brain.DishwasherManager.manager?() - - case manager do - :no_specified -> {:ok, "As the schedule has not been created, there is not Dishwasher Manager."} - name -> SlackManager.send_private_message(":wave: Hey Dishwasher Manager! Please do your dishwasher duties as soon as you can.", manager) - {:ok, "The current dishwasher manager `#{fullname}` was :wave:"} - end - end - # Prints out help message. def on_message(<<"help"::utf8>>, @channel, @boss) do res = boss_help_menu() @@ -222,4 +212,16 @@ defmodule Bot.DiswasherManager do end + defp wave_dishwasher_manager do + {:ok, manager, fullname} = Brain.DishwasherManager.manager?() + + case manager do + :no_specified -> {:ok, "As the schedule has not been created, there is not Dishwasher Manager."} + _name -> SlackManager.send_private_message(":wave: Hey Dishwasher Manager! Please do your dishwasher duties as soon as you can.", manager) + {:ok, "The current dishwasher manager `#{fullname}` was :wave:"} + end + end + + + end diff --git a/lib/brain/dishwasher_manager.ex b/lib/brain/dishwasher_manager.ex index 8791e3f..2c9867a 100644 --- a/lib/brain/dishwasher_manager.ex +++ b/lib/brain/dishwasher_manager.ex @@ -115,7 +115,7 @@ defmodule Brain.DishwasherManager do :no_specified -> sch = build_schedule(users, Date.utc_today) man = get_manager_of_week(sch) {sch, man} - manager -> {schedule, manager} + user -> {schedule, user} end fullName = Keyword.get(users, manager, :no_specified) {:reply, {:ok, fullName}, {schedule, users, manager}} @@ -163,7 +163,7 @@ defmodule Brain.DishwasherManager do end def handle_call({:swap, _userA, _userB}, _from, {[], users, manager}) do - {:reply, {:error, "There is no schedule ready. Use the command 'help' for more information."}, {schedule, users, manager}} + {:reply, {:error, "There is no schedule ready. Use the command 'help' for more information."}, {[], users, manager}} end def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) do @@ -245,7 +245,7 @@ defmodule Brain.DishwasherManager do defp add_to_schedule([] = schedule, _user, _fullName), do: schedule defp add_to_schedule(schedule, user, fullName) do - {_, {_, lastDate}} = Enum.max_by(schedule, fn({u, {f, date}}) -> date end) + {_, {_, lastDate}} = Enum.max_by(schedule, fn({_, {_, date}}) -> date end) Keyword.put(schedule, user, {fullName, get_next_valid_date(Date.add(lastDate, 7))}) end @@ -278,7 +278,7 @@ defmodule Brain.DishwasherManager do defp get_manager_of_week([]), do: :no_specified defp get_manager_of_week(schedule) do startDate = get_start_date() - result = Enum.find(schedule, fn({k, {_, date}}) -> Date.compare(startDate, date) == :eq end) + result = Enum.find(schedule, fn({_, {_, date}}) -> Date.compare(startDate, date) == :eq end) case result do nil -> :no_specified {user,_} -> user @@ -289,7 +289,7 @@ defmodule Brain.DishwasherManager do defp get_next_manager([]), do: :no_specified defp get_next_manager(schedule) do startDate = Date.add(get_start_date(), 7) - result = Enum.find(schedule, fn({k, {_, date}}) -> Date.compare(startDate, date) == :eq end) + result = Enum.find(schedule, fn({_, {_, date}}) -> Date.compare(startDate, date) == :eq end) case result do nil -> :no_specified {user,_} -> user From 69c2e109d28cbf881cd4cc8e682ecb54acc4455e Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 15:08:03 +0200 Subject: [PATCH 27/30] Fix typo on the reminder message for the next dishwasher manager --- lib/scheduler/dishwasher_scheduler.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/dishwasher_scheduler.ex b/lib/scheduler/dishwasher_scheduler.ex index fde0199..4100476 100644 --- a/lib/scheduler/dishwasher_scheduler.ex +++ b/lib/scheduler/dishwasher_scheduler.ex @@ -39,7 +39,7 @@ defmodule Scheduler.DishwasherScheduler do every :thursday, at: "14:00" do msg = """ - Hello! Next week you will be our Dishwasher Managger :tada: + Hello! Next week you will be our Dishwasher Manager :tada: If you will be out next week please change your turn with another person using the `swap_with` command. e.g. `swap_with @cdetroye` """ From 85ce1daaf545de0b8d23de75047022b40dfc6ee6 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Thu, 14 Sep 2017 16:03:02 +0200 Subject: [PATCH 28/30] Fix bugs on message patterns and generalize them --- lib/bot/diswasher_manager.ex | 61 +++++++++--------------------------- 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index d083492..bb8d3ee 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -4,6 +4,8 @@ defmodule Bot.DiswasherManager do @boss Application.fetch_env!(:slack, :diswasher_duties_owner) @channel Application.fetch_env!(:slack, :diswasher_duties_channel) + @private_channel :dishwasher_app + @channels [@channel, @private_channel ] # The message "swap_with @x" is used to swap weekly duties with the user `x`. def on_message(<<"swap_with"::utf8, user::bitstring>>, _channel, sender) do @@ -39,24 +41,24 @@ defmodule Bot.DiswasherManager do # Prints out all the outstanding orders. # Restricted to admins only. - def on_message(<<"schedule"::utf8, _::bitstring>>, _channel, _sender) do + def on_message(<<"schedule"::utf8, _::bitstring>>, channel, _sender) when channel in @channels do {:ok, schedule} = Brain.DishwasherManager.schedule() build_schedule_list(schedule) end # Prints out all the outstanding orders. # Restricted to admins only. - def on_message(<<"create_schedule"::utf8, startDate::bitstring>>, _channel, @boss) do + def on_message(<<"create_schedule"::utf8, startDate::bitstring>>, channel, @boss) when channel in @channels do {:ok, schedule} = Brain.DishwasherManager.create_schedule(startDate) build_schedule_list(schedule) end - def on_message(<<"users"::utf8, _::bitstring>>, _channel, @boss) do + def on_message(<<"users"::utf8, _::bitstring>>, channel, @boss) when channel in @channels do {:ok, users} = Brain.DishwasherManager.users() build_user_list(users) end - def on_message(<<"add_user"::utf8, userDetails::bitstring>>, _channel, @boss) do + def on_message(<<"add_user"::utf8, userDetails::bitstring>>, channel, @boss) when channel in @channels do case String.split(userDetails) do [] -> {:noreply} [user| fullname] -> :ok = Brain.DishwasherManager.add_user(user, fullname) @@ -64,22 +66,22 @@ defmodule Bot.DiswasherManager do end end - def on_message(<<"remove_user"::utf8, user::bitstring>>, _channel, @boss) do + def on_message(<<"remove_user"::utf8, user::bitstring>>, channel, @boss) when channel in @channels do :ok = Brain.DishwasherManager.remove_user(user) {:ok, "The user #{user} has been removed."} end - def on_message(<<"remove_users"::utf8>>, _channel, @boss) do + def on_message(<<"remove_users"::utf8>>, channel, @boss) when channel in @channels do :ok = Brain.DishwasherManager.remove_users() {:ok, "The user list was removed."} end - def on_message(<<"remove_schedule"::utf8>>, _channel, @boss) do + def on_message(<<"remove_schedule"::utf8>>, channel, @boss) when channel in @channels do :ok = Brain.DishwasherManager.remove_schedule() {:ok, "The schedule was removed."} end - def on_message(<<"set_manager"::utf8>>, _channel, @boss) do + def on_message(<<"set_manager"::utf8>>, channel, @boss) when channel in @channels do {:ok, manager} = Brain.DishwasherManager.set_manager_of_the_week() case manager do :no_specified -> {:ok, "The schedule has not been created. Use the command 'help' for more information."} @@ -87,66 +89,31 @@ defmodule Bot.DiswasherManager do end end - def on_message(<<"wave"::utf8>>, :dishwasher_app, _sender) do + def on_message(<<"wave"::utf8>>, channel, _sender) when channel in @channels do wave_dishwasher_manager() end - def on_message(<<"wave"::utf8>>, :channel, _sender) do - wave_dishwasher_manager() - end - - def on_message(<<":wave:"::utf8>>, :dishwasher_app, _sender) do - wave_dishwasher_manager() - end - - - def on_message(<<":wave:"::utf8>>, :channel, _sender) do + def on_message(<<":wave:"::utf8>>, channel, _sender) when channel in @channels do wave_dishwasher_manager() end # Prints out help message. - def on_message(<<"help"::utf8>>, @channel, @boss) do + def on_message(<<"help"::utf8>>, channel, @boss) when channel in @channels do res = boss_help_menu() {:ok, res} end # Prints out help message. - def on_message(<<"help"::utf8>>, @channel, _sender) do + def on_message(<<"help"::utf8>>, channel, _sender) when channel in @channels do res = user_help_menu() {:ok, res} end - # Prints out help message. - def on_message(<<"help"::utf8>>, :dishwasher_app, @boss) do - res = boss_help_menu() - {:ok, res} - end - - def on_message(<<"help"::utf8>>, :dishwasher_app, _sender) do - res = user_help_menu() - {:ok, res} - end - - -# def on_message(_text, @channel, _sender) do -# {:ok, general_msg()} -# end -# -# def on_message(_text, :dishwasher_app, _sender) do -# {:ok, general_msg()} -# end - def on_message(_text, _channel, _sender) do {:noreply} end -# defp general_msg do -# """ -# Hello Softie! Please use the command `help` for more information. -# """ -# end - defp build_schedule_list(schedule) when schedule == %{} , do: {:ok, "There is no schedule ready. Use the command 'help' for more information."} defp build_schedule_list(schedule) do From 7cb5fb43b87ba42b19ba2180ed6fdfee50d306b6 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Wed, 28 Mar 2018 00:39:57 +0200 Subject: [PATCH 29/30] Update dependencies --- data/dishwasher_manager/users.dat | 61 +++++++++++++++++-------------- mix.exs | 6 +-- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/data/dishwasher_manager/users.dat b/data/dishwasher_manager/users.dat index f1f8e01..35f4de8 100644 --- a/data/dishwasher_manager/users.dat +++ b/data/dishwasher_manager/users.dat @@ -1,28 +1,33 @@ -[{cderoove,<<"Coen De Roover">>}, - {mathsaey,<<"Mathijs Saey">>}, - {thierry,<<"Thierry Renaux">>}, - {kevin,<<"Kevin Pinte">>}, - {fmyter,<<"Florian Myter">>}, - {tmoldere,<<"Tim Molderez">>}, - {joeri,<<"Joeri De Koster">>}, - {simon,<<"Simon Van de Water">>}, - {nathalie,<<"Nathalie Oostvogels">>}, - {jswalens,<<"Janwillem Swalens">>}, - {eljenso,<<"Jens Nicolay">>}, - {kennedy,<<"Kennedy Kambona">>}, - {qstieven,<<"Quentin Stievenart">>}, - {dirk,<<"Dirk van Deun">>}, - {jbsartor,<<"Jennifer Sartor">>}, - {jdeblese,<<"Jonas De Bleser">>}, - {nvgeele,<<"Nils Van Geele">>}, - {ascullpu,<<"Angel Luis Scull Pupo">>}, - {carmen,<<"Carmen Torres Lopez">>}, - {jezaman,<<"Jesse Zaman">>}, - {mvdcamme,<<"Maarten Vandercammen">>}, - {lachrist,<<"Laurent Christophe">>}, - {marmat,<<"Matteo Marra">>}, - {noah,<<"Noah Van Es">>}, - {svdvonde,<<"Sam Van den Vonder">>}, - {humberto,<<"Humberto Rodriguez">>}, - {cdetroye,<<"Christophe De Troyer">>}, - {elisagboix,<<"Elisa Gonzalez">>}]. +[{'U03K40ETE',<<"Humberto Rodriguez">>}, + {'U08DX089E',<<"Christophe De Troyer">>}, + {'U02D6HWS1',<<"Elisa Gonzalez Boix">>}, + {'U0LV04PPT',<<"Ward Muylaert">>}, + {'U02C3FMQ2',<<"Wolfgang De Meuter">>}, + {'U94HUEHLJ',<<"Thomas Dupriez">>}, + {'U8PGUSQ3F',<<"Dario Di Nucci">>}, + {'U02QPK57T',<<"Coen De Roover">>}, + {'U02J6647B',<<"Mathijs Saey">>}, + {'U02J62LRF',<<"Thierry Renaux">>}, + {'U02BYG1E9',<<"Kevin Pinte">>}, + {'U02MXLBFX',<<"Florian Myter">>}, + {'U03QXV0QJ',<<"Tim Molderez">>}, + {'U03SKNNFB',<<"Joeri De Koster">>}, + {'U21S584KW',<<"Sam Van den Vonder">>}, + {'U02C2C9BD',<<"Nathalie Oostvogels">>}, + {'U02C3M0CL',<<"Janwillem Swalens">>}, + {'U02C36Q3E',<<"Jens Nicolay">>}, + {'U02J62SFM',<<"Kennedy Kambona">>}, + {'U02J7ERTW',<<"Quentin Stievenart">>}, + {'U02C53L03',<<"Dirk van Deun">>}, + {'U21RHEHR7',<<"Jonas De Bleser">>}, + {'U21SQKEFL',<<"Nils Van Geele">>}, + {'U0QSNFR96',<<"Angel Luis Scull Pupo">>}, + {'U15B9LJHL',<<"Carmen Torres">>}, + {'U02C36WBA',<<"Jesse Zaman">>}, + {'U088RMBMY',<<"Maarten Vandercammen">>}, + {'U03U17WCQ',<<"Laurent Christophe">>}, + {'U4U6994KG',<<"Matteo Marra">>}, + {'U6X6VGMF1',<<"Noah Van Es">>}, + {'U21S584KW',<<"Sam Van den Vonder">>}, + {'U6SH5G347',<<"Isaac Oteyo">>}, + {'U758VEE2E',<<"Yunior Pacheco Correa">>}]. diff --git a/mix.exs b/mix.exs index 58d79cc..a2e0405 100644 --- a/mix.exs +++ b/mix.exs @@ -27,10 +27,10 @@ defmodule Slackbot.Mixfile do # Type `mix help deps` for more examples and options defp deps do [ - {:slack, "~> 0.12.0"}, + {:slack, "~> 0.13.0"}, {:poison, "~> 3.1.0"}, - {:timex, "~> 3.1.24"}, - {:feeder_ex, "~> 1.1"}, + {:timex, "~> 3.2.1"}, + {:feeder_ex, "~> 1.1.0"}, {:html_entities, "~> 0.4.0"}, {:cronex, git: "https://github.com/rhumbertgz/cronex.git"} ] From d02f2856ed7012fe98e961eaf9eb3c6adc9a92d9 Mon Sep 17 00:00:00 2001 From: Humberto Rodriguez Avila Date: Wed, 28 Mar 2018 00:41:37 +0200 Subject: [PATCH 30/30] Fix error after user-name changes --- lib/bot/diswasher_manager.ex | 6 +- lib/brain/dishwasher_manager.ex | 114 +++++++++++++++----------- lib/scheduler/dishwasher_scheduler.ex | 4 +- lib/supervisor/bot.ex | 14 ++-- 4 files changed, 80 insertions(+), 58 deletions(-) diff --git a/lib/bot/diswasher_manager.ex b/lib/bot/diswasher_manager.ex index bb8d3ee..d2c316a 100644 --- a/lib/bot/diswasher_manager.ex +++ b/lib/bot/diswasher_manager.ex @@ -129,7 +129,7 @@ defmodule Bot.DiswasherManager do defp build_user_list(users) do resp = users - |> Enum.map(fn {user, fullname} -> "- #{fullname} (@#{user})" end) + |> Enum.map(fn {_, fullname} -> "- #{fullname}" end) |> Enum.join("\n") {:ok, "```#{resp}```"} @@ -144,9 +144,9 @@ defmodule Bot.DiswasherManager do Example: "manager?" schedule : Shows the current dishwasher schedule. Example: "schedule" - wave : Sends a notification to the current diswasher manager in case he has to do his duties. + wave : Sends a notification to the current dishwasher manager in case he has to do his duties. Example: "wave" or ":wave:" - when? : Shows the dates of your the next diswasher duties. + when? : Shows the dates of your the next dishwasher duties. Example: "when? " ``` diff --git a/lib/brain/dishwasher_manager.ex b/lib/brain/dishwasher_manager.ex index 2c9867a..98b87aa 100644 --- a/lib/brain/dishwasher_manager.ex +++ b/lib/brain/dishwasher_manager.ex @@ -3,6 +3,7 @@ defmodule Brain.DishwasherManager do use GenServer @users_file "data/dishwasher_manager/users.dat" + @users_map_file "data/dishwasher_manager/users-map.dat" @schedule_file "data/dishwasher_manager/schedule.dat" @holidays [~D[2017-12-25], ~D[2018-01-01] ] @@ -11,13 +12,13 @@ defmodule Brain.DishwasherManager do end def init([[]]) do - Logger.debug "No orders provided. Reading from disk." + Logger.debug "No state provided. Reading from disk." case restore_state() do {:ok, state} -> {:ok, state} _ -> - Logger.warn "No initial orders and can't read backup, starting with empty order." - {:ok, {%{}, %{}, :no_specified}} + Logger.warn "No initial state was restored from backup." + {:ok, {%{}, %{}, %{}, :no_specified}} end end @@ -83,33 +84,34 @@ defmodule Brain.DishwasherManager do # Calls # ######### - def handle_call(:users, _from, {_, users, _} = state) do + def handle_call(:users, _from, {_, users, _, _,_} = state) do {:reply, {:ok, users}, state} end - def handle_call(:manager?, _from, {_, users, manager} = state) do + def handle_call(:manager?, _from, {_, users, idNameMap, _, manager} = state) do fullName = Keyword.get(users, manager, :no_specified) - {:reply, {:ok, Atom.to_string(manager), fullName}, state} + user = Map.get(idNameMap, Atom.to_string(manager)) + {:reply, {:ok, user, fullName}, state} end - def handle_call(:next_manager, _from, {schedule, users, _} = state) do + def handle_call(:next_manager, _from, {schedule, users, idNameMap, _, _} = state) do manager = case get_next_manager(schedule) do :no_specified -> {user, _} = List.first users user user -> user end - - {:reply, {:ok, Atom.to_string(manager)}, state} + {:reply, {:ok, Map.get(idNameMap, Atom.to_string(manager))}, state} end - def handle_call({:when?, user}, _from, {schedule, _, _} = state) do - {fullName, startDate} = Keyword.get(schedule, String.to_atom(user), {:invalid_user, :no_specified}) + def handle_call({:when?, user}, _from, {schedule, _, _, nameIdMap, _} = state) do + userId = Map.get(nameIdMap, user) |> String.to_atom + {fullName, startDate} = Keyword.get(schedule, userId, {:invalid_user, :no_specified}) {:reply, {:ok, fullName, startDate}, state} end - def handle_call(:set_manager_of_the_week, _from, {schedule, users, _} ) do + def handle_call(:set_manager_of_the_week, _from, {schedule, users, idNameMap, nameIdMap, _} ) do {schedule, manager} = case get_manager_of_week(schedule) do :no_specified -> sch = build_schedule(users, Date.utc_today) @@ -117,15 +119,16 @@ defmodule Brain.DishwasherManager do {sch, man} user -> {schedule, user} end + fullName = Keyword.get(users, manager, :no_specified) - {:reply, {:ok, fullName}, {schedule, users, manager}} + {:reply, {:ok, fullName}, {schedule, users, idNameMap, nameIdMap, manager}} end - def handle_call(:schedule, _from, {schedule, _,_} = state) do + def handle_call(:schedule, _from, {schedule, _,_,_,_} = state) do {:reply, {:ok, schedule}, state} end - def handle_call({:create_schedule, startDate}, _from, {_, users, _}) do + def handle_call({:create_schedule, startDate}, _from, {_, users, idNameMap, nameIdMap, _}) do {:ok, startDate} = startDate |> String.trim() @@ -134,74 +137,79 @@ defmodule Brain.DishwasherManager do schedule = build_schedule(users, startDate) save_state(schedule, @schedule_file) manager = get_manager_of_week(schedule) - {:reply, {:ok, schedule}, {schedule, users, manager}} + {:reply, {:ok, schedule}, {schedule, users, idNameMap, nameIdMap, manager}} end - def handle_call({:add_user, user, fullname}, _from, {schedule, users, manager}) do + def handle_call({:add_user, user, fullname}, _from, {schedule, users, idNameMap, nameIdMap, manager}) do fullname = buildFullName(fullname) user = user |> String.trim() - |> String.to_atom() + # |> String.to_atom() - users = Keyword.put_new(users, user, fullname) - schedule = add_to_schedule(schedule, user, fullname) + userId = Map.get(nameIdMap, user) + users = Keyword.put_new(users, userId, fullname) + schedule = add_to_schedule(schedule, userId, fullname) save_state(schedule, @schedule_file) save_state(users, @users_file) - {:reply, :ok, {schedule, users, manager}} + {:reply, :ok, {schedule, users, idNameMap, nameIdMap, manager}} end - def handle_call({:remove_user, user}, _from, {schedule, users, manager}) do + def handle_call({:remove_user, user}, _from, {schedule, users, idNameMap, nameIdMap, manager}) do user = user |> String.trim() - |> String.to_atom() + # |> String.to_atom() - userList = Keyword.delete(users, user) + userId = Map.get(nameIdMap, user) + userList = Keyword.delete(users, userId) save_state(userList, @users_file) - {:reply, :ok, {schedule, userList, manager}} + {:reply, :ok, {schedule, userList, idNameMap, nameIdMap, manager}} end - def handle_call({:swap, _userA, _userB}, _from, {[], users, manager}) do - {:reply, {:error, "There is no schedule ready. Use the command 'help' for more information."}, {[], users, manager}} + def handle_call({:swap, _userA, _userB}, _from, {[], _, _, _, _} = state) do + {:reply, {:error, "There is no schedule ready. Use the command 'help' for more information."}, state} end - def handle_call({:swap, userA, userB}, _from, {schedule, users, manager}) do + def handle_call({:swap, userA, userB}, _from, {schedule, users, idNameMap, nameIdMap, manager}) do userA = userA |> String.trim() - |> String.to_atom() + # |> String.to_atom() userB = userB |> String.trim() - |> String.to_atom() + # |> String.to_atom() + + userIdA = Map.get(nameIdMap, userA) |> String.to_atom + userIdB = Map.get(nameIdMap, userB) |> String.to_atom - case validate_user_names([userA, userB], users) do + case validate_user_ids([userIdA, userIdB], users) do true -> - {nameA, dateA} = Keyword.get(schedule, userA) - {nameB, dateB} = Keyword.get(schedule, userB) + {nameA, dateA} = Keyword.get(schedule, userIdA) + {nameB, dateB} = Keyword.get(schedule, userIdB) newSchedule = schedule - |> Keyword.replace!(userA, {nameA, dateB}) - |> Keyword.replace!(userB, {nameB, dateA}) + |> Keyword.replace!(userIdA, {nameA, dateB}) + |> Keyword.replace!(userIdB, {nameB, dateA}) save_state(newSchedule, @schedule_file) manager = get_manager_of_week(newSchedule) - {:reply, :ok, {newSchedule, users, manager}} + {:reply, :ok, {newSchedule, users, idNameMap, nameIdMap, manager}} - msg -> {:reply, {:error, msg}, {schedule, users, manager}} + msg -> {:reply, {:error, msg}, {schedule, users, idNameMap, nameIdMap, manager}} end end - def handle_call(:remove_users, _from, _state) do + def handle_call(:remove_users, _from, {_, _, idNameMap, nameIdMap, _}) do save_state([], @users_file) save_state([], @schedule_file) - {:reply, :ok, {[], [], :no_specified}} + {:reply, :ok, {[], [], idNameMap, :no_specified}} end - def handle_call(:remove_schedule, _from, {_, users, _}) do + def handle_call(:remove_schedule, _from, {_, users, idNameMap,nameIdMap, _}) do save_state([], @schedule_file) - {:reply, :ok, {[], users, :no_specified}} + {:reply, :ok, {[], users, idNameMap,nameIdMap, :no_specified}} end @@ -230,7 +238,21 @@ defmodule Brain.DishwasherManager do manager = get_manager_of_week(schedule) - {:ok, {schedule, users, manager}} + members = Slack.Web.Users.list(%{token: "xoxb-236968418545-LS34wziPDCf07sha2bkzhbe3"}) + idNameMap = members + |> Map.get("members") + |> Enum.map(fn(member) -> + {member["id"], member["name"]} + end) + + nameIdMap = members + |> Map.get("members") + |> Enum.map(fn(member) -> + {member["name"], member["id"]} + end) + + + {:ok, {schedule, users, Map.new(idNameMap), Map.new(nameIdMap), manager}} end defp buildFullName(fullName, acc \\ "") @@ -249,11 +271,11 @@ defmodule Brain.DishwasherManager do Keyword.put(schedule, user, {fullName, get_next_valid_date(Date.add(lastDate, 7))}) end - defp validate_user_names([], _users), do: true - defp validate_user_names([user| rest], users) do + defp validate_user_ids([], _users), do: true + defp validate_user_ids([user| rest], users) do case Keyword.has_key?(users, user) do - false -> "Invalid username! The user #{user} is not a registered." - _ -> validate_user_names(rest, users) + false -> "Invalid user id! The user #{user} is not a registered." + _ -> validate_user_ids(rest, users) end end diff --git a/lib/scheduler/dishwasher_scheduler.ex b/lib/scheduler/dishwasher_scheduler.ex index 4100476..152e78d 100644 --- a/lib/scheduler/dishwasher_scheduler.ex +++ b/lib/scheduler/dishwasher_scheduler.ex @@ -37,7 +37,7 @@ defmodule Scheduler.DishwasherScheduler do send_notification(msg) end - every :thursday, at: "14:00" do + every :wednesday, at: "10:00" do msg = """ Hello! Next week you will be our Dishwasher Manager :tada: If you will be out next week please change your turn with another person using the `swap_with` command. @@ -48,7 +48,7 @@ defmodule Scheduler.DishwasherScheduler do end defp send_notification(msg) do - {:ok, manager} = Brain.DishwasherManager.manager?() + {:ok, manager, _} = Brain.DishwasherManager.manager?() SlackManager.send_private_message(msg, manager) end diff --git a/lib/supervisor/bot.ex b/lib/supervisor/bot.ex index eec9270..1686fc7 100644 --- a/lib/supervisor/bot.ex +++ b/lib/supervisor/bot.ex @@ -7,14 +7,14 @@ defmodule Supervisor.Bot do def init(opts) do children = [ - worker(Bot.Karma, [opts]), - worker(Bot.ChuckNorris, [opts]), - worker(Bot.Resto, [opts]), - worker(Bot.Cronjob, [opts]), - worker(Bot.Rss, [opts]), - worker(Bot.Benvolios, [opts]), +# worker(Bot.Karma, [opts]), +# worker(Bot.ChuckNorris, [opts]), +# worker(Bot.Resto, [opts]), +# worker(Bot.Cronjob, [opts]), +# worker(Bot.Rss, [opts]), +# worker(Bot.Benvolios, [opts]), worker(Bot.DiswasherManager, [opts]), - worker(Bot.Misc, [opts]) +# worker(Bot.Misc, [opts]) ] supervise(children, strategy: :one_for_one) end