analytics/lib/plausible_web/plugins/api/controllers/shared_links.ex
hq1 082ec91c63
OpenAPI: first pass on Plugins API - Shared Links (#3378)
* Update depenedencies: OpenAPISpex + cursor based pagination

* Update formatter config

* Add internal server error implementation

* Test errors

* Implement pagination interface

* Implement Plugins API module macros

* Implement Public API base URI

(to be used with path helpers once called from within
forwarded router's scope)

* Implement OpenAPI specs + schemas

* Implement Shared Links context module

* Add pagination and error views

* Add Shared Link view

* Implement Shared Link controller

* Expose SharedLink.t() spec

* Implement separate router for the Plugins API

* Update moduledocs

* Always wrap resource objects with `data`

* Update moduledoc

* Use https://github.com/open-api-spex/open_api_spex/pull/425

due to https://github.com/open-api-spex/open_api_spex/issues/92

* Rely on BASE_URL for swagger-ui server definition

* Fixup goals migration

* Migrate broken goals before deleting dupes

* Remove bypassing test rate limiting for which there's none anyway

* Move the context module under `Plausible.` namespace

* Bring back conn assignment to PluginsAPICase template

* Update test/plausible_web/plugins/api/controllers/shared_links_test.exs

Co-authored-by: Uku Taht <Uku.taht@gmail.com>

* Update renamed aliases

* Seed static token for development purposes

* Delegate Plugins API 500s to a familiar shape

* Simplify with statement

---------

Co-authored-by: Uku Taht <Uku.taht@gmail.com>
2023-10-02 11:18:49 +02:00

110 lines
3.3 KiB
Elixir

defmodule PlausibleWeb.Plugins.API.Controllers.SharedLinks do
@moduledoc """
Controller for the Shared Link resource under Plugins API
"""
use PlausibleWeb, :plugins_api_controller
operation(:index,
summary: "Retrieve Shared Links",
parameters: [
limit: [in: :query, type: :integer, description: "Maximum entries per page", example: 10],
after: [
in: :query,
type: :string,
description: "Cursor value to seek after - generated internally"
],
before: [
in: :query,
type: :string,
description: "Cursor value to seek before - generated internally"
]
],
responses: %{
ok: {"Shared Links response", "application/json", Schemas.SharedLink.ListResponse},
unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized}
}
)
@spec index(Plug.Conn.t(), %{}) :: Plug.Conn.t()
def index(conn, _params) do
{:ok, pagination} =
Context.SharedLinks.get_shared_links(conn.assigns.authorized_site, conn.query_params)
conn
|> put_view(Views.SharedLink)
|> render("index.json", %{pagination: pagination})
end
operation(:create,
summary: "Create Shared Link",
request_body: {"Shared Link params", "application/json", Schemas.SharedLink.CreateRequest},
responses: %{
created: {"Shared Link", "application/json", Schemas.SharedLink},
unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized},
unprocessable_entity:
{"Unprocessable entity", "application/json", Schemas.UnprocessableEntity}
}
)
@spec create(Plug.Conn.t(), map()) :: Plug.Conn.t()
def create(
%{
private: %{
open_api_spex: %{
body_params: %Schemas.SharedLink.CreateRequest{name: name, password: password}
}
}
} = conn,
_params
) do
site = conn.assigns.authorized_site
{:ok, shared_link} = Context.SharedLinks.get_or_create(site, name, password)
conn
|> put_view(Views.SharedLink)
|> put_status(:created)
|> put_resp_header("location", shared_links_url(base_uri(), :get, shared_link.id))
|> render("shared_link.json", shared_link: shared_link, authorized_site: site)
end
operation(:get,
summary: "Retrieve Shared Link by ID",
parameters: [
id: [
in: :path,
type: :integer,
description: "Shared Link ID",
example: 123,
required: true
]
],
responses: %{
created: {"Shared Link", "application/json", Schemas.SharedLink},
not_found: {"NotFound", "application/json", Schemas.NotFound},
unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized},
unprocessable_entity:
{"Unprocessable entity", "application/json", Schemas.UnprocessableEntity}
}
)
@spec get(Plug.Conn.t(), map()) :: Plug.Conn.t()
def get(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _params) do
site = conn.assigns.authorized_site
case Context.SharedLinks.get(site, id) do
nil ->
conn
|> put_view(Views.Error)
|> put_status(:not_found)
|> render("404.json")
shared_link ->
conn
|> put_view(Views.SharedLink)
|> put_status(:ok)
|> render("shared_link.json", shared_link: shared_link, authorized_site: site)
end
end
end