Merge branch 'feature/object-normalization' into 'develop'
authorlambda <pleromagit@rogerbraun.net>
Thu, 12 Jul 2018 16:48:15 +0000 (16:48 +0000)
committerlambda <pleromagit@rogerbraun.net>
Thu, 12 Jul 2018 16:48:15 +0000 (16:48 +0000)
object normalization

See merge request pleroma/pleroma!238

16 files changed:
config/config.exs
lib/pleroma/formatter.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/activity_pub/views/user_view.ex
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
lib/pleroma/web/twitter_api/representers/activity_representer.ex
lib/pleroma/web/twitter_api/twitter_api_controller.ex
lib/pleroma/web/twitter_api/views/activity_view.ex
lib/pleroma/web/twitter_api/views/user_view.ex
test/web/activity_pub/views/user_view_test.exs
test/web/twitter_api/representers/activity_representer_test.exs
test/web/twitter_api/views/activity_view_test.exs
test/web/twitter_api/views/user_view_test.exs

index cf6cbaa9d140697be8017cdd63b4e1a77bb08250..0616fe4fb19d48a5ad288749c42af5a0fb64e49e 100644 (file)
@@ -12,6 +12,8 @@ config :pleroma, Pleroma.Repo, types: Pleroma.PostgresTypes
 
 config :pleroma, Pleroma.Upload, uploads: "uploads"
 
+config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"]
+
 # Configures the endpoint
 config :pleroma, Pleroma.Web.Endpoint,
   url: [host: "localhost"],
index df7ffbc4165bdc45bcce98401b04cf72e1aafb9e..0aaf215383c6168f32fe4b4e06a988a9e6f27f5a 100644 (file)
@@ -116,7 +116,28 @@ defmodule Pleroma.Formatter do
                       _ -> []
                     end)
 
-  @emoji @finmoji_with_filenames ++ @emoji_from_file
+  @emoji_from_globs (
+                      static_path = Path.join(:code.priv_dir(:pleroma), "static")
+
+                      globs =
+                        Application.get_env(:pleroma, :emoji, [])
+                        |> Keyword.get(:shortcode_globs, [])
+
+                      paths =
+                        Enum.map(globs, fn glob ->
+                          Path.join(static_path, glob)
+                          |> Path.wildcard()
+                        end)
+                        |> Enum.concat()
+
+                      Enum.map(paths, fn path ->
+                        shortcode = Path.basename(path, Path.extname(path))
+                        external_path = Path.join("/", Path.relative_to(path, static_path))
+                        {shortcode, external_path}
+                      end)
+                    )
+
+  @emoji @finmoji_with_filenames ++ @emoji_from_globs ++ @emoji_from_file
 
   def emojify(text, emoji \\ @emoji)
   def emojify(text, nil), do: text
index 9d7c64743a7b43571892b228700aa070115735c3..0d21661960d82b8ad01a262ddc2c3bfb813a4749 100644 (file)
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   """
   def fix_object(object) do
     object
-    |> Map.put("actor", object["attributedTo"])
+    |> fix_actor
     |> fix_attachments
     |> fix_context
     |> fix_in_reply_to
@@ -27,6 +27,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     |> fix_content_map
   end
 
+  def fix_actor(%{"attributedTo" => actor} = object) do
+    # attributedTo can be a list in the case of peertube or plume
+    actor =
+      if is_list(actor) do
+        Enum.at(actor, 0)
+      else
+        actor
+      end
+
+    object
+    |> Map.put("actor", actor)
+  end
+
   def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object)
       when not is_nil(in_reply_to_id) do
     case ActivityPub.fetch_object_from_id(in_reply_to_id) do
@@ -122,10 +135,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   # TODO: validate those with a Ecto scheme
   # - tags
   # - emoji
-  def handle_incoming(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
+  def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data)
+      when objtype in ["Article", "Note"] do
     with nil <- Activity.get_create_activity_by_object_ap_id(object["id"]),
          %User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do
-      object = fix_object(data["object"])
+      # prefer the activity's actor instead of attributedTo
+      object =
+        fix_object(data["object"])
+        |> Map.put("actor", data["actor"])
 
       params = %{
         to: data["to"],
index 64329b710080362bbf6b4c30e8903e8efda00ff0..8b41a3becbb26cad7af645d8bd6480316bd2a8c0 100644 (file)
@@ -128,7 +128,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
   Inserts a full object if it is contained in an activity.
   """
   def insert_full_object(%{"object" => %{"type" => type} = object_data})
-      when is_map(object_data) and type in ["Note"] do
+      when is_map(object_data) and type in ["Article", "Note"] do
     with {:ok, _} <- Object.create(object_data) do
       :ok
     end
