Fix activity_representer to work with User.get_or_fetch returning tuple.
[akkoma] / lib / pleroma / web / ostatus / ostatus_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.OStatus.OStatusController do
6 use Pleroma.Web, :controller
7
8 alias Fallback.RedirectController
9 alias Pleroma.Activity
10 alias Pleroma.Object
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPubController
13 alias Pleroma.Web.ActivityPub.ObjectView
14 alias Pleroma.Web.ActivityPub.Visibility
15 alias Pleroma.Web.Endpoint
16 alias Pleroma.Web.Metadata.PlayerView
17 alias Pleroma.Web.Router
18
19 plug(
20 Pleroma.Plugs.RateLimiter,
21 {:ap_routes, params: ["uuid"]} when action in [:object, :activity]
22 )
23
24 plug(
25 Pleroma.Plugs.SetFormatPlug
26 when action in [:object, :activity, :notice]
27 )
28
29 action_fallback(:errors)
30
31 def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
32 when format in ["json", "activity+json"] do
33 ActivityPubController.call(conn, :object)
34 end
35
36 def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
37 with id <- o_status_url(conn, :object, uuid),
38 {_, %Activity{} = activity} <-
39 {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
40 {_, true} <- {:public?, Visibility.is_public?(activity)},
41 %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
42 case format do
43 "html" -> redirect(conn, to: "/notice/#{activity.id}")
44 _ -> represent_activity(conn, nil, activity, user)
45 end
46 else
47 reason when reason in [{:public?, false}, {:activity, nil}] ->
48 {:error, :not_found}
49
50 e ->
51 e
52 end
53 end
54
55 def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
56 when format in ["json", "activity+json"] do
57 ActivityPubController.call(conn, :activity)
58 end
59
60 def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
61 with id <- o_status_url(conn, :activity, uuid),
62 {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
63 {_, true} <- {:public?, Visibility.is_public?(activity)},
64 %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
65 case format do
66 "html" -> redirect(conn, to: "/notice/#{activity.id}")
67 _ -> represent_activity(conn, format, activity, user)
68 end
69 else
70 reason when reason in [{:public?, false}, {:activity, nil}] ->
71 {:error, :not_found}
72
73 e ->
74 e
75 end
76 end
77
78 def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
79 if Pleroma.Config.get([:instance, :static_fe], false) do
80 Pleroma.Web.StaticFE.StaticFEController.show(conn, %{"notice_id" => id})
81 else
82 with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
83 {_, true} <- {:public?, Visibility.is_public?(activity)},
84 %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
85 cond do
86 format == "html" && activity.data["type"] == "Create" ->
87 %Object{} = object = Object.normalize(activity)
88
89 RedirectController.redirector_with_meta(
90 conn,
91 %{
92 activity_id: activity.id,
93 object: object,
94 url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
95 user: user
96 }
97 )
98
99 format == "html" ->
100 RedirectController.redirector(conn, nil)
101
102 true ->
103 represent_activity(conn, format, activity, user)
104 end
105 else
106 reason when reason in [{:public?, false}, {:activity, nil}] ->
107 conn
108 |> put_status(404)
109 |> RedirectController.redirector(nil, 404)
110
111 e ->
112 e
113 end
114 end
115 end
116
117 # Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
118 def notice_player(conn, %{"id" => id}) do
119 with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
120 true <- Visibility.is_public?(activity),
121 %Object{} = object <- Object.normalize(activity),
122 %{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
123 true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
124 conn
125 |> put_layout(:metadata_player)
126 |> put_resp_header("x-frame-options", "ALLOW")
127 |> put_resp_header(
128 "content-security-policy",
129 "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
130 )
131 |> put_view(PlayerView)
132 |> render("player.html", url)
133 else
134 _error ->
135 conn
136 |> put_status(404)
137 |> RedirectController.redirector(nil, 404)
138 end
139 end
140
141 defp represent_activity(
142 conn,
143 "activity+json",
144 %Activity{data: %{"type" => "Create"}} = activity,
145 _user
146 ) do
147 object = Object.normalize(activity)
148
149 conn
150 |> put_resp_header("content-type", "application/activity+json")
151 |> put_view(ObjectView)
152 |> render("object.json", %{object: object})
153 end
154
155 defp represent_activity(_conn, _, _, _) do
156 {:error, :not_found}
157 end
158
159 def errors(conn, {:error, :not_found}) do
160 render_error(conn, :not_found, "Not found")
161 end
162
163 def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
164
165 def errors(conn, _) do
166 render_error(conn, :internal_server_error, "Something went wrong")
167 end
168 end