| defmodule PlausibleWeb.Plugins.API.Controllers.SharedLinksTest do |
| use PlausibleWeb.PluginsAPICase, async: true |
|
|
| describe "examples" do |
| test "SharedLink" do |
| assert_schema( |
| Schemas.SharedLink.schema().example, |
| "SharedLink", |
| spec() |
| ) |
| end |
| end |
|
|
| describe "unauthorized calls" do |
| for {method, url} <- [ |
| {:get, Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :get, 1)}, |
| {:put, Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :create)}, |
| {:get, Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :index)} |
| ] do |
| test "unauthorized call: #{method} #{url}", %{conn: conn} do |
| conn |
| |> unquote(method)(unquote(url)) |
| |> json_response(401) |
| |> assert_schema("UnauthorizedError", spec()) |
| end |
| end |
| end |
|
|
| describe "get /shared_links/:id" do |
| test "validates input out of the box", %{conn: conn, token: token, site: site} do |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :get, "hello") |
|
|
| resp = |
| conn |
| |> authenticate(site.domain, token) |
| |> get(url) |
| |> json_response(422) |
| |> assert_schema("UnprocessableEntityError", spec()) |
|
|
| assert %{errors: [%{detail: "Invalid integer. Got: string"}]} = resp |
| end |
|
|
| test "retrieve shared link by ID", %{conn: conn, site: site, token: token} do |
| shared_link = insert(:shared_link, name: "Some Link Name", site: site) |
|
|
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :get, shared_link.id) |
|
|
| resp = |
| conn |
| |> authenticate(site.domain, token) |
| |> get(url) |
| |> json_response(200) |
| |> assert_schema("SharedLink", spec()) |
|
|
| assert resp.shared_link.href == |
| "http://localhost:8000/share/#{URI.encode_www_form(site.domain)}?auth=#{shared_link.slug}" |
|
|
| assert resp.shared_link.id == shared_link.id |
| assert resp.shared_link.password_protected == false |
| assert resp.shared_link.name == "Some Link Name" |
| end |
|
|
| test "fails to retrieve non-existing link", %{conn: conn, site: site, token: token} do |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :get, 666) |
|
|
| conn |
| |> authenticate(site.domain, token) |
| |> get(url) |
| |> json_response(404) |
| |> assert_schema("NotFoundError", spec()) |
| end |
|
|
| test "fails to retrieve link from another site", %{conn: conn, site: site, token: token} do |
| shared_link = insert(:shared_link, name: "Some Link Name", site: build(:site)) |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :get, shared_link.id) |
|
|
| conn |
| |> authenticate(site.domain, token) |
| |> get(url) |
| |> json_response(404) |
| |> assert_schema("NotFoundError", spec()) |
| end |
| end |
|
|
| describe "put /shared_links" do |
| test "successfully creates a shared link with the location header", %{ |
| conn: conn, |
| site: site, |
| token: token |
| } do |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :create) |
|
|
| initial_conn = authenticate(conn, site.domain, token) |
|
|
| conn = |
| initial_conn |
| |> put_req_header("content-type", "application/json") |
| |> put(url, %{ |
| shared_link: %{ |
| name: "My Shared Link" |
| } |
| }) |
|
|
| resp = |
| conn |
| |> json_response(201) |
| |> assert_schema("SharedLink", spec()) |
|
|
| assert resp.shared_link.name == "My Shared Link" |
|
|
| assert resp.shared_link.href =~ |
| "http://localhost:8000/share/#{URI.encode_www_form(site.domain)}?auth=" |
|
|
| [location] = get_resp_header(conn, "location") |
|
|
| assert location == |
| Routes.plugins_api_shared_links_url( |
| PlausibleWeb.Endpoint, |
| :get, |
| resp.shared_link.id |
| ) |
|
|
| assert ^resp = |
| initial_conn |
| |> get(location) |
| |> json_response(200) |
| |> assert_schema("SharedLink", spec()) |
| end |
|
|
| test "create is idempotent", %{ |
| conn: conn, |
| site: site, |
| token: token |
| } do |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :create) |
|
|
| initial_conn = authenticate(conn, site.domain, token) |
|
|
| create = fn -> |
| initial_conn |
| |> put_req_header("content-type", "application/json") |
| |> put(url, %{ |
| shared_link: %{ |
| name: "My Shared Link" |
| } |
| }) |
| end |
|
|
| conn = create.() |
|
|
| resp = |
| conn |
| |> json_response(201) |
| |> assert_schema("SharedLink", spec()) |
|
|
| id = resp.shared_link.id |
|
|
| conn = create.() |
|
|
| assert ^id = |
| conn |
| |> json_response(201) |
| |> Map.fetch!("shared_link") |
| |> Map.fetch!("id") |
| end |
|
|
| test "validates input out of the box", %{conn: conn, token: token, site: site} do |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :create) |
|
|
| resp = |
| conn |
| |> authenticate(site.domain, token) |
| |> put_req_header("content-type", "application/json") |
| |> put(url, %{}) |
| |> json_response(422) |
| |> assert_schema("UnprocessableEntityError", spec()) |
|
|
| assert %{errors: [%{detail: "Missing field: shared_link"}]} = resp |
| end |
|
|
| test "skips shared links feature access check", %{ |
| conn: conn, |
| site: site, |
| token: token |
| } do |
| insert(:starter_subscription, team: site.team) |
|
|
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :create) |
|
|
| resp = |
| authenticate(conn, site.domain, token) |
| |> put_req_header("content-type", "application/json") |
| |> put(url, %{ |
| shared_link: %{ |
| name: "My Shared Link" |
| } |
| }) |
| |> json_response(201) |
| |> assert_schema("SharedLink", spec()) |
|
|
| assert resp.shared_link.name == "My Shared Link" |
|
|
| assert resp.shared_link.href =~ |
| "http://localhost:8000/share/#{URI.encode_www_form(site.domain)}?auth=" |
| end |
|
|
| for special_name <- Plausible.Sites.shared_link_special_names() do |
| test "can create shared link with the reserved '#{special_name}' name", %{ |
| conn: conn, |
| site: site, |
| token: token |
| } do |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :create) |
|
|
| resp = |
| authenticate(conn, site.domain, token) |
| |> put_req_header("content-type", "application/json") |
| |> put(url, %{ |
| shared_link: %{ |
| name: unquote(special_name) |
| } |
| }) |
| |> json_response(201) |
| |> assert_schema("SharedLink", spec()) |
|
|
| assert resp.shared_link.name == unquote(special_name) |
|
|
| assert resp.shared_link.href =~ |
| "http://localhost:8000/share/#{URI.encode_www_form(site.domain)}?auth=" |
| end |
| end |
| end |
|
|
| describe "get /shared_links" do |
| test "returns an empty shared link list if there's none", %{ |
| conn: conn, |
| token: token, |
| site: site |
| } do |
| url = Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :index) |
|
|
| resp = |
| conn |
| |> authenticate(site.domain, token) |
| |> get(url) |
| |> json_response(200) |
| |> assert_schema("SharedLink.ListResponse", spec()) |
|
|
| assert resp.shared_links == [] |
| assert resp.meta.pagination.has_next_page == false |
| assert resp.meta.pagination.has_prev_page == false |
| assert resp.meta.pagination.links == %{} |
| end |
|
|
| test "returns a shared links list with pagination", %{ |
| conn: conn, |
| token: token, |
| site: site |
| } do |
| for i <- 1..5 do |
| insert(:shared_link, site: site, name: "Shared Link #{i}") |
| end |
|
|
| url = |
| Routes.plugins_api_shared_links_url(PlausibleWeb.Endpoint, :index, limit: 2) |
|
|
| initial_conn = authenticate(conn, site.domain, token) |
|
|
| page1 = |
| initial_conn |
| |> get(url) |
| |> json_response(200) |
| |> assert_schema("SharedLink.ListResponse", spec()) |
|
|
| assert [%{shared_link: %{name: "Shared Link 5"}}, %{shared_link: %{name: "Shared Link 4"}}] = |
| page1.shared_links |
|
|
| assert page1.meta.pagination.has_next_page == true |
| assert page1.meta.pagination.has_prev_page == false |
| assert page1.meta.pagination.links.next |
| refute page1.meta.pagination.links[:prev] |
|
|
| page2 = |
| initial_conn |
| |> get(page1.meta.pagination.links.next.url) |
| |> json_response(200) |
| |> assert_schema("SharedLink.ListResponse", spec()) |
|
|
| assert [%{shared_link: %{name: "Shared Link 3"}}, %{shared_link: %{name: "Shared Link 2"}}] = |
| page2.shared_links |
|
|
| assert page2.meta.pagination.has_next_page == true |
| assert page2.meta.pagination.has_prev_page == true |
| assert page2.meta.pagination.links.next |
| assert page2.meta.pagination.links.prev |
|
|
| assert ^page1 = |
| initial_conn |
| |> get(page2.meta.pagination.links.prev.url) |
| |> json_response(200) |
| |> assert_schema("SharedLink.ListResponse", spec()) |
| end |
| end |
| end |
|
|