index f4b2e0610ccd608d53b8d533192a7b63b6cc23a4..41bfe5048a886e9e3266620f73abe4e5c1a1af5d 100644 (file)
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
   def render("user.json", %{user: user}) do
     {:ok, user} = WebFinger.ensure_keys_present(user)
     {:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"])
-    public_key = :public_key.pem_entry_encode(:RSAPublicKey, public_key)
+    public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
     public_key = :public_key.pem_encode([public_key])
 
     %{
index 9d3f526c922b98a6d2329b2ddd10ebff3a232508..09e6b0b59ce22db8518a05a3eafbd0dd7e41c2d5 100644 (file)
@@ -873,7 +873,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
           },
           compose: %{
             me: "#{user.id}",
-            default_privacy: "public",
+            default_privacy: user.info["default_scope"] || "public",
             default_sensitive: false
           },
           media_attachments: %{
index 59898457b73aee226df473ccdbeb48961c7d155a..4c20581d6239440f3e52b2a12ca9ee23f44d7d48 100644 (file)
@@ -54,8 +54,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
     %{
       id: to_string(activity.id),
       uri: object,
-      # TODO: This might be wrong, check with mastodon.
-      url: nil,
+      url: object,
       account: AccountView.render("account.json", %{user: user}),
       in_reply_to_id: nil,
       in_reply_to_account_id: nil,
@@ -128,7 +127,7 @@ 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: HtmlSanitizeEx.basic_html(object["content"]),
+      content: render_content(object),
       created_at: created_at,
       reblogs_count: announcement_count,
       favourites_count: like_count,
@@ -207,4 +206,21 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
         "direct"
     end
   end
+
+  def render_content(%{"type" => "Article"} = object) do
+    summary = object["name"]
+
+    content =
+      if !!summary and summary != "" do
+        "<p><a href=\"#{object["url"]}\">#{summary}</a></p>#{object["content"]}"
+      else
+        object["content"]
+      end
+
+    HtmlSanitizeEx.basic_html(content)
+  end
+
+  def render_content(object) do
+    HtmlSanitizeEx.basic_html(object["content"])
+  end
 end
index aec77168a5c466ef5f91cf9351cf735c94d5963d..12aca4a10d12634c28467a3fbef7522825045b0d 100644 (file)
@@ -4,8 +4,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
   alias Pleroma.Stats
   alias Pleroma.Web
 
-  @instance Application.get_env(:pleroma, :instance)
-
   def schemas(conn, _params) do
     response = %{
       links: [
@@ -21,20 +19,22 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
 
   # Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.0/schema.json
   def nodeinfo(conn, %{"version" => "2.0"}) do
+    instance = Application.get_env(:pleroma, :instance)
+    media_proxy = Application.get_env(:pleroma, :media_proxy)
     stats = Stats.get_stats()
 
     response = %{
       version: "2.0",
       software: %{
         name: "pleroma",
-        version: Keyword.get(@instance, :version)
+        version: Keyword.get(instance, :version)
       },
       protocols: ["ostatus", "activitypub"],
       services: %{
         inbound: [],
         outbound: []
       },
-      openRegistrations: Keyword.get(@instance, :registrations_open),
+      openRegistrations: Keyword.get(instance, :registrations_open),
       usage: %{
         users: %{
           total: stats.user_count || 0
@@ -42,7 +42,8 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
         localPosts: stats.status_count || 0
       },
       metadata: %{
-        nodeName: Keyword.get(@instance, :name)
+        nodeName: Keyword.get(instance, :name),
+        mediaProxy: Keyword.get(media_proxy, :enabled)
       }
     }
 
index 57837205e08132f67efbf55b1dcc095a6a98c934..26bfb79af16d5e5b0d90cda5c9f69f3137d9db9a 100644 (file)
@@ -4,7 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
   use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter
   alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
   alias Pleroma.{Activity, User}
-  alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView}
+  alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView}
   alias Pleroma.Web.CommonAPI.Utils
   alias Pleroma.Formatter
 
@@ -164,14 +164,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
 
     tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags
 
-    summary = activity.data["object"]["summary"]
-
-    content =
-      if !!summary and summary != "" do
-        "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
-      else
-        content
-      end
+    {summary, content} = ActivityView.render_content(object)
 
     html =
       HtmlSanitizeEx.basic_html(content)
@@ -198,7 +191,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
       "tags" => tags,
       "activity_type" => "post",
       "possibly_sensitive" => possibly_sensitive,
-      "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object)
+      "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object),
+      "summary" => object["summary"]
     }
   end
 
index 8f5b3c786fa0a7287ffb998f1c91b1a1c95dc02d..65e67396b2284ebf54b572ae8c9f2856e48044e0 100644 (file)
@@ -431,6 +431,19 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
         user
       end
 
+    user =
+      if default_scope = params["default_scope"] do
+        with new_info <- Map.put(user.info, "default_scope", default_scope),
+             change <- User.info_changeset(user, %{info: new_info}),
+             {:ok, user} <- User.update_and_set_cache(change) do
+          user
+        else
+          _e -> user
+        end
+      else
+        user
+      end
+
     with changeset <- User.update_changeset(user, params),
          {:ok, user} <- User.update_and_set_cache(changeset) do
       CommonAPI.update(user)
index 62ce3b7b5d0d152c1558099f13ee270f63ed68c0..55b5287f5e2bb4e94cfcde2bdc7ea646a2009f00 100644 (file)
@@ -228,15 +228,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
 
     tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags
 
-    summary = activity.data["object"]["summary"]
-    content = object["content"]
-
-    content =
-      if !!summary and summary != "" do
-        "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
-      else
-        content
-      end
+    {summary, content} = render_content(object)
 
     html =
       HtmlSanitizeEx.basic_html(content)
@@ -263,7 +255,41 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
       "tags" => tags,
       "activity_type" => "post",
       "possibly_sensitive" => possibly_sensitive,
-      "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object)
+      "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object),
+      "summary" => summary
     }
   end
+
+  def render_content(%{"type" => "Note"} = object) do
+    summary = object["summary"]
+
+    content =
+      if !!summary and summary != "" do
+        "<p>#{summary}</p>#{object["content"]}"
+      else
+        object["content"]
+      end
+
+    {summary, content}
+  end
+
+  def render_content(%{"type" => "Article"} = object) do
+    summary = object["name"] || object["summary"]
+
+    content =
+      if !!summary and summary != "" do
+        "<p><a href=\"#{object["url"]}\">#{summary}</a></p>#{object["content"]}"
+      else
+        object["content"]
+      end
+
+    {summary, content}
+  end
+
+  def render_content(object) do
+    summary = object["summary"] || "Unhandled activity type: #{object["type"]}"
+    content = "<p>#{summary}</p>#{object["content"]}"
+
+    {summary, content}
+  end
 end
index 71100897373b88f88b1144fb2144e3657af60455..9c8460378cb200c5f35835ce64dc31bb09bb59fd 100644 (file)
@@ -52,7 +52,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
       "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
       "background_image" => image_url(user.info["background"]) |> MediaProxy.url(),
       "is_local" => user.local,
-      "locked" => !!user.info["locked"]
+      "locked" => !!user.info["locked"],
+      "default_scope" => user.info["default_scope"] || "public"
     }
 
     if assigns[:token] do
index 0c64e62c3416807d018df6d39f932d4f66aab522..7fc870e962753840ef6dca0fa70bd627491c00c6 100644 (file)
@@ -13,6 +13,6 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
     assert result["id"] == user.ap_id
     assert result["preferredUsername"] == user.nickname
 
-    assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN RSA PUBLIC KEY")
+    assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN PUBLIC KEY")
   end
 end
index 16c6e7b0d49f0551250b9fe380f8b422ff42909d..3f85e028ba87ff62f8bb8be6b9d7e5ebaf9370f4 100644 (file)
@@ -126,7 +126,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
     }
 
     expected_html =
