diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 698abc1c..ec2abd89 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,10 @@ env: SONARR_BASE_URL: http://localhost:8989 SONARR_API_KEY: 1accda4476394bfcaddefe8c4fd77d4a + VAPID_PUBLIC_KEY: BDntLA3k5K1tsrFOXXAuS_9Ey30jxy-R2CAosC2DOQnTs8LpQGxpTEx3AcPXinVYFFpJI6tT_RJC8pHgUsdbhOk + VAPID_PRIVATE_KEY: RVPPDBVNmJtSLoZ28jE1SumpG4HyhhCPfcix3bvxbLw + VAPID_SUBJECT: mailto:admin@email.com + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} @@ -40,7 +44,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - otp: [ '25' ] + otp: [ '24' ] elixir: [ '1.15' ] services: diff --git a/README.md b/README.md index 97af4473..18343b6a 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ services: To keep your media in sync, webhook urls are required in your integrations. Midarr accepts a POST request from your integrations with your unique API Token (found on the Midarr Settings page). -Add your webhook urls to `Radarr / Sonarr -> Settings -> Connect`: +Add these webhook urls to Radarr / Sonarr under `Settings -> Connect -> Webhook`: #### Radarr example ``` diff --git a/lib/media_server/application.ex b/lib/media_server/application.ex index 4c6975d7..e5e13a83 100644 --- a/lib/media_server/application.ex +++ b/lib/media_server/application.ex @@ -20,9 +20,11 @@ defmodule MediaServer.Application do # {MediaServer.Worker, arg} MediaServerWeb.Presence, {DynamicSupervisor, name: MediaServer.DynamicSupervisor}, - MediaServer.UserActions, MediaServer.MoviesIndex, - MediaServer.SeriesIndex + MediaServer.SeriesIndex, + MediaServer.MovieActions, + MediaServer.SeriesActions, + MediaServer.UserActions ] # See https://hexdocs.pm/elixir/Supervisor.html diff --git a/lib/media_server/media_actions.ex b/lib/media_server/media_actions.ex index 9a591ea3..fc2f4628 100644 --- a/lib/media_server/media_actions.ex +++ b/lib/media_server/media_actions.ex @@ -1,6 +1,7 @@ defmodule MediaServer.MediaActions do use Ecto.Schema import Ecto.Changeset + import Ecto.Query alias MediaServer.Repo @@ -59,6 +60,25 @@ defmodule MediaServer.MediaActions do def delete(attrs) do Repo.get_by(__MODULE__, attrs) - |> Repo.delete + |> Repo.delete() + end + + def movie(id) do + from this in __MODULE__, + where: this.media_type_id == ^MediaServer.MediaTypes.get_movie_id() and this.media_id == ^id + end + + def series(id) do + from this in __MODULE__, + where: + this.media_type_id == ^MediaServer.MediaTypes.get_series_id() and this.media_id == ^id + end + + def followers(query) do + MediaServer.Repo.all( + from this in query, + where: this.action_id == ^MediaServer.Actions.get_followed_id(), + preload: [user: [:push_subscriptions]] + ) end end diff --git a/lib/media_server/media_types.ex b/lib/media_server/media_types.ex index 3b73b2c7..f3ad3cf8 100644 --- a/lib/media_server/media_types.ex +++ b/lib/media_server/media_types.ex @@ -25,6 +25,10 @@ defmodule MediaServer.MediaTypes do Repo.get_by!(__MODULE__, type: "movie").id end + def get_series_id() do + Repo.get_by!(__MODULE__, type: "series").id + end + def get_episode_id() do Repo.get_by!(__MODULE__, type: "episode").id end diff --git a/lib/media_server/movie_actions.ex b/lib/media_server/movie_actions.ex new file mode 100644 index 00000000..00231b04 --- /dev/null +++ b/lib/media_server/movie_actions.ex @@ -0,0 +1,34 @@ +defmodule MediaServer.MovieActions do + use Task + + def start_link(arg) do + Task.start_link(__MODULE__, :run, [arg]) + end + + def run(_arg) do + Phoenix.PubSub.subscribe(MediaServer.PubSub, "movie") + end + + def handle_info({:added, %{"movie" => %{"id" => id, "title" => title}}}) do + MediaServer.MoviesIndex.reset() + + followers = MediaServer.MediaActions.movie(id) |> MediaServer.MediaActions.followers() + + Enum.each(followers, fn media_action -> + Enum.each(media_action.user.push_subscriptions, fn push_subscription -> + WebPushElixir.send_notification( + push_subscription.push_subscription, + "#{title} is now available" + ) + end) + end) + end + + def handle_info({:deleted}) do + MediaServer.MoviesIndex.reset() + end + + def handle_info({:deleted_file}) do + MediaServer.MoviesIndex.reset() + end +end diff --git a/lib/media_server/push_subscriptions.ex b/lib/media_server/push_subscriptions.ex index 2ed44309..be3f567b 100644 --- a/lib/media_server/push_subscriptions.ex +++ b/lib/media_server/push_subscriptions.ex @@ -34,6 +34,6 @@ defmodule MediaServer.PushSubscriptions do def delete(attrs) do Repo.get_by(__MODULE__, attrs) - |> Repo.delete + |> Repo.delete() end end diff --git a/lib/media_server/series_actions.ex b/lib/media_server/series_actions.ex new file mode 100644 index 00000000..a58b76e1 --- /dev/null +++ b/lib/media_server/series_actions.ex @@ -0,0 +1,36 @@ +defmodule MediaServer.SeriesActions do + use Task + + require Logger + + def start_link(arg) do + Task.start_link(__MODULE__, :run, [arg]) + end + + def run(_arg) do + Phoenix.PubSub.subscribe(MediaServer.PubSub, "series") + end + + def handle_info({:added, %{"series" => %{"id" => id, "title" => title}}}) do + MediaServer.SeriesIndex.reset() + + followers = MediaServer.MediaActions.series(id) |> MediaServer.MediaActions.followers() + + Enum.each(followers, fn media_action -> + Enum.each(media_action.user.push_subscriptions, fn push_subscription -> + WebPushElixir.send_notification( + push_subscription.push_subscription, + "#{title} is now available" + ) + end) + end) + end + + def handle_info({:deleted}) do + MediaServer.SeriesIndex.reset() + end + + def handle_info({:deleted_episode_file}) do + MediaServer.SeriesIndex.reset() + end +end diff --git a/lib/media_server/user_actions.ex b/lib/media_server/user_actions.ex index b94a3cbd..41efef0e 100644 --- a/lib/media_server/user_actions.ex +++ b/lib/media_server/user_actions.ex @@ -24,7 +24,6 @@ defmodule MediaServer.UserActions do end def handle_info({:followed, params}, state) do - media_type_id = MediaServer.MediaTypes.get_type_id(params["media_type"]) MediaServer.MediaActions.create(%{ @@ -34,13 +33,14 @@ defmodule MediaServer.UserActions do media_type_id: media_type_id }) - Logger.info("user_id:#{ params["user_id"] }:followed:media_type_id:#{ media_type_id }:media_id:#{ params["media_id"] }") + Logger.info( + "user_id:#{params["user_id"]}:followed:media_type_id:#{media_type_id}:media_id:#{params["media_id"]}" + ) {:noreply, state} end def handle_info({:unfollowed, params}, state) do - media_type_id = MediaServer.MediaTypes.get_type_id(params["media_type"]) MediaServer.MediaActions.delete(%{ @@ -50,31 +50,35 @@ defmodule MediaServer.UserActions do media_type_id: media_type_id }) - Logger.info("user_id:#{ params["user_id"] }:unfollowed:media_type_id:#{ media_type_id }:media_id:#{ params["media_id"] }") + Logger.info( + "user_id:#{params["user_id"]}:unfollowed:media_type_id:#{media_type_id}:media_id:#{params["media_id"]}" + ) {:noreply, state} end def handle_info({:granted_push_notifications, params}, state) do - MediaServer.PushSubscriptions.create(%{ user_id: params["user_id"], push_subscription: params["push_subscription"] }) - Logger.info("user_id:#{ params["user_id"] }:granted_push_notifications:media_type_id:#{ params["media_type_id"] }:media_id:#{ params["media_id"] }") + Logger.info( + "user_id:#{params["user_id"]}:granted_push_notifications:media_type_id:#{params["media_type_id"]}:media_id:#{params["media_id"]}" + ) {:noreply, state} end def handle_info({:denied_push_notifications, params}, state) do - MediaServer.PushSubscriptions.create(%{ user_id: params["user_id"], push_subscription: params["message"] }) - Logger.info("user_id:#{ params["user_id"] }:denied_push_notifications:media_type_id:#{ params["media_type_id"] }:media_id:#{ params["media_id"] }") + Logger.info( + "user_id:#{params["user_id"]}:denied_push_notifications:media_type_id:#{params["media_type_id"]}:media_id:#{params["media_id"]}" + ) {:noreply, state} end diff --git a/lib/media_server_web/components/follow_component.ex b/lib/media_server_web/components/follow_component.ex index f8f5858b..4051f3c3 100644 --- a/lib/media_server_web/components/follow_component.ex +++ b/lib/media_server_web/components/follow_component.ex @@ -6,16 +6,20 @@ defmodule MediaServerWeb.Components.FollowComponent do @impl true def preload(list_of_assigns) do media_id = Enum.find(list_of_assigns, fn assign -> Map.get(assign, :media_id) end).media_id - media_type = Enum.find(list_of_assigns, fn assign -> Map.get(assign, :media_type) end).media_type + + media_type = + Enum.find(list_of_assigns, fn assign -> Map.get(assign, :media_type) end).media_type + user_id = Enum.find(list_of_assigns, fn assign -> Map.get(assign, :user_id) end).user_id media_type_id = MediaServer.MediaTypes.get_type_id(media_type) query = from media_actions in MediaServer.MediaActions, - where: - media_actions.media_type_id == ^media_type_id and - media_actions.user_id == ^user_id and media_actions.media_id == ^media_id and media_actions.action_id == ^MediaServer.Actions.get_followed_id + where: + media_actions.media_type_id == ^media_type_id and + media_actions.user_id == ^user_id and media_actions.media_id == ^media_id and + media_actions.action_id == ^MediaServer.Actions.get_followed_id() result = MediaServer.Repo.all(query) @@ -30,7 +34,8 @@ defmodule MediaServerWeb.Components.FollowComponent do state: "Following", event: "unfollow" } - end |> Map.merge(%{ + end + |> Map.merge(%{ media_id: assign.media_id, media_type: assign.media_type, user_id: assign.user_id, diff --git a/lib/media_server_web/components/follow_component.html.heex b/lib/media_server_web/components/follow_component.html.heex index 41296f8e..8c7f0500 100644 --- a/lib/media_server_web/components/follow_component.html.heex +++ b/lib/media_server_web/components/follow_component.html.heex @@ -10,4 +10,4 @@ class="inline-flex items-center gap-2 justify-center rounded-lg py-2 px-3 text-sm outline-offset-2 transition active:transition-none bg-zinc-800 font-semibold text-zinc-100 hover:bg-zinc-700 active:bg-zinc-800" > <%= @state %> - \ No newline at end of file + diff --git a/lib/media_server_web/components/footer_component.html.heex b/lib/media_server_web/components/footer_component.html.heex index 014f09ab..fce9b0e7 100644 --- a/lib/media_server_web/components/footer_component.html.heex +++ b/lib/media_server_web/components/footer_component.html.heex @@ -3,7 +3,7 @@

