2020-01-26 21:36:50 +01:00
|
|
|
defmodule Mobilizon.Web.PageController do
|
2018-01-14 17:56:50 +01:00
|
|
|
@moduledoc """
|
|
|
|
Controller to load our webapp
|
|
|
|
"""
|
2020-01-26 21:36:50 +01:00
|
|
|
use Mobilizon.Web, :controller
|
2019-09-17 23:39:26 +02:00
|
|
|
|
2020-10-12 12:16:36 +02:00
|
|
|
alias Mobilizon.Actors.Actor
|
2020-07-09 17:24:28 +02:00
|
|
|
alias Mobilizon.Discussions.Comment
|
2020-02-18 08:57:00 +01:00
|
|
|
alias Mobilizon.Events.Event
|
2019-12-20 13:04:34 +01:00
|
|
|
alias Mobilizon.Federation.ActivityPub
|
|
|
|
alias Mobilizon.Tombstone
|
2020-08-12 16:05:34 +02:00
|
|
|
alias Mobilizon.Web.{ActivityPubController, Cache, PageController}
|
2018-01-13 23:33:03 +01:00
|
|
|
|
2019-07-04 17:34:59 +02:00
|
|
|
plug(:put_layout, false)
|
2020-01-26 21:36:50 +01:00
|
|
|
action_fallback(Mobilizon.Web.FallbackController)
|
2017-12-08 09:58:14 +01:00
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec my_events(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate my_events(conn, params), to: PageController, as: :index
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec create_event(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate create_event(conn, params), to: PageController, as: :index
|
2023-12-11 00:30:39 +01:00
|
|
|
@spec calendar(Plug.Conn.t(), any) :: Plug.Conn.t()
|
|
|
|
defdelegate calendar(conn, params), to: PageController, as: :index
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec list_events(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate list_events(conn, params), to: PageController, as: :index
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec edit_event(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate edit_event(conn, params), to: PageController, as: :index
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec moderation_report(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate moderation_report(conn, params), to: PageController, as: :index
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec participation_email_confirmation(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate participation_email_confirmation(conn, params), to: PageController, as: :index
|
2023-12-01 09:52:28 +01:00
|
|
|
@spec participation_email_cancellation(Plug.Conn.t(), any) :: Plug.Conn.t()
|
|
|
|
defdelegate participation_email_cancellation(conn, params), to: PageController, as: :index
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec user_email_validation(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate user_email_validation(conn, params), to: PageController, as: :index
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec my_groups(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2020-08-12 16:05:34 +02:00
|
|
|
defdelegate my_groups(conn, params), to: PageController, as: :index
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@typep object_type ::
|
|
|
|
:actor | :event | :comment | :resource | :post | :discussion | :todo_list | :todo
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
@spec index(Plug.Conn.t(), any) :: Plug.Conn.t()
|
2019-05-02 13:04:21 +02:00
|
|
|
def index(conn, _params), do: render(conn, :index)
|
2019-03-04 17:20:18 +01:00
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
@spec actor(Plug.Conn.t(), map) :: {:error, :not_found} | Plug.Conn.t()
|
2019-03-04 17:20:18 +01:00
|
|
|
def actor(conn, %{"name" => name}) do
|
2020-08-14 11:32:23 +02:00
|
|
|
{status, actor} = Cache.get_actor_by_name(name)
|
2020-10-12 12:16:36 +02:00
|
|
|
render_or_error(conn, &checks?/3, status, :actor, actor)
|
2019-03-04 17:20:18 +01:00
|
|
|
end
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
@spec event(Plug.Conn.t(), map) :: {:error, :not_found} | Plug.Conn.t()
|
2019-03-04 17:20:18 +01:00
|
|
|
def event(conn, %{"uuid" => uuid}) do
|
2019-09-17 23:39:26 +02:00
|
|
|
{status, event} = Cache.get_public_event_by_uuid_with_preload(uuid)
|
2019-12-20 13:04:34 +01:00
|
|
|
render_or_error(conn, &checks?/3, status, :event, event)
|
2019-03-04 17:20:18 +01:00
|
|
|
end
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
@spec comment(Plug.Conn.t(), map) :: {:error, :not_found} | Plug.Conn.t()
|
2019-03-04 17:20:18 +01:00
|
|
|
def comment(conn, %{"uuid" => uuid}) do
|
2019-09-17 23:39:26 +02:00
|
|
|
{status, comment} = Cache.get_comment_by_uuid_with_preload(uuid)
|
2019-12-20 13:04:34 +01:00
|
|
|
render_or_error(conn, &checks?/3, status, :comment, comment)
|
|
|
|
end
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
@spec resource(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
|
|
|
|
def resource(conn, %{"uuid" => uuid}) do
|
|
|
|
{status, resource} = Cache.get_resource_by_uuid_with_preload(uuid)
|
|
|
|
render_or_error(conn, &checks?/3, status, :resource, resource)
|
|
|
|
end
|
|
|
|
|
2020-07-09 17:24:28 +02:00
|
|
|
@spec post(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
|
|
|
|
def post(conn, %{"slug" => slug}) do
|
|
|
|
{status, post} = Cache.get_post_by_slug_with_preload(slug)
|
|
|
|
render_or_error(conn, &checks?/3, status, :post, post)
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec discussion(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
|
|
|
|
def discussion(conn, %{"slug" => slug}) do
|
|
|
|
{status, discussion} = Cache.get_discussion_by_slug_with_preload(slug)
|
|
|
|
render_or_error(conn, &checks?/3, status, :discussion, discussion)
|
|
|
|
end
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@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) :: 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
|
|
|
|
|
2023-10-17 16:41:31 +02:00
|
|
|
@spec conversation(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
|
|
|
|
def conversation(conn, %{"id" => slug}) do
|
|
|
|
{status, conversation} = Cache.get_conversation_by_id_with_preload(slug)
|
|
|
|
render_or_error(conn, &checks?/3, status, :conversation, conversation)
|
|
|
|
end
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@typep collections :: :resources | :posts | :discussions | :events | :todos
|
|
|
|
|
|
|
|
@spec resources(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
2020-02-18 08:57:00 +01:00
|
|
|
def resources(conn, %{"name" => _name}) do
|
2020-07-09 17:24:28 +02:00
|
|
|
handle_collection_route(conn, :resources)
|
|
|
|
end
|
2020-02-18 08:57:00 +01:00
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec posts(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
2020-07-09 17:24:28 +02:00
|
|
|
def posts(conn, %{"name" => _name}) do
|
|
|
|
handle_collection_route(conn, :posts)
|
|
|
|
end
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec discussions(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
2020-07-09 17:24:28 +02:00
|
|
|
def discussions(conn, %{"name" => _name}) do
|
|
|
|
handle_collection_route(conn, :discussions)
|
|
|
|
end
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec events(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
2020-07-09 17:24:28 +02:00
|
|
|
def events(conn, %{"name" => _name}) do
|
|
|
|
handle_collection_route(conn, :events)
|
|
|
|
end
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec todos(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
2020-07-09 17:24:28 +02:00
|
|
|
def todos(conn, %{"name" => _name}) do
|
|
|
|
handle_collection_route(conn, :todos)
|
2020-02-18 08:57:00 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
@spec interact(Plug.Conn.t(), map()) :: Plug.Conn.t() | {:error, :not_found}
|
2019-12-20 13:04:34 +01:00
|
|
|
def interact(conn, %{"uri" => uri}) do
|
|
|
|
case ActivityPub.fetch_object_from_url(uri) do
|
|
|
|
{:ok, %Event{uuid: uuid}} -> redirect(conn, to: "/events/#{uuid}")
|
|
|
|
{:ok, %Comment{uuid: uuid}} -> redirect(conn, to: "/comments/#{uuid}")
|
|
|
|
_ -> {:error, :not_found}
|
|
|
|
end
|
2019-05-02 13:04:21 +02:00
|
|
|
end
|
2019-03-04 17:20:18 +01:00
|
|
|
|
2023-02-15 19:31:23 +01:00
|
|
|
@spec authorize(Plug.Conn.t(), any) :: Plug.Conn.t()
|
|
|
|
def authorize(conn, _params), do: render(conn, :index)
|
|
|
|
|
2023-02-21 14:50:09 +01:00
|
|
|
@spec auth_device(Plug.Conn.t(), any) :: Plug.Conn.t()
|
|
|
|
def auth_device(conn, _params), do: render(conn, :index)
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec handle_collection_route(Plug.Conn.t(), collections()) :: Plug.Conn.t()
|
2020-07-09 17:24:28 +02:00
|
|
|
defp handle_collection_route(conn, collection) do
|
|
|
|
case get_format(conn) do
|
|
|
|
"html" ->
|
|
|
|
render(conn, :index)
|
|
|
|
|
|
|
|
"activity-json" ->
|
|
|
|
ActivityPubController.call(conn, collection)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec render_or_error(Plug.Conn.t(), function(), cache_status(), object_type(), any()) ::
|
|
|
|
Plug.Conn.t() | {:error, :not_found}
|
2019-05-02 13:04:21 +02:00
|
|
|
defp render_or_error(conn, check_fn, status, object_type, object) do
|
2019-12-20 13:04:34 +01:00
|
|
|
case check_fn.(conn, status, object) do
|
|
|
|
true ->
|
|
|
|
case object do
|
|
|
|
%Tombstone{} ->
|
|
|
|
conn
|
|
|
|
|> put_status(:gone)
|
2022-11-22 11:32:31 +01:00
|
|
|
|> maybe_add_content_type_header()
|
2019-12-20 13:04:34 +01:00
|
|
|
|> render(object_type, object: object)
|
|
|
|
|
|
|
|
_ ->
|
2020-09-02 09:24:22 +02:00
|
|
|
conn
|
|
|
|
|> maybe_add_noindex_header(object)
|
2022-11-22 11:32:31 +01:00
|
|
|
|> maybe_add_content_type_header()
|
2020-09-02 09:24:22 +02:00
|
|
|
|> render(object_type, object: object)
|
2019-12-20 13:04:34 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
:remote ->
|
|
|
|
redirect(conn, external: object.url)
|
|
|
|
|
|
|
|
false ->
|
|
|
|
{:error, :not_found}
|
2019-03-04 17:20:18 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec is_visible?(map) :: boolean()
|
2019-05-02 13:04:21 +02:00
|
|
|
defp is_visible?(%{visibility: v}), do: v in [:public, :unlisted]
|
2019-12-20 13:04:34 +01:00
|
|
|
defp is_visible?(%Tombstone{}), do: true
|
2020-02-18 08:57:00 +01:00
|
|
|
defp is_visible?(_), do: true
|
2019-05-02 13:04:21 +02:00
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec ok_status?(cache_status) :: boolean()
|
2019-05-02 13:04:21 +02:00
|
|
|
defp ok_status?(status), do: status in [:ok, :commit]
|
2019-12-20 13:04:34 +01:00
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@typep cache_status :: :ok | :commit | :ignore
|
|
|
|
|
|
|
|
@spec ok_status_and_is_visible?(Plug.Conn.t(), cache_status, map()) :: boolean()
|
2019-12-20 13:04:34 +01:00
|
|
|
defp ok_status_and_is_visible?(_conn, status, o),
|
|
|
|
do: ok_status?(status) and is_visible?(o)
|
|
|
|
|
|
|
|
defp checks?(conn, status, o) do
|
2020-10-12 12:16:36 +02:00
|
|
|
cond do
|
|
|
|
ok_status_and_is_visible?(conn, status, o) ->
|
|
|
|
if is_local?(o) == :remote && get_format(conn) == "activity-json", do: :remote, else: true
|
|
|
|
|
|
|
|
is_person?(o) && get_format(conn) == "activity-json" ->
|
|
|
|
true
|
|
|
|
|
|
|
|
true ->
|
|
|
|
false
|
2019-12-20 13:04:34 +01:00
|
|
|
end
|
|
|
|
end
|
2019-05-02 13:04:21 +02:00
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec is_local?(map()) :: boolean | :remote
|
2020-02-18 08:57:00 +01:00
|
|
|
defp is_local?(%{local: local}), do: if(local, do: true, else: :remote)
|
|
|
|
defp is_local?(_), do: false
|
2020-09-02 09:24:22 +02:00
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec maybe_add_noindex_header(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
2020-09-02 10:00:39 +02:00
|
|
|
defp maybe_add_noindex_header(conn, %{visibility: visibility})
|
2020-09-02 09:24:22 +02:00
|
|
|
when visibility != :public do
|
|
|
|
put_resp_header(conn, "x-robots-tag", "noindex")
|
|
|
|
end
|
|
|
|
|
|
|
|
defp maybe_add_noindex_header(conn, _), do: conn
|
2020-10-12 12:16:36 +02:00
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec is_person?(Actor.t()) :: boolean()
|
2020-10-12 12:16:36 +02:00
|
|
|
defp is_person?(%Actor{type: :Person}), do: true
|
|
|
|
defp is_person?(_), do: false
|
2022-11-22 11:32:31 +01:00
|
|
|
|
|
|
|
defp maybe_add_content_type_header(conn) do
|
|
|
|
case get_format(conn) do
|
|
|
|
"html" ->
|
|
|
|
conn
|
|
|
|
|
|
|
|
"activity-json" ->
|
|
|
|
put_resp_content_type(conn, "application/activity+json")
|
|
|
|
end
|
|
|
|
end
|
2017-12-08 09:58:14 +01:00
|
|
|
end
|