-      "<span>2hu</span><br />alert('YAY')Some <img height='32px' width='32px' alt='2hu' title='2hu' src='corndog.png' /> content mentioning <a href=\"#{
+      "<p>2hu</p>alert('YAY')Some <img height='32px' width='32px' alt='2hu' title='2hu' src='corndog.png' /> content mentioning <a href=\"#{
         mentioned_user.ap_id
       }\">@shp</a>"
 
@@ -155,7 +155,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
       "activity_type" => "post",
       "possibly_sensitive" => true,
       "uri" => activity.data["object"]["id"],
-      "visibility" => "direct"
+      "visibility" => "direct",
+      "summary" => "2hu"
     }
 
     assert ActivityRepresenter.to_map(activity, %{
index 5b2a7466bd6011bb79257ffd749490146b2b8bf4..a101e4ae8b96c8f29c68ad654eb06274ddcf45e8 100644 (file)
@@ -48,7 +48,8 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
       "text" => "Hey @shp!",
       "uri" => activity.data["object"]["id"],
       "user" => UserView.render("show.json", %{user: user}),
-      "visibility" => "direct"
+      "visibility" => "direct",
+      "summary" => nil
     }
 
     assert result == expected
index eea743b32c093c7629c96ebab449e9134091d8f9..49f73c2fe1121de682a96137994f15806f1ba27d 100644 (file)
@@ -60,7 +60,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "cover_photo" => banner,
       "background_image" => nil,
       "is_local" => true,
-      "locked" => false
+      "locked" => false,
+      "default_scope" => "public"
     }
 
     assert represented == UserView.render("show.json", %{user: user})
@@ -96,7 +97,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "cover_photo" => banner,
       "background_image" => nil,
       "is_local" => true,
-      "locked" => false
+      "locked" => false,
+      "default_scope" => "public"
     }
 
     assert represented == UserView.render("show.json", %{user: user, for: follower})
@@ -133,7 +135,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "cover_photo" => banner,
       "background_image" => nil,
       "is_local" => true,
-      "locked" => false
+      "locked" => false,
+      "default_scope" => "public"
     }
 
     assert represented == UserView.render("show.json", %{user: follower, for: user})
@@ -177,7 +180,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "cover_photo" => banner,
       "background_image" => nil,
       "is_local" => true,
-      "locked" => false
+      "locked" => false,
+      "default_scope" => "public"
     }
 
     blocker = Repo.get(User, blocker.id)