Refactor Mobilizon.Federation.ActivityPub and add typespecs

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2021-09-28 19:40:37 +02:00
parent 41f086e2c9
commit b5d9b82bdd
125 changed files with 2497 additions and 1673 deletions

View File

@@ -9,6 +9,7 @@ defmodule Mobilizon.Web.AuthController do
plug(Ueberauth)
@spec request(Plug.Conn.t(), map()) :: Plug.Conn.t()
def request(conn, %{"provider" => provider_name} = _params) do
case provider_config(provider_name) do
{:ok, provider_config} ->
@@ -20,6 +21,7 @@ defmodule Mobilizon.Web.AuthController do
end
end
@spec callback(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, any()}
def callback(
%{assigns: %{ueberauth_failure: fails}} = conn,
%{"provider" => provider} = _params
@@ -85,6 +87,7 @@ defmodule Mobilizon.Web.AuthController do
# Github only give public emails as part of the user profile,
# so we explicitely request all user emails and filter on the primary one
@spec email_from_ueberauth(Ueberauth.Auth.t()) :: String.t() | nil
defp email_from_ueberauth(%Ueberauth.Auth{
strategy: Ueberauth.Strategy.Github,
extra: %Ueberauth.Auth.Extra{raw_info: %{user: %{"emails" => emails}}}
@@ -100,6 +103,7 @@ defmodule Mobilizon.Web.AuthController do
defp email_from_ueberauth(_), do: nil
@spec provider_config(String.t()) :: {:ok, any()} | {:error, :not_supported | :unknown_error}
defp provider_config(provider_name) do
with ueberauth when is_list(ueberauth) <- Application.get_env(:ueberauth, Ueberauth),
providers when is_list(providers) <- Keyword.get(ueberauth, :providers),

View File

@@ -6,6 +6,7 @@ defmodule Mobilizon.Web.FallbackController do
"""
use Mobilizon.Web, :controller
@spec call(Plug.Conn.t(), {:error, :not_found}) :: Plug.Conn.t()
def call(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)

View File

@@ -7,6 +7,7 @@ defmodule Mobilizon.Web.FeedController do
action_fallback(Mobilizon.Web.FallbackController)
alias Mobilizon.Config
@spec instance(Plug.Conn.t(), map()) :: Plug.Conn.t()
def instance(conn, %{"format" => format}) do
if Config.get([:instance, :enable_instance_feeds], false) do
return_data(conn, format, "instance", Config.instance_name())
@@ -15,6 +16,7 @@ defmodule Mobilizon.Web.FeedController do
end
end
@spec actor(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
def actor(conn, %{"format" => format, "name" => name}) do
return_data(conn, format, "actor_" <> name, name)
end
@@ -23,14 +25,17 @@ defmodule Mobilizon.Web.FeedController do
{:error, :not_found}
end
@spec event(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
def event(conn, %{"uuid" => uuid, "format" => "ics"}) do
return_data(conn, "ics", "event_" <> uuid, "event")
end
@spec instance(Plug.Conn.t(), map()) :: Plug.Conn.t()
def event(_conn, _) do
{:error, :not_found}
end
@spec going(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
def going(conn, %{"token" => token, "format" => format}) do
return_data(conn, format, "token_" <> token, "events")
end
@@ -39,6 +44,8 @@ defmodule Mobilizon.Web.FeedController do
{:error, :not_found}
end
@spec return_data(Plug.Conn.t(), String.t(), String.t(), String.t()) ::
Plug.Conn.t() | {:error, :not_found}
defp return_data(conn, "atom", type, filename) do
case Cachex.fetch(:feed, type) do
{status, data} when status in [:commit, :ok] ->

View File

@@ -10,6 +10,7 @@ defmodule Mobilizon.Web.MediaProxyController do
alias Plug.Conn
# sobelow_skip ["XSS.SendResp"]
@spec remote(Plug.Conn.t(), map()) :: Plug.Conn.t()
def remote(conn, %{"sig" => sig64, "url" => url64}) do
with {_, true} <- {:enabled, MediaProxy.enabled?()},
{:ok, url} <- MediaProxy.decode_url(sig64, url64),
@@ -27,6 +28,7 @@ defmodule Mobilizon.Web.MediaProxyController do
end
end
@spec media_proxy_opts :: Keyword.t()
defp media_proxy_opts do
Config.get([:media_proxy, :proxy_opts], [])
end

View File

@@ -15,6 +15,7 @@ defmodule Mobilizon.Web.NodeInfoController do
@node_info_supported_versions ["2.0", "2.1"]
@node_info_schema_uri "http://nodeinfo.diaspora.software/ns/schema/"
@spec schemas(Plug.Conn.t(), any) :: Plug.Conn.t()
def schemas(conn, _params) do
links =
@node_info_supported_versions
@@ -31,6 +32,7 @@ defmodule Mobilizon.Web.NodeInfoController do
end
# Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.1/schema.json
@spec nodeinfo(Plug.Conn.t(), any()) :: Plug.Conn.t()
def nodeinfo(conn, %{"version" => version}) when version in @node_info_supported_versions do
response = %{
version: version,

View File

@@ -14,15 +14,26 @@ defmodule Mobilizon.Web.PageController do
plug(:put_layout, false)
action_fallback(Mobilizon.Web.FallbackController)
@spec my_events(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate my_events(conn, params), to: PageController, as: :index
@spec create_event(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate create_event(conn, params), to: PageController, as: :index
@spec list_events(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate list_events(conn, params), to: PageController, as: :index
@spec edit_event(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate edit_event(conn, params), to: PageController, as: :index
@spec moderation_report(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate moderation_report(conn, params), to: PageController, as: :index
@spec participation_email_confirmation(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate participation_email_confirmation(conn, params), to: PageController, as: :index
@spec user_email_validation(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate user_email_validation(conn, params), to: PageController, as: :index
@spec my_groups(Plug.Conn.t(), any) :: Plug.Conn.t()
defdelegate my_groups(conn, params), to: PageController, as: :index
@typep object_type ::
:actor | :event | :comment | :resource | :post | :discussion | :todo_list | :todo
@spec index(Plug.Conn.t(), any) :: Plug.Conn.t()
def index(conn, _params), do: render(conn, :index)
@@ -62,38 +73,45 @@ defmodule Mobilizon.Web.PageController do
render_or_error(conn, &checks?/3, status, :discussion, discussion)
end
def resources(conn, %{"name" => _name}) do
handle_collection_route(conn, :resources)
end
def posts(conn, %{"name" => _name}) do
handle_collection_route(conn, :posts)
end
def discussions(conn, %{"name" => _name}) do
handle_collection_route(conn, :discussions)
end
def events(conn, %{"name" => _name}) do
handle_collection_route(conn, :events)
end
def todos(conn, %{"name" => _name}) do
handle_collection_route(conn, :todos)
end
@spec todo_list(Plug.Conn.t(), map) :: {:error, :not_found} | Plug.Conn.t()
@spec todo_list(Plug.Conn.t(), map) :: Plug.Conn.t() | {:error, :not_found}
def todo_list(conn, %{"uuid" => uuid}) do
{status, todo_list} = Cache.get_todo_list_by_uuid_with_preload(uuid)
render_or_error(conn, &checks?/3, status, :todo_list, todo_list)
end
@spec todo(Plug.Conn.t(), map) :: {:error, :not_found} | Plug.Conn.t()
@spec todo(Plug.Conn.t(), map) :: Plug.Conn.t() | {:error, :not_found}
def todo(conn, %{"uuid" => uuid}) do
{status, todo} = Cache.get_todo_by_uuid_with_preload(uuid)
render_or_error(conn, &checks?/3, status, :todo, todo)
end
@typep collections :: :resources | :posts | :discussions | :events | :todos
@spec resources(Plug.Conn.t(), map()) :: Plug.Conn.t()
def resources(conn, %{"name" => _name}) do
handle_collection_route(conn, :resources)
end
@spec posts(Plug.Conn.t(), map()) :: Plug.Conn.t()
def posts(conn, %{"name" => _name}) do
handle_collection_route(conn, :posts)
end
@spec discussions(Plug.Conn.t(), map()) :: Plug.Conn.t()
def discussions(conn, %{"name" => _name}) do
handle_collection_route(conn, :discussions)
end
@spec events(Plug.Conn.t(), map()) :: Plug.Conn.t()
def events(conn, %{"name" => _name}) do
handle_collection_route(conn, :events)
end
@spec todos(Plug.Conn.t(), map()) :: Plug.Conn.t()
def todos(conn, %{"name" => _name}) do
handle_collection_route(conn, :todos)
end
@spec interact(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
def interact(conn, %{"uri" => uri}) do
case ActivityPub.fetch_object_from_url(uri) do
@@ -103,6 +121,7 @@ defmodule Mobilizon.Web.PageController do
end
end
@spec handle_collection_route(Plug.Conn.t(), collections()) :: Plug.Conn.t()
defp handle_collection_route(conn, collection) do
case get_format(conn) do
"html" ->
@@ -113,6 +132,8 @@ defmodule Mobilizon.Web.PageController do
end
end
@spec render_or_error(Plug.Conn.t(), function(), cache_status(), object_type(), any()) ::
Plug.Conn.t() | {:error, :not_found}
defp render_or_error(conn, check_fn, status, object_type, object) do
case check_fn.(conn, status, object) do
true ->
@@ -136,12 +157,17 @@ defmodule Mobilizon.Web.PageController do
end
end
@spec is_visible?(map) :: boolean()
defp is_visible?(%{visibility: v}), do: v in [:public, :unlisted]
defp is_visible?(%Tombstone{}), do: true
defp is_visible?(_), do: true
@spec ok_status?(cache_status) :: boolean()
defp ok_status?(status), do: status in [:ok, :commit]
@typep cache_status :: :ok | :commit | :ignore
@spec ok_status_and_is_visible?(Plug.Conn.t(), cache_status, map()) :: boolean()
defp ok_status_and_is_visible?(_conn, status, o),
do: ok_status?(status) and is_visible?(o)
@@ -158,9 +184,11 @@ defmodule Mobilizon.Web.PageController do
end
end
@spec is_local?(map()) :: boolean | :remote
defp is_local?(%{local: local}), do: if(local, do: true, else: :remote)
defp is_local?(_), do: false
@spec maybe_add_noindex_header(Plug.Conn.t(), map()) :: Plug.Conn.t()
defp maybe_add_noindex_header(conn, %{visibility: visibility})
when visibility != :public do
put_resp_header(conn, "x-robots-tag", "noindex")
@@ -168,6 +196,7 @@ defmodule Mobilizon.Web.PageController do
defp maybe_add_noindex_header(conn, _), do: conn
@spec is_person?(Actor.t()) :: boolean()
defp is_person?(%Actor{type: :Person}), do: true
defp is_person?(_), do: false
end

View File

@@ -17,6 +17,7 @@ defmodule Mobilizon.Web.WebFingerController do
@doc """
Provides /.well-known/host-meta
"""
@spec host_meta(Plug.Conn.t(), any()) :: Plug.Conn.t() | no_return
def host_meta(conn, _params) do
xml = WebFinger.host_meta()
@@ -28,6 +29,7 @@ defmodule Mobilizon.Web.WebFingerController do
@doc """
Provides /.well-known/webfinger
"""
@spec webfinger(Plug.Conn.t(), any()) :: Plug.Conn.t() | no_return
def webfinger(conn, %{"resource" => resource}) do
case WebFinger.webfinger(resource, "JSON") do
{:ok, response} -> json(conn, response)