defmodule PlausibleWeb.HelpScoutControllerTest do use PlausibleWeb.ConnCase, async: true @moduletag :ee_only on_ee do alias Plausible.HelpScout describe "callback/2" do test "returns details on success", %{conn: conn} do user = insert(:user) signature_key = Application.fetch_env!(:plausible, HelpScout)[:signature_key] data = ~s|{"conversation-id":"123","customer-id":"500"}| signature = :hmac |> :crypto.mac(:sha, signature_key, data) |> Base.encode64() |> URI.encode_www_form() Req.Test.stub(HelpScout, fn %{request_path: "/v2/oauth2/token"} = conn -> Req.Test.json(conn, %{ "token_type" => "bearer", "access_token" => "369dbb08be58430086d2f8bd832bc1eb", "expires_in" => 172_800 }) %{request_path: "/v2/customers/500"} = conn -> Req.Test.json(conn, %{ "id" => 500, "_embedded" => %{ "emails" => [ %{ "id" => 1, "value" => user.email, "type" => "home" } ] } }) end) conn = get( conn, "/helpscout/callback?conversation-id=123&customer-id=500&X-HelpScout-Signature=#{signature}" ) assert [] = Plug.Conn.get_resp_header(conn, "content-security-policy") html = html_response(conn, 200) assert html =~ Routes.customer_support_user_path(PlausibleWeb.Endpoint, :show, user.id) assert text_of_attr("input[name=token]", "value") != "" end test "returns error on failure", %{conn: conn} do conn = get( conn, "/helpscout/callback?conversation-id=123&customer-id=500&X-HelpScout-Signature=invalid" ) html = html_response(conn, 200) assert html =~ "bad_signature" refute text_of_attr("input[name=token]", "value") end test "handles invalid parameters gracefully", %{conn: conn} do conn = get( conn, "/helpscout/callback?customer-id=500&X-HelpScout-Signature=whatever" ) assert html_response(conn, 200) =~ "Missing expected parameters" end end describe "search/2" do test "returns results", %{conn: conn} do insert(:user, email: "hs.match@plausible.test") insert(:user, email: "hs.nomatch@plausible.test") token = sign_conversation_token("123") conn = conn |> get( "/helpscout/search?conversation_id=123&customer_id=500&term=hs.match&token=#{token}" ) html = html_response(conn, 200) assert html =~ "hs.match@plausible.test" refute html =~ "hs.nomatch@plausible.test" end test "returns error when token is invalid", %{conn: conn} do conn = get( conn, "/helpscout/search?conversation_id=123&customer_id=500&term=hs.match&token=invalid" ) assert html_response(conn, 200) =~ "invalid_token" end test "returns error when token does not match", %{conn: conn} do token = sign_conversation_token("456") conn = conn |> get( "/helpscout/search?conversation_id=123&customer_id=500&term=hs.match&token=#{token}" ) assert html_response(conn, 200) =~ "invalid_conversation" end end describe "show/2" do test "returns details on success", %{conn: conn} do user = insert(:user, email: "hs.match@plausible.test", notes: "Some note\nwith new line") token = sign_conversation_token("123") conn = conn |> get( "/helpscout/show?conversation_id=123&customer_id=500&email=hs.match@plausible.test&token=#{token}" ) assert html = html_response(conn, 200) assert html =~ Routes.customer_support_user_path(PlausibleWeb.Endpoint, :show, user.id) assert html =~ "Some note
\nwith new line" end test "returns teams list when the match is an owner in multiple teams", %{conn: conn} do user = new_user(email: "hs.match@plausible.test", notes: "Some user notes") other_user = new_user() _site1 = new_site(owner: user) _site2 = new_site(owner: other_user) _team1 = team_of(user) team2 = team_of(other_user) team2 = team2 |> Plausible.Teams.complete_setup() |> Ecto.Changeset.change(name: "HS Integration Test Team") |> Plausible.Repo.update!() add_member(team2, user: user, role: :owner) token = sign_conversation_token("123") conn = conn |> get( "/helpscout/show?conversation_id=123&customer_id=500&email=hs.match@plausible.test&token=#{token}" ) assert html = html_response(conn, 200) assert html =~ Routes.customer_support_user_path(PlausibleWeb.Endpoint, :show, user.id) assert html =~ "Some user notes" assert html =~ "My personal sites" assert html =~ "HS Integration Test Team" end test "returns personal team details when identifier passed explicitly", %{conn: conn} do user = new_user(email: "hs.match@plausible.test", notes: "Some user notes") other_user = new_user() _site1 = new_site(owner: user) _site2 = new_site(owner: other_user) team1 = team_of(user) team2 = team_of(other_user) team2 = team2 |> Plausible.Teams.complete_setup() |> Ecto.Changeset.change(name: "HS Integration Test Team") |> Plausible.Repo.update!() add_member(team2, user: user, role: :owner) token = sign_conversation_token("123") conn = conn |> get( "/helpscout/show?conversation_id=123&customer_id=500&email=hs.match@plausible.test&team_identifier=#{team1.identifier}&token=#{token}" ) assert html = html_response(conn, 200) refute html =~ "HS Integration Test Team" refute html =~ "My personal sites" assert html =~ "Some user notes" end test "returns setup team details when identifier passed explicitly", %{conn: conn} do user = new_user(email: "hs.match@plausible.test", notes: "Some user notes") other_user = new_user() _site1 = new_site(owner: user) _site2 = new_site(owner: other_user) _team1 = team_of(user) team2 = team_of(other_user) team2 = team2 |> Plausible.Teams.complete_setup() |> Ecto.Changeset.change(name: "HS Integration Test Team") |> Plausible.Repo.update!() add_member(team2, user: user, role: :owner) token = sign_conversation_token("123") conn = conn |> get( "/helpscout/show?conversation_id=123&customer_id=500&email=hs.match@plausible.test&team_identifier=#{team2.identifier}&token=#{token}" ) assert html = html_response(conn, 200) assert html =~ "HS Integration Test Team" refute html =~ "My personal sites" assert html =~ "Some user notes" end test "returns error when token is invalid", %{conn: conn} do conn = get( conn, "/helpscout/show?conversation_id=123&customer_id=500&email=hs.match@plausible.test&token=invalid" ) assert html_response(conn, 200) =~ "invalid_token" end test "returns error when token does not match", %{conn: conn} do token = sign_conversation_token("456") conn = conn |> get( "/helpscout/show?conversation_id=123&customer_id=500&email=hs.match@plausible.test&token=#{token}" ) assert html_response(conn, 200) =~ "invalid_conversation" end end defp sign_conversation_token(conversation_id) do PlausibleWeb.HelpScoutController.sign_token(conversation_id) end end end