Copyright © 2023 Midarr Labs

- v4.2.0-beta.1 + v4.2.0-beta.2

diff --git a/lib/media_server_web/controllers/webhooks_controller.ex b/lib/media_server_web/controllers/webhooks_controller.ex index 328095e7..ccae5b53 100644 --- a/lib/media_server_web/controllers/webhooks_controller.ex +++ b/lib/media_server_web/controllers/webhooks_controller.ex @@ -1,43 +1,43 @@ defmodule MediaServerWeb.WebhooksController do use MediaServerWeb, :controller - def create(conn, %{"id" => "movie", "eventType" => "Download"}) do - MediaServer.MoviesIndex.reset() + def create(conn, %{"id" => "movie", "eventType" => "Download"} = params) do + Phoenix.PubSub.broadcast(MediaServer.PubSub, "movie", {:added, params}) conn |> send_resp(201, "Ok") end def create(conn, %{"id" => "movie", "eventType" => "MovieDelete"}) do - MediaServer.MoviesIndex.reset() + Phoenix.PubSub.broadcast(MediaServer.PubSub, "movie", {:deleted}) conn |> send_resp(201, "Ok") end def create(conn, %{"id" => "movie", "eventType" => "MovieFileDelete"}) do - MediaServer.MoviesIndex.reset() + Phoenix.PubSub.broadcast(MediaServer.PubSub, "movie", {:deleted_file}) conn |> send_resp(201, "Ok") end - def create(conn, %{"id" => "series", "eventType" => "Download"}) do - MediaServer.SeriesIndex.reset() + def create(conn, %{"id" => "series", "eventType" => "Download"} = params) do + Phoenix.PubSub.broadcast(MediaServer.PubSub, "series", {:added, params}) conn |> send_resp(201, "Ok") end def create(conn, %{"id" => "series", "eventType" => "SeriesDelete"}) do - MediaServer.SeriesIndex.reset() + Phoenix.PubSub.broadcast(MediaServer.PubSub, "series", {:deleted}) conn |> send_resp(201, "Ok") end def create(conn, %{"id" => "series", "eventType" => "EpisodeFileDelete"}) do - MediaServer.SeriesIndex.reset() + Phoenix.PubSub.broadcast(MediaServer.PubSub, "series", {:deleted_episode_file}) conn |> send_resp(201, "Ok") diff --git a/lib/media_server_web/live/movies_live/show.html.heex b/lib/media_server_web/live/movies_live/show.html.heex index be376bff..7b21ac04 100644 --- a/lib/media_server_web/live/movies_live/show.html.heex +++ b/lib/media_server_web/live/movies_live/show.html.heex @@ -20,16 +20,16 @@
<%= if @movie["hasFile"] do %> - <.link - id={"play-#{ @movie["id"] }"} - navigate={"/watch?movie=#{@movie["id"]}#{ if !is_nil(@continue) do "×tamp=#{@continue.current_time}" end }"} - class="group relative flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-full bg-zinc-800 hover:bg-zinc-700 focus:outline-none focus:ring focus:ring-slate-700 focus:ring-offset-4" - > - - - - - + <.link + id={"play-#{ @movie["id"] }"} + navigate={"/watch?movie=#{@movie["id"]}#{ if !is_nil(@continue) do "×tamp=#{@continue.current_time}" end }"} + class="group relative flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-full bg-zinc-800 hover:bg-zinc-700 focus:outline-none focus:ring focus:ring-slate-700 focus:ring-offset-4" + > + + + + + <% end %> <.live_component @@ -39,7 +39,7 @@ media_type="movie" user_id={@current_user.id} return_to={~p"/movies/#{@movie["id"]}"} - /> + />
diff --git a/lib/media_server_web/live/series_live/show.html.heex b/lib/media_server_web/live/series_live/show.html.heex index 97acf6f1..05e09650 100644 --- a/lib/media_server_web/live/series_live/show.html.heex +++ b/lib/media_server_web/live/series_live/show.html.heex @@ -26,7 +26,7 @@ media_type="series" user_id={@current_user.id} return_to={~p"/series/#{@serie["id"]}"} - /> + /> diff --git a/lib/media_server_web/templates/layout/live.html.heex b/lib/media_server_web/templates/layout/live.html.heex index 81c5df13..65337f66 100644 --- a/lib/media_server_web/templates/layout/live.html.heex +++ b/lib/media_server_web/templates/layout/live.html.heex @@ -20,7 +20,7 @@
<.link - navigate={"/movies"} + navigate="/movies" class="inline-flex flex-col items-center justify-center p-4 hover:bg-gray-50 dark:hover:bg-gray-800 group" > Movies <.link - navigate={"/series"} + navigate="/series" class="inline-flex flex-col items-center justify-center p-4 hover:bg-gray-50 dark:hover:bg-gray-800 group" > Series <.link - navigate={"/history"} + navigate="/history" class="inline-flex flex-col items-center justify-center p-4 hover:bg-gray-50 dark:hover:bg-gray-800 group" > "http://localhost:8081/some-push-service", + "keys" => %{ + "p256dh" => + "BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM=", + "auth" => "tBHItJI5svbpez7KI4CCXg==" + } + } + @subscription_with_error %{ + "endpoint" => "http://localhost:8081/some-push-service-with-error", + "keys" => %{ + "p256dh" => + "BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM=", + "auth" => "tBHItJI5svbpez7KI4CCXg==" + } + } + setup do %{user: MediaServer.AccountsFixtures.user_fixture()} end - test "it should halt", %{conn: conn} do - conn = - post(conn, Routes.webhooks_path(conn, :create, "movie", %{"someKey" => "someValue"}), - token: "someToken" - ) + test "movie should halt", %{conn: conn} do + conn = post(conn, ~p"/api/webhooks/movie?token=someToken", %{"someKey" => "someValue"}) assert conn.status === 403 assert conn.halted end - test "it should fall through", %{conn: conn, user: user} do + test "movie should fall through", %{conn: conn, user: user} do conn = - post(conn, Routes.webhooks_path(conn, :create, "movie", %{"someKey" => "someValue"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/movie?token=#{user.api_token.token}", %{ + "someKey" => "someValue" + }) assert conn.status === 200 end - test "it should fall through again", %{conn: conn, user: user} do + test "movie should fall through again", %{conn: conn, user: user} do conn = - post(conn, Routes.webhooks_path(conn, :create, "movie", %{"eventType" => "someValue"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/movie?token=#{user.api_token.token}", %{ + "eventType" => "someValue" + }) assert conn.status === 200 end - test "it should create", %{conn: conn, user: user} do + test "it should add movie", %{conn: conn, user: user} do + {:ok, _struct} = + MediaServer.MediaActions.create(%{ + media_id: 3, + user_id: user.id, + action_id: MediaServer.Actions.get_followed_id(), + media_type_id: MediaServer.MediaTypes.get_type_id("movie") + }) + + {:ok, _struct} = + MediaServer.PushSubscriptions.create(%{ + user_id: user.id, + push_subscription: Jason.encode!(@subscription) + }) + + {:ok, _struct} = + MediaServer.PushSubscriptions.create(%{ + user_id: user.id, + push_subscription: Jason.encode!(@subscription_with_error) + }) + conn = - post(conn, Routes.webhooks_path(conn, :create, "movie", %{"eventType" => "Download"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/movie?token=#{user.api_token.token}", %{ + "eventType" => "Download", + "movie" => %{"id" => 3, "title" => "Some Movie"} + }) assert conn.status === 201 end - test "it should create on delete", %{conn: conn, user: user} do + test "it should delete movie", %{conn: conn, user: user} do conn = - post(conn, Routes.webhooks_path(conn, :create, "movie", %{"eventType" => "MovieDelete"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/movie?token=#{user.api_token.token}", %{ + "eventType" => "MovieDelete" + }) assert conn.status === 201 end - test "it should create on file delete", %{conn: conn, user: user} do + test "it should delete movie file", %{conn: conn, user: user} do conn = - post( - conn, - Routes.webhooks_path(conn, :create, "movie", %{"eventType" => "MovieFileDelete"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/movie?token=#{user.api_token.token}", %{ + "eventType" => "MovieFileDelete" + }) assert conn.status === 201 end test "series should halt", %{conn: conn} do - conn = - post(conn, Routes.webhooks_path(conn, :create, "series", %{"someKey" => "someValue"}), - token: "someToken" - ) + conn = post(conn, ~p"/api/webhooks/series?token=someToken", %{"someKey" => "someValue"}) assert conn.status === 403 assert conn.halted @@ -74,47 +104,74 @@ defmodule MediaServerWeb.WebhooksControllerTest do test "series should fall through", %{conn: conn, user: user} do conn = - post(conn, Routes.webhooks_path(conn, :create, "series", %{"someKey" => "someValue"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/series?token=#{user.api_token.token}", %{ + "someKey" => "someValue" + }) assert conn.status === 200 end test "series should fall through again", %{conn: conn, user: user} do conn = - post(conn, Routes.webhooks_path(conn, :create, "series", %{"eventType" => "someValue"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/series?token=#{user.api_token.token}", %{ + "eventType" => "someValue" + }) assert conn.status === 200 end - test "series should create", %{conn: conn, user: user} do + test "it should add series", %{conn: conn, user: user} do + {:ok, _struct} = + MediaServer.MediaActions.create(%{ + media_id: 1, + user_id: user.id, + action_id: MediaServer.Actions.get_followed_id(), + media_type_id: MediaServer.MediaTypes.get_type_id("series") + }) + + {:ok, _struct} = + MediaServer.PushSubscriptions.create(%{ + user_id: user.id, + push_subscription: Jason.encode!(@subscription) + }) + + {:ok, _struct} = + MediaServer.PushSubscriptions.create(%{ + user_id: user.id, + push_subscription: Jason.encode!(@subscription_with_error) + }) + conn = - post(conn, Routes.webhooks_path(conn, :create, "series", %{"eventType" => "Download"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/series?token=#{user.api_token.token}", %{ + "eventType" => "Download", + "series" => %{"id" => 1, "title" => "Some Series"} + }) assert conn.status === 201 end - test "series should create on delete", %{conn: conn, user: user} do + test "it should delete series", %{conn: conn, user: user} do + Phoenix.PubSub.subscribe(MediaServer.PubSub, "series") + conn = - post(conn, Routes.webhooks_path(conn, :create, "series", %{"eventType" => "SeriesDelete"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/series?token=#{user.api_token.token}", %{ + "eventType" => "SeriesDelete" + }) + + assert_received {:deleted} assert conn.status === 201 end test "series should create on episode file delete", %{conn: conn, user: user} do + Phoenix.PubSub.subscribe(MediaServer.PubSub, "series") + conn = - post( - conn, - Routes.webhooks_path(conn, :create, "series", %{"eventType" => "EpisodeFileDelete"}), - token: user.api_token.token - ) + post(conn, ~p"/api/webhooks/series?token=#{user.api_token.token}", %{ + "eventType" => "EpisodeFileDelete" + }) + + assert_received {:deleted_episode_file} assert conn.status === 201 end diff --git a/test/media_server_web/user_follow_test.exs b/test/media_server_web/user_follow_test.exs index 529b4f71..12dde76b 100644 --- a/test/media_server_web/user_follow_test.exs +++ b/test/media_server_web/user_follow_test.exs @@ -22,7 +22,8 @@ defmodule MediaServerWeb.UserFollowTest do |> element("#follow", "Follow") |> render_hook(:follow, %{media_id: movie["id"], media_type: "movie", user_id: user.id}) - assert_received {:followed, %{"media_id" => 3, "media_type" => "movie", "user_id" => _user_id}} + assert_received {:followed, + %{"media_id" => 3, "media_type" => "movie", "user_id" => _user_id}} # Not ideal but wait for processed message (async) :timer.sleep(1000) @@ -53,7 +54,8 @@ defmodule MediaServerWeb.UserFollowTest do |> element("#follow", "Following") |> render_hook(:unfollow, %{media_id: movie["id"], media_type: "movie", user_id: user.id}) - assert_received {:unfollowed, %{"media_id" => 3, "media_type" => "movie", "user_id" => _user_id}} + assert_received {:unfollowed, + %{"media_id" => 3, "media_type" => "movie", "user_id" => _user_id}} # Not ideal but wait for processed message (async) :timer.sleep(1000) @@ -74,7 +76,8 @@ defmodule MediaServerWeb.UserFollowTest do |> element("#follow", "Follow") |> render_hook(:follow, %{media_id: series["id"], media_type: "series", user_id: user.id}) - assert_received {:followed, %{"media_id" => 1, "media_type" => "series", "user_id" => _user_id}} + assert_received {:followed, + %{"media_id" => 1, "media_type" => "series", "user_id" => _user_id}} # Not ideal but wait for processed message (async) :timer.sleep(1000) @@ -105,7 +108,8 @@ defmodule MediaServerWeb.UserFollowTest do |> element("#follow", "Following") |> render_hook(:unfollow, %{media_id: series["id"], media_type: "series", user_id: user.id}) - assert_received {:unfollowed, %{"media_id" => 1, "media_type" => "series", "user_id" => _user_id}} + assert_received {:unfollowed, + %{"media_id" => 1, "media_type" => "series", "user_id" => _user_id}} # Not ideal but wait for processed message (async) :timer.sleep(1000) @@ -124,9 +128,20 @@ defmodule MediaServerWeb.UserFollowTest do view |> element("#follow", "Follow") - |> render_hook(:grant_push_notifications, %{media_id: movie["id"], media_type: "movie", user_id: user.id, push_subscription: "some subscription"}) + |> render_hook(:grant_push_notifications, %{ + media_id: movie["id"], + media_type: "movie", + user_id: user.id, + push_subscription: "some subscription" + }) - assert_received {:granted_push_notifications, %{"media_id" => 3, "media_type" => "movie", "user_id" => _user_id, "push_subscription" => "some subscription"}} + assert_received {:granted_push_notifications, + %{ + "media_id" => 3, + "media_type" => "movie", + "user_id" => _user_id, + "push_subscription" => "some subscription" + }} # Not ideal but wait for processed message (async) :timer.sleep(1000) @@ -145,9 +160,20 @@ defmodule MediaServerWeb.UserFollowTest do view |> element("#follow", "Follow") - |> render_hook(:deny_push_notifications, %{media_id: movie["id"], media_type: "movie", user_id: user.id, message: "some message"}) + |> render_hook(:deny_push_notifications, %{ + media_id: movie["id"], + media_type: "movie", + user_id: user.id, + message: "some message" + }) - assert_received {:denied_push_notifications, %{"media_id" => 3, "media_type" => "movie", "user_id" => _user_id, "message" => "some message"}} + assert_received {:denied_push_notifications, + %{ + "media_id" => 3, + "media_type" => "movie", + "user_id" => _user_id, + "message" => "some message" + }} # Not ideal but wait for processed message (async) :timer.sleep(1000) diff --git a/test/support/mock_server.ex b/test/support/mock_server.ex index 15be6bc8..44e9bd62 100644 --- a/test/support/mock_server.ex +++ b/test/support/mock_server.ex @@ -18,4 +18,14 @@ defmodule MediaServer.MockServer do conn |> Plug.Conn.send_resp(200, Jason.encode!(%{name: "someName", email: "someEmail"})) end + + post "/some-push-service" do + conn + |> Plug.Conn.send_resp(201, "ok") + end + + post "/some-push-service-with-error" do + conn + |> Plug.Conn.send_resp(401, "unauthorized") + end end