Merge branch 'captcha' into 'develop'
[akkoma] / lib / pleroma / web / mastodon_api / views / status_view.ex
index cdae2de7abf9f9b3a73d3313b298a1a55aa155f3..477ab3b5fbe10b5442139fb631cb97e4ee7d8196 100644 (file)
@@ -1,17 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
 defmodule Pleroma.Web.MastodonAPI.StatusView do
   use Pleroma.Web, :view
-  alias Pleroma.Web.MastodonAPI.{AccountView, StatusView}
-  alias Pleroma.{User, Activity}
+
+  alias Pleroma.Activity
+  alias Pleroma.HTML
+  alias Pleroma.Repo
+  alias Pleroma.User
   alias Pleroma.Web.CommonAPI.Utils
   alias Pleroma.Web.MediaProxy
-  alias Pleroma.Repo
+  alias Pleroma.Web.MastodonAPI.AccountView
+  alias Pleroma.Web.MastodonAPI.StatusView
 
   # TODO: Add cached version.
   defp get_replied_to_activities(activities) do
     activities
     |> Enum.map(fn
-      %{data: %{"type" => "Create", "object" => %{"inReplyTo" => inReplyTo}}} ->
-        inReplyTo != "" && inReplyTo
+      %{data: %{"type" => "Create", "object" => %{"inReplyTo" => in_reply_to}}} ->
+        in_reply_to != "" && in_reply_to
 
       _ ->
         nil
@@ -27,12 +35,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
   def render("index.json", opts) do
     replied_to_activities = get_replied_to_activities(opts.activities)
 
-    render_many(
-      opts.activities,
+    opts.activities
+    |> render_many(
       StatusView,
       "status.json",
       Map.put(opts, :replied_to_activities, replied_to_activities)
     )
+    |> Enum.filter(fn x -> not is_nil(x) end)
   end
 
   def render(
@@ -59,9 +68,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       in_reply_to_id: nil,
       in_reply_to_account_id: nil,
       reblog: reblogged,
-      content: reblogged[:content],
+      content: reblogged[:content] || "",
       created_at: created_at,
       reblogs_count: 0,
+      replies_count: 0,
       favourites_count: 0,
       reblogged: false,
       favourited: false,
@@ -69,9 +79,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       sensitive: false,
       spoiler_text: "",
       visibility: "public",
-      media_attachments: [],
+      media_attachments: reblogged[:media_attachments] || [],
       mentions: mentions,
-      tags: [],
+      tags: reblogged[:tags] || [],
       application: %{
         name: "Web",
         website: nil
@@ -100,7 +110,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
     favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
 
     attachment_data = object["attachment"] || []
-    attachment_data = attachment_data ++ if object["type"] == "Video", do: [object], else: []
     attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
 
     created_at = Utils.to_masto_date(object["published"])
@@ -108,17 +117,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
     reply_to = get_reply_to(activity, opts)
     reply_to_user = reply_to && User.get_cached_by_ap_id(reply_to.data["actor"])
 
-    emojis =
-      (activity.data["object"]["emoji"] || [])
-      |> Enum.map(fn {name, url} ->
-        name = HtmlSanitizeEx.strip_tags(name)
-
-        url =
-          HtmlSanitizeEx.strip_tags(url)
-          |> MediaProxy.url()
-
-        %{shortcode: name, url: url, static_url: url, visible_in_picker: false}
-      end)
+    content =
+      object
+      |> render_content()
+      |> HTML.get_cached_scrubbed_html_for_object(User.html_filter_policy(opts[:for]), activity)
 
     %{
       id: to_string(activity.id),
@@ -128,33 +130,37 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       in_reply_to_id: reply_to && to_string(reply_to.id),
       in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
       reblog: nil,
-      content: render_content(object),
+      content: content,
       created_at: created_at,
       reblogs_count: announcement_count,
+      replies_count: 0,
       favourites_count: like_count,
-      reblogged: !!repeated,
-      favourited: !!favorited,
+      reblogged: present?(repeated),
+      favourited: present?(favorited),
       muted: false,
       sensitive: sensitive,
       spoiler_text: object["summary"] || "",
       visibility: get_visibility(object),
       media_attachments: attachments |> Enum.take(4),
       mentions: mentions,
-      # fix,
-      tags: [],
+      tags: build_tags(tags),
       application: %{
         name: "Web",
         website: nil
       },
       language: nil,
-      emojis: emojis
+      emojis: build_emojis(activity.data["object"]["emoji"])
     }
   end
 
+  def render("status.json", _) do
+    nil
+  end
+
   def render("attachment.json", %{attachment: attachment}) do
     [attachment_url | _] = attachment["url"]
-    media_type = attachment_url["mediaType"] || attachment_url["mimeType"]
-    href = attachment_url["href"]
+    media_type = attachment_url["mediaType"] || attachment_url["mimeType"] || "image"
+    href = attachment_url["href"] |> MediaProxy.url()
 
     type =
       cond do
@@ -168,9 +174,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
 
     %{
       id: to_string(attachment["id"] || hash_id),
-      url: MediaProxy.url(href),
+      url: href,
       remote_url: href,
-      preview_url: MediaProxy.url(href),
+      preview_url: href,
       text_url: href,
       type: type,
       description: attachment["name"]
@@ -212,32 +218,77 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
   end
 
   def render_content(%{"type" => "Video"} = object) do
-    name = object["name"]
-
-    content =
-      if !!name and name != "" do
-        "<p><a href=\"#{object["id"]}\">#{name}</a></p>#{object["content"]}"
-      else
-        object["content"]
-      end
+    with name when not is_nil(name) and name != "" <- object["name"] do
+      "<p><a href=\"#{object["id"]}\">#{name}</a></p>#{object["content"]}"
+    else
+      _ -> object["content"] || ""
+    end
+  end
 
-    HtmlSanitizeEx.basic_html(content)
+  def render_content(%{"type" => object_type} = object)
+      when object_type in ["Article", "Page"] do
+    with summary when not is_nil(summary) and summary != "" <- object["name"],
+         url when is_bitstring(url) <- object["url"] do
+      "<p><a href=\"#{url}\">#{summary}</a></p>#{object["content"]}"
+    else
+      _ -> object["content"] || ""
+    end
   end
 
-  def render_content(%{"type" => "Article"} = object) do
-    summary = object["name"]
+  def render_content(object), do: object["content"] || ""
 
-    content =
-      if !!summary and summary != "" do
-        "<p><a href=\"#{object["url"]}\">#{summary}</a></p>#{object["content"]}"
-      else
-        object["content"]
-      end
+  @doc """
+  Builds a dictionary tags.
+
+  ## Examples
+
+  iex> Pleroma.Web.MastodonAPI.StatusView.build_tags(["fediverse", "nextcloud"])
+  [{"name": "fediverse", "url": "/tag/fediverse"},
+   {"name": "nextcloud", "url": "/tag/nextcloud"}]
+
+  """
+  @spec build_tags(list(any())) :: list(map())
+  def build_tags(object_tags) when is_list(object_tags) do
+    object_tags = for tag when is_binary(tag) <- object_tags, do: tag
 
-    HtmlSanitizeEx.basic_html(content)
+    Enum.reduce(object_tags, [], fn tag, tags ->
+      tags ++ [%{name: tag, url: "/tag/#{tag}"}]
+    end)
   end
 
-  def render_content(object) do
-    HtmlSanitizeEx.basic_html(object["content"])
+  def build_tags(_), do: []
+
+  @doc """
+  Builds list emojis.
+
+  Arguments: `nil` or list tuple of name and url.
+
+  Returns list emojis.
+
+  ## Examples
+
+  iex> Pleroma.Web.MastodonAPI.StatusView.build_emojis([{"2hu", "corndog.png"}])
+  [%{shortcode: "2hu", static_url: "corndog.png", url: "corndog.png", visible_in_picker: false}]
+
+  """
+  @spec build_emojis(nil | list(tuple())) :: list(map())
+  def build_emojis(nil), do: []
+
+  def build_emojis(emojis) do
+    emojis
+    |> Enum.map(fn {name, url} ->
+      name = HTML.strip_tags(name)
+
+      url =
+        url
+        |> HTML.strip_tags()
+        |> MediaProxy.url()
+
+      %{shortcode: name, url: url, static_url: url, visible_in_picker: false}
+    end)
   end
+
+  defp present?(nil), do: false
+  defp present?(false), do: false
+  defp present?(_), do: true
 end