Merge branch 'feature/788-separate-email-addresses' into 'develop'
authorkaniini <nenolod@gmail.com>
Tue, 16 Apr 2019 18:44:07 +0000 (18:44 +0000)
committerkaniini <nenolod@gmail.com>
Tue, 16 Apr 2019 18:44:07 +0000 (18:44 +0000)
Feature/788 separate email addresses

Closes #788

See merge request pleroma/pleroma!1040

27 files changed:
CHANGELOG.md [new file with mode: 0644]
Changelog.md [deleted file]
config/config.exs
docs/config.md
docs/config/custom_emoji.md
docs/installation/arch_linux_en.md
installation/pleroma.supervisord [new file with mode: 0644]
lib/pleroma/activity.ex
lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/activity_pub_controller.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/common_api/utils.ex
lib/pleroma/web/endpoint.ex
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/twitter_api/controllers/util_controller.ex
lib/pleroma/web/twitter_api/views/activity_view.ex
mix.exs
mix.lock
test/activity_test.exs
test/web/activity_pub/activity_pub_controller_test.exs
test/web/activity_pub/transmogrifier_test.exs
test/web/mastodon_api/mastodon_api_controller_test.exs
test/web/twitter_api/twitter_api_test.exs
test/web/twitter_api/util_controller_test.exs

diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..1d2ad33
--- /dev/null
@@ -0,0 +1,93 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+
+## [unreleased]
+### Added
+- LDAP authentication
+- External OAuth provider authentication
+- A [job queue](https://git.pleroma.social/pleroma/pleroma_job_queue) for federation, emails, web push, etc.
+- [Prometheus](https://prometheus.io/) metrics
+- Support for Mastodon's remote interaction
+- Federation: Support for reports
+- Configuration: `safe_dm_mentions` option
+- Configuration: `link_name` option
+- Configuration: `fetch_initial_posts` option
+- Pleroma API: User subscribtions
+- Admin API: Endpoints for listing/revoking invite tokens
+- Admin API: Endpoints for making users follow/unfollow each other
+- Mastodon API: [Scheduled statuses](https://docs.joinmastodon.org/api/rest/scheduled-statuses/)
+- Mastodon API: `/api/v1/notifications/destroy_multiple` (glitch-soc extension)
+- Mastodon API: [Reports](https://docs.joinmastodon.org/api/rest/reports/)
+- ActivityPub C2S: OAuth endpoints
+
+### Changed
+- **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer
+- Enforcement of OAuth scopes
+- Add multiple use/time expiring invite token
+- Restyled OAuth pages to fit with Pleroma's default theme
+- Link/mention/hashtag detection is now handled by [auto_linker](https://git.pleroma.social/pleroma/auto_linker)
+- NodeInfo: Return `safe_dm_mentions` feature flag
+- Federation: Expand the audience of delete activities to all recipients of the deleted object
+- Federation: Removed `inReplyToStatusId` from objects
+- Configuration: Dedupe enabled by default
+- Configuration: Added `extra_cookie_attrs` for setting non-standard cookie attributes. Defaults to ["SameSite=Lax"] so that remote follows work.
+- Pleroma API: Support for emoji tags in `/api/pleroma/emoji` resulting in a breaking API change
+- Mastodon API: Support for `exclude_types`, `limit` and `min_id` in `/api/v1/notifications`
+- Mastodon API: Add `languages` and `registrations` to `/api/v1/instance`
+- Mastodon API: Provide plaintext versions of cw/content in the Status entity
+- Mastodon API: Add `pleroma.conversation_id` field to the Status entity
+- Mastodon API: Add `pleroma.tags`, `pleroma.relationship{}`, `pleroma.is_moderator`, `pleroma.is_admin`, `pleroma.confirmation_pending` fields to the User entity
+- Mastodon API: Add `pleroma.is_seen` to the Notification entity
+- Mastodon API: Add `pleroma.local` to the Status entity
+- Mastodon API: Add `preview` parameter to `POST /api/v1/statuses`
+- Mastodon API: Add `with_muted` parameter to timeline endpoints
+- Mastodon API: Actual reblog hiding instead of a dummy
+- Mastodon API: Remove attachment limit in the Status entity
+- Deps: Updated Cowboy to 2.6
+- Deps: Updated Ecto to 3.0.7
+
+### Fixed
+- Followers counter not being updated when a follower is blocked
+- Deactivated users being able to request an access token
+- Limit on request body in rich media/relme parsers being ignored resulting in a possible memory leak
+- proper Twitter Card generation instead of a dummy
+- NodeInfo: Include admins in `staffAccounts`
+- ActivityPub: Crashing when requesting empty local user's outbox
+- Federation: Handling of objects without `summary` property
+- Federation: Add a language tag to activities as required by ActivityStreams 2.0
+- Federation: Do not federate avatar/banner if set to default allowing other servers/clients to use their defaults
+- Federation: Cope with missing or explicitly nulled address lists
+- Federation: Explicitly ensure activities addressed to `as:Public` become addressed to the followers collection
+- Federation: Better cope with actors which do not declare a followers collection and use `as:Public` with these semantics
+- MediaProxy: Parse name from content disposition headers even for non-whitelisted types
+- MediaProxy: S3 link encoding
+- Rich Media: Reject any data which cannot be explicitly encoded into JSON
+- Mastodon API: `/api/v1/favourites` serving only public activities
+- Mastodon API: Reblogs having `in_reply_to_id` - `null` even when they are replies
+- Mastodon API: Streaming API broadcasting wrong activity id
+- Mastodon API: 500 errors when requesting a card for a private conversation
+
+## [0.9.9999] - 2019-04-05
+### Security
+- Mastodon API: Fix content warnings skipping HTML sanitization
+
+## [0.9.999] - 2019-03-13
+Frontend changes only.
+### Added
+- Added floating action button for posting status on mobile
+### Changed
+- Changed user-settings icon to a pencil
+### Fixed
+- Keyboard shortcuts activating when typing a message
+- Gaps when scrolling down on a timeline after showing new
+
+## [0.9.99] - 2019-03-08
+### Changed
+- Update the frontend to the 0.9.99 tag
+### Fixed
+- Sign the date header in federation to fix Mastodon federation.
+
+## [0.9.9] - 2019-02-22
+This is our first stable release.
diff --git a/Changelog.md b/Changelog.md
deleted file mode 100644 (file)
index 1fddf41..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# Changelog
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
-
-## [unreleased]
-### Changed
-- Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer
index 2a067e146ecab442c0a43e42ab621dcad9c1389d..595e3505cdd8f8cf6bd3d66d2c0423be244af049 100644 (file)
@@ -1,3 +1,41 @@
+#                                 .i;;;;i.
+#                               iYcviii;vXY:
+#                             .YXi       .i1c.
+#                            .YC.     .    in7.
+#                           .vc.   ......   ;1c.
+#                           i7,   ..        .;1;
+#                          i7,   .. ...      .Y1i
+#                         ,7v     .6MMM@;     .YX,
+#                        .7;.   ..IMMMMMM1     :t7.
+#                       .;Y.     ;$MMMMMM9.     :tc.
+#                       vY.   .. .nMMM@MMU.      ;1v.
+#                      i7i   ...  .#MM@M@C. .....:71i
+#                     it:   ....   $MMM@9;.,i;;;i,;tti
+#                    :t7.  .....   0MMMWv.,iii:::,,;St.
+#                   .nC.   .....   IMMMQ..,::::::,.,czX.
+#                  .ct:   ....... .ZMMMI..,:::::::,,:76Y.
+#                  c2:   ......,i..Y$M@t..:::::::,,..inZY
+#                 vov   ......:ii..c$MBc..,,,,,,,,,,..iI9i
+#                i9Y   ......iii:..7@MA,..,,,,,,,,,....;AA:
+#               iIS.  ......:ii::..;@MI....,............;Ez.
+#              .I9.  ......:i::::...8M1..................C0z.
+#             .z9;  ......:i::::,.. .i:...................zWX.
+#             vbv  ......,i::::,,.      ................. :AQY
+#            c6Y.  .,...,::::,,..:t0@@QY. ................ :8bi
+#           :6S. ..,,...,:::,,,..EMMMMMMI. ............... .;bZ,
+#          :6o,  .,,,,..:::,,,..i#MMMMMM#v.................  YW2.
+#         .n8i ..,,,,,,,::,,,,.. tMMMMM@C:.................. .1Wn
+#         7Uc. .:::,,,,,::,,,,..   i1t;,..................... .UEi
+#         7C...::::::::::::,,,,..        ....................  vSi.
+#         ;1;...,,::::::,.........       ..................    Yz:
+#          v97,.........                                     .voC.
+#           izAotX7777777777777777777777777777777777777777Y7n92:
+#             .;CoIIIIIUAA666666699999ZZZZZZZZZZZZZZZZZZZZ6ov.
+#
+#                          !!! ATTENTION !!!
+# DO NOT EDIT THIS FILE! THIS FILE CONTAINS THE DEFAULT VALUES FOR THE CON-
+# FIGURATION! EDIT YOUR SECRET FILE (either prod.secret.exs, dev.secret.exs).
+#
 # This file is responsible for configuring your application
 # and its dependencies with the aid of the Mix.Config module.
 #
@@ -116,7 +154,10 @@ config :pleroma, Pleroma.Web.Endpoint,
   signing_salt: "CqaoopA2",
   render_errors: [view: Pleroma.Web.ErrorView, accepts: ~w(json)],
   pubsub: [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2],
-  secure_cookie_flag: true
+  secure_cookie_flag: true,
+  extra_cookie_attrs: [
+    "SameSite=Lax"
+  ]
 
 # Configures Elixir's Logger
 config :logger, :console,
index 66e68229da64d526eaa79f3d7704448ebfbd8a3f..d618c5ddee1aaca75583f904d0c0eea86560718a 100644 (file)
@@ -222,6 +222,8 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i
   - `scheme` - e.g `http`, `https`
   - `port`
   - `path`
+* `extra_cookie_attrs` - a list of `Key=Value` strings to be added as non-standard cookie attributes. Defaults to `["SameSite=Lax"]`. See the [SameSite article](https://www.owasp.org/index.php/SameSite) on OWASP for more info.
+
 
 
 **Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need
@@ -443,6 +445,8 @@ The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx.
 
 Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies.
 
+Note: make sure that `"SameSite=Lax"` is set in `extra_cookie_attrs` when you have this feature enabled. OAuth consumer mode will not work with `"SameSite=Strict"`
+
 * For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https://<your_host>/oauth/twitter/callback
 
 * For Facebook, [register an app](https://developers.facebook.com/apps), configure callback URL to https://<your_host>/oauth/facebook/callback, enable Facebook Login service at https://developers.facebook.com/apps/<app_id>/fb-login/settings/
index 419a7d0e2366f05127a7376a8a28600372c4eca6..5ce9865a27ba940e0ff5412c427dd46449f1e5f8 100644 (file)
@@ -20,7 +20,7 @@ The files should be PNG (APNG is okay with `.png` for `image/png` Content-type)
 
 ## Emoji tags (groups)
 
-Default tags are set in `config.exs`.
+Default tags are set in `config.exs`. To set your own tags, copy the structure to your secrets file (`prod.secret.exs` or `dev.secret.exs`) and edit it.
 ```elixir
 config :pleroma, :emoji,
   shortcode_globs: ["/emoji/custom/**/*.png"],
index 4b3bbbbb0338ee7fe5549b7b94b6d7cb7246ffb7..2b040cfbc0f3a99cf4beb6461bd18fe2d50d28a5 100644 (file)
@@ -7,7 +7,6 @@ This guide will assume that you have administrative rights, either as root or a
 
 * `postgresql`
 * `elixir`
-* `erlang-unixodbc`
 * `git`
 * `base-devel`
 
@@ -27,7 +26,7 @@ sudo pacman -Syu
 * Install some of the above mentioned programs:
 
 ```shell
-sudo pacman -S git base-devel elixir erlang-unixodbc
+sudo pacman -S git base-devel elixir
 ```
 
 ### Install PostgreSQL
diff --git a/installation/pleroma.supervisord b/installation/pleroma.supervisord
new file mode 100644 (file)
index 0000000..19efffd
--- /dev/null
@@ -0,0 +1,21 @@
+; Assumes pleroma is installed in /home/pleroma/pleroma and running as the pleroma user
+; Also assumes mix is in /usr/bin, this might differ on BSDs or niche Linux distros
+; Logs into /home/pleroma/logs
+[program:pleroma]
+command=/usr/bin/mix phx.server
+directory=/home/pleroma/pleroma
+autostart=true
+autorestart=true
+user=pleroma
+environment =
+  MIX_ENV=prod,
+  HOME=/home/pleroma,
+  USER=pleroma,
+  PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/pleroma/bin:%(ENV_PATH)s",
+  PWD=/home/pleroma/pleroma
+stdout_logfile=/home/pleroma/logs/stdout.log
+stdout_logfile_maxbytes=50MB
+stdout_logfile_backups=10
+stderr_logfile=/home/pleroma/logs/stderr.log
+stderr_logfile_maxbytes=50MB
+stderr_logfile_backups=10
\ No newline at end of file
index ab8861b277b7683660e6ca031dd8f69db664522c..e6507e5ca011b342b8a656c6ce20e1476332eaaa 100644 (file)
@@ -246,20 +246,22 @@ defmodule Pleroma.Activity do
     |> Repo.all()
   end
 
-  def increase_replies_count(id) do
-    Activity
-    |> where(id: ^id)
-    |> update([a],
-      set: [
-        data:
-          fragment(
-            """
-            jsonb_set(?, '{object, repliesCount}',
-              (coalesce((?->'object'->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true)
-            """,
-            a.data,
-            a.data
-          )
+  def increase_replies_count(nil), do: nil
+
+  def increase_replies_count(object_ap_id) do
+    from(a in create_by_object_ap_id(object_ap_id),
+      update: [
+        set: [
+          data:
+            fragment(
+              """
+              jsonb_set(?, '{object, repliesCount}',
+                (coalesce((?->'object'->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true)
+              """,
+              a.data,
+              a.data
+            )
+        ]
       ]
     )
     |> Repo.update_all([])
@@ -269,20 +271,22 @@ defmodule Pleroma.Activity do
     end
   end
 
-  def decrease_replies_count(id) do
-    Activity
-    |> where(id: ^id)
-    |> update([a],
-      set: [
-        data:
-          fragment(
-            """
-            jsonb_set(?, '{object, repliesCount}',
-              (greatest(0, (?->'object'->>'repliesCount')::int - 1))::varchar::jsonb, true)
-            """,
-            a.data,
-            a.data
-          )
+  def decrease_replies_count(nil), do: nil
+
+  def decrease_replies_count(object_ap_id) do
+    from(a in create_by_object_ap_id(object_ap_id),
+      update: [
+        set: [
+          data:
+            fragment(
+              """
+              jsonb_set(?, '{object, repliesCount}',
+                (greatest(0, (?->'object'->>'repliesCount')::int - 1))::varchar::jsonb, true)
+              """,
+              a.data,
+              a.data
+            )
+        ]
       ]
     )
     |> Repo.update_all([])
index 4a41a15c77eba6893602518a1f94bbd9fea8cf7b..78eb29ddd8839dc73bee3dac5905cb63ebf59030 100644 (file)
@@ -281,6 +281,8 @@ defmodule Pleroma.User do
       user
       |> Pleroma.Emails.UserEmail.account_confirmation_email()
       |> Pleroma.Emails.Mailer.deliver_async()
+
+      {:ok, :enqueued}
     else
       {:ok, :noop}
     end
index 89fee2d9fade7b65983c80bba3b0e36ddb97ba90..54dd4097c755ab99b798a8f11b41915d95d43228 100644 (file)
@@ -91,12 +91,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   end
 
   def increase_replies_count_if_reply(%{
-        "object" =>
-          %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object,
+        "object" => %{"inReplyTo" => reply_ap_id} = object,
         "type" => "Create"
       }) do
     if is_public?(object) do
-      Activity.increase_replies_count(reply_status_id)
+      Activity.increase_replies_count(reply_ap_id)
       Object.increase_replies_count(reply_ap_id)
     end
   end
@@ -104,10 +103,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   def increase_replies_count_if_reply(_create_data), do: :noop
 
   def decrease_replies_count_if_reply(%Object{
-        data: %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object
+        data: %{"inReplyTo" => reply_ap_id} = object
       }) do
     if is_public?(object) do
-      Activity.decrease_replies_count(reply_status_id)
+      Activity.decrease_replies_count(reply_ap_id)
       Object.decrease_replies_count(reply_ap_id)
     end
   end
index 7091d6927fa3373c3f72a7924ef3825473939fd8..3331ebebd3b67406c5ec4e4a57797dd33a62eca5 100644 (file)
@@ -153,9 +153,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
   end
 
   def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
-    with %User{} = user <- User.get_cached_by_nickname(nickname),
-         true <- Utils.recipient_in_message(user.ap_id, params),
-         params <- Utils.maybe_splice_recipient(user.ap_id, params) do
+    with %User{} = recipient <- User.get_cached_by_nickname(nickname),
+         %User{} = actor <- User.get_or_fetch_by_ap_id(params["actor"]),
+         true <- Utils.recipient_in_message(recipient, actor, params),
+         params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do
       Federator.incoming_ap_doc(params)
       json(conn, "ok")
     end
index 49ea732041e7dbadd76514f6693f76e05866b9a6..39cd319212c415b265282dd12ae766907139c5f6 100644 (file)
@@ -225,12 +225,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
     case fetch_obj_helper(in_reply_to_id) do
       {:ok, replied_object} ->
-        with %Activity{} = activity <-
+        with %Activity{} = _activity <-
                Activity.get_create_by_object_ap_id(replied_object.data["id"]) do
           object
           |> Map.put("inReplyTo", replied_object.data["id"])
           |> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id)
-          |> Map.put("inReplyToStatusId", activity.id)
           |> Map.put("conversation", replied_object.data["context"] || object["conversation"])
           |> Map.put("context", replied_object.data["context"] || object["conversation"])
         else
index 0b53f71c3acc25471a9c531a0e9edfdb138e9475..ccc9da7c667dc03c39a984d164007aad0d6495da 100644 (file)
@@ -52,7 +52,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
   defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll
   defp recipient_in_collection(_, _), do: false
 
-  def recipient_in_message(ap_id, params) do
+  def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params) do
     cond do
       recipient_in_collection(ap_id, params["to"]) ->
         true
@@ -71,6 +71,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do
       !params["to"] && !params["cc"] && !params["bto"] && !params["bcc"] ->
         true
 
+      # if the message is sent from somebody the user is following, then assume it
+      # is addressed to the recipient
+      User.following?(recipient, actor) ->
+        true
+
       true ->
         false
     end
index 58a561a40fd8a2a8932432b830a9c2c274c5c27b..185292878b6e94f72ee9b5fbeb4730f63185c8b5 100644 (file)
@@ -228,7 +228,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
     if inReplyTo do
       object
       |> Map.put("inReplyTo", inReplyTo.data["object"]["id"])
-      |> Map.put("inReplyToStatusId", inReplyTo.id)
     else
       object
     end
index 1633477c365dd8aa2649b515d6a55d3a507ecc08..7f939991d970a080ff98075a43e38c9a92d2bfc2 100644 (file)
@@ -58,14 +58,9 @@ defmodule Pleroma.Web.Endpoint do
       do: "__Host-pleroma_key",
       else: "pleroma_key"
 
-  same_site =
-    if Pleroma.Config.oauth_consumer_enabled?() do
-      # Note: "SameSite=Strict" prevents sign in with external OAuth provider
-      #   (there would be no cookies during callback request from OAuth provider)
-      "SameSite=Lax"
-    else
-      "SameSite=Strict"
-    end
+  extra =
+    Pleroma.Config.get([__MODULE__, :extra_cookie_attrs])
+    |> Enum.join(";")
 
   # The session will be stored in the cookie and signed,
   # this means its contents can be read but not tampered with.
@@ -77,7 +72,7 @@ defmodule Pleroma.Web.Endpoint do
     signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]},
     http_only: true,
     secure: secure_cookies,
-    extra: same_site
+    extra: extra
   )
 
   # Note: the plug and its configuration is compile-time this can't be upstreamed yet
index e0a090659ee26e484b6fb487523fad97c641b9a0..63fadce3811ceea8a681860888d49ad8f8f4cb8d 100644 (file)
@@ -815,13 +815,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
-    with %User{} = followed <- User.get_by_id(id),
+    with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)},
+         {_, true} <- {:followed, follower.id != followed.id},
          false <- User.following?(follower, followed),
          {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
       conn
       |> put_view(AccountView)
       |> render("relationship.json", %{user: follower, target: followed})
     else
+      {:followed, _} ->
+        {:error, :not_found}
+
       true ->
         followed = User.get_cached_by_id(id)
 
@@ -843,12 +847,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
-    with %User{} = followed <- User.get_by_nickname(uri),
+    with {_, %User{} = followed} <- {:followed, User.get_cached_by_nickname(uri)},
+         {_, true} <- {:followed, follower.id != followed.id},
          {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
       conn
       |> put_view(AccountView)
       |> render("account.json", %{user: followed, for: follower})
     else
+      {:followed, _} ->
+        {:error, :not_found}
+
       {:error, message} ->
         conn
         |> put_resp_content_type("application/json")
@@ -857,11 +865,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
-    with %User{} = followed <- User.get_by_id(id),
+    with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)},
+         {_, true} <- {:followed, follower.id != followed.id},
          {:ok, follower} <- CommonAPI.unfollow(follower, followed) do
       conn
       |> put_view(AccountView)
       |> render("relationship.json", %{user: follower, target: followed})
+    else
+      {:followed, _} ->
+        {:error, :not_found}
+
+      error ->
+        error
     end
   end
 
index bdc33186ea70b2f48338294d0b01f0444566a68a..a9f607aa5dd8b38d8da006471cc847eb18bf50c6 100644 (file)
@@ -54,6 +54,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
 
   defp get_context_id(_), do: nil
 
+  defp reblogged?(activity, user) do
+    object = activity.data["object"] || %{}
+    present?(user && user.ap_id in (object["announcements"] || []))
+  end
+
   def render("index.json", opts) do
     replied_to_activities = get_replied_to_activities(opts.activities)
 
@@ -72,8 +77,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
     user = get_user(activity.data["actor"])
     created_at = Utils.to_masto_date(activity.data["published"])
 
-    reblogged = Activity.get_create_by_object_ap_id(object)
-    reblogged = render("status.json", Map.put(opts, :activity, reblogged))
+    reblogged_activity = Activity.get_create_by_object_ap_id(object)
+    reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity))
 
     mentions =
       activity.recipients
@@ -94,7 +99,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       reblogs_count: 0,
       replies_count: 0,
       favourites_count: 0,
-      reblogged: false,
+      reblogged: reblogged?(reblogged_activity, opts[:for]),
       favourited: false,
       bookmarked: false,
       muted: false,
@@ -132,7 +137,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       |> Enum.filter(& &1)
       |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end)
 
-    repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
     favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
     bookmarked = opts[:for] && object["id"] in opts[:for].bookmarks
 
@@ -203,7 +207,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       reblogs_count: announcement_count,
       replies_count: object["repliesCount"] || 0,
       favourites_count: like_count,
-      reblogged: present?(repeated),
+      reblogged: reblogged?(activity, opts[:for]),
       favourited: present?(favorited),
       bookmarked: present?(bookmarked),
       muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user),
index d066d35f5c129b0463b9a094506c0f24b9553a63..ed45ca73574fc62b407ff0429f08beb3f88c107f 100644 (file)
@@ -304,7 +304,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   end
 
   def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
-    with followed_identifiers <- String.split(list),
+    with lines <- String.split(list, "\n"),
+         followed_identifiers <-
+           Enum.map(lines, fn line ->
+             String.split(line, ",") |> List.first()
+           end)
+           |> List.delete("Account address"),
          {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do
       json(conn, "job started")
     end
index 433322eb8fbfce70632803921504a234d789b3b8..ecb2b437ba4cff9249284a7ca2da2d6ce6474975 100644 (file)
@@ -291,7 +291,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
       "is_local" => activity.local,
       "is_post_verb" => true,
       "created_at" => created_at,
-      "in_reply_to_status_id" => object["inReplyToStatusId"],
+      "in_reply_to_status_id" => reply_parent && reply_parent.id,
       "in_reply_to_screen_name" => reply_user && reply_user.nickname,
       "in_reply_to_profileurl" => User.profile_url(reply_user),
       "in_reply_to_ostatus_uri" => reply_user && reply_user.ap_id,
diff --git a/mix.exs b/mix.exs
index e0c870fa791f2661a339101f9358ad998fddebd3..15e18223908525955beb045af0ece96b8cee3de1 100644 (file)
--- a/mix.exs
+++ b/mix.exs
@@ -22,7 +22,7 @@ defmodule Pleroma.Mixfile do
       homepage_url: "https://pleroma.social/",
       docs: [
         logo: "priv/static/static/logo.png",
-        extras: ["README.md" | Path.wildcard("docs/**/*.md")],
+        extras: ["README.md", "CHANGELOG.md"] ++ Path.wildcard("docs/**/*.md"),
         groups_for_extras: [
           "Installation manuals": Path.wildcard("docs/installation/*.md"),
           Configuration: Path.wildcard("docs/config/*.md"),
@@ -90,7 +90,7 @@ defmodule Pleroma.Mixfile do
       {:crypt,
        git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"},
       {:cors_plug, "~> 1.5"},
-      {:ex_doc, "~> 0.19", only: :dev, runtime: false},
+      {:ex_doc, "~> 0.20.2", only: :dev, runtime: false},
       {:web_push_encryption, "~> 0.2.1"},
       {:swoosh, "~> 0.20"},
       {:gen_smtp, "~> 0.13"},
index e13fdcbd45ec0ba43a552db92e030ba8f6d75582..d494cc82dd4245d65ad6cc2110f9b7a1b375312f 100644 (file)
--- a/mix.lock
+++ b/mix.lock
   "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]},
   "db_connection": {:hex, :db_connection, "2.0.5", "ddb2ba6761a08b2bb9ca0e7d260e8f4dd39067426d835c24491a321b7f92a4da", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
   "decimal": {:hex, :decimal, "1.7.0", "30d6b52c88541f9a66637359ddf85016df9eb266170d53105f02e4a67e00c5aa", [:mix], [], "hexpm"},
-  "earmark": {:hex, :earmark, "1.3.0", "17f0c38eaafb4800f746b457313af4b2442a8c2405b49c645768680f900be603", [:mix], [], "hexpm"},
+  "earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm"},
   "ecto": {:hex, :ecto, "3.0.7", "44dda84ac6b17bbbdeb8ac5dfef08b7da253b37a453c34ab1a98de7f7e5fec7f", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
   "ecto_sql": {:hex, :ecto_sql, "3.0.5", "7e44172b4f7aca4469f38d7f6a3da394dbf43a1bcf0ca975e958cb957becd74e", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0.6", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
   "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"},
   "ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"},
   "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
-  "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
+  "ex_doc": {:hex, :ex_doc, "0.20.2", "1bd0dfb0304bade58beb77f20f21ee3558cc3c753743ae0ddbb0fd7ba2912331", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
   "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
   "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
   "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
@@ -35,8 +35,8 @@
   "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
   "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
   "jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
-  "makeup": {:hex, :makeup, "0.5.5", "9e08dfc45280c5684d771ad58159f718a7b5788596099bdfb0284597d368a882", [:mix], [{:nimble_parsec, "~> 0.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
-  "makeup_elixir": {:hex, :makeup_elixir, "0.10.0", "0f09c2ddf352887a956d84f8f7e702111122ca32fbbc84c2f0569b8b65cbf7fa", [:mix], [{:makeup, "~> 0.5.5", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
+  "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
+  "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
   "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm"},
   "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
   "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
@@ -44,7 +44,7 @@
   "mochiweb": {:hex, :mochiweb, "2.15.0", "e1daac474df07651e5d17cc1e642c4069c7850dc4508d3db7263a0651330aacc", [:rebar3], [], "hexpm"},
   "mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
   "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
-  "nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"},
+  "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
   "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
   "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"},
   "phoenix": {:hex, :phoenix, "1.4.1", "801f9d632808657f1f7c657c8bbe624caaf2ba91429123ebe3801598aea4c3d9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
index ad889f544830a5ed8463312461c5ee35bdd3b7af..dc9c56a21b1b25efe2145509eb8dee6d83817b16 100644 (file)
@@ -28,4 +28,18 @@ defmodule Pleroma.ActivityTest do
 
     assert activity == found_activity
   end
+
+  test "reply count" do
+    %{id: id, data: %{"object" => %{"id" => object_ap_id}}} = activity = insert(:note_activity)
+
+    replies_count = activity.data["object"]["repliesCount"] || 0
+    expected_increase = replies_count + 1
+    Activity.increase_replies_count(object_ap_id)
+    %{data: %{"object" => %{"repliesCount" => actual_increase}}} = Activity.get_by_id(id)
+    assert expected_increase == actual_increase
+    expected_decrease = expected_increase - 1
+    Activity.decrease_replies_count(object_ap_id)
+    %{data: %{"object" => %{"repliesCount" => actual_decrease}}} = Activity.get_by_id(id)
+    assert expected_decrease == actual_decrease
+  end
 end
index 8dd8e7e0ab0ca669e2225d0522d718e6072cdb11..7b1c60f15749508b5aec2983bef9bb48db55fbd2 100644 (file)
@@ -253,6 +253,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       assert Activity.get_by_ap_id(data["id"])
     end
 
+    test "it accepts messages from actors that are followed by the user", %{conn: conn} do
+      recipient = insert(:user)
+      actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
+
+      {:ok, recipient} = User.follow(recipient, actor)
+
+      data =
+        File.read!("test/fixtures/mastodon-post-activity.json")
+        |> Poison.decode!()
+
+      object =
+        data["object"]
+        |> Map.put("attributedTo", actor.ap_id)
+
+      data =
+        data
+        |> Map.put("actor", actor.ap_id)
+        |> Map.put("object", object)
+
+      conn =
+        conn
+        |> assign(:valid_signature, true)
+        |> put_req_header("content-type", "application/activity+json")
+        |> post("/users/#{recipient.nickname}/inbox", data)
+
+      assert "ok" == json_response(conn, 200)
+      :timer.sleep(500)
+      assert Activity.get_by_ap_id(data["id"])
+    end
+
     test "it rejects reads from other users", %{conn: conn} do
       user = insert(:user)
       otheruser = insert(:user)
index 47cffe257827d7853fb5b33570cfa249d21c5c4e..c857a7ec1e44372f7a818b4454b7cfd413598be7 100644 (file)
@@ -58,8 +58,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       assert returned_activity.data["object"]["inReplyToAtomUri"] ==
                "https://shitposter.club/notice/2827873"
-
-      assert returned_activity.data["object"]["inReplyToStatusId"] == activity.id
     end
 
     test "it works for incoming notices" do
index b3039a7b539b4b97ce35d6fec3f2c54e71d33362..f21cf677d1147bdf580ae9652bc8d71736337dd0 100644 (file)
@@ -342,7 +342,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     activity = Activity.get_by_id(id)
 
     assert activity.data["context"] == replied_to.data["context"]
-    assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
+    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
   end
 
   test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
@@ -1008,8 +1008,41 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
         |> assign(:user, user)
         |> post("/api/v1/statuses/#{activity.id}/reblog")
 
-      assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
-               json_response(conn, 200)
+      assert %{
+               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
+               "reblogged" => true
+             } = json_response(conn, 200)
+
+      assert to_string(activity.id) == id
+    end
+
+    test "reblogged status for another user", %{conn: conn} do
+      activity = insert(:note_activity)
+      user1 = insert(:user)
+      user2 = insert(:user)
+      user3 = insert(:user)
+      {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
+      {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
+
+      conn_res =
+        conn
+        |> assign(:user, user3)
+        |> get("/api/v1/statuses/#{reblog_activity1.id}")
+
+      assert %{
+               "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
+               "reblogged" => false
+             } = json_response(conn_res, 200)
+
+      conn_res =
+        conn
+        |> assign(:user, user2)
+        |> get("/api/v1/statuses/#{reblog_activity1.id}")
+
+      assert %{
+               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
+               "reblogged" => true
+             } = json_response(conn_res, 200)
 
       assert to_string(activity.id) == id
     end
@@ -1587,6 +1620,40 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     assert id == to_string(other_user.id)
   end
 
+  test "following / unfollowing errors" do
+    user = insert(:user)
+
+    conn =
+      build_conn()
+      |> assign(:user, user)
+
+    # self follow
+    conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
+    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
+
+    # self unfollow
+    user = User.get_cached_by_id(user.id)
+    conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
+    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
+
+    # self follow via uri
+    user = User.get_cached_by_id(user.id)
+    conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
+    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
+
+    # follow non existing user
+    conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
+    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
+
+    # follow non existing user via uri
+    conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
+    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
+
+    # unfollow non existing user
+    conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
+    assert %{"error" => "Record not found"} = json_response(conn_res, 404)
+  end
+
   test "muting / unmuting a user", %{conn: conn} do
     user = insert(:user)
     other_user = insert(:user)
@@ -2727,7 +2794,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     activity = Activity.get_by_id(id)
 
     assert activity.data["object"]["inReplyTo"] == replied_to.data["object"]["id"]
-    assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
+    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
 
     # Reblog from the third user
     conn2 =
index 3440ad268db0b6f474affabac465a3560945fc02..4c9ae2da8033e24c502537ad38ecbab652fc62af 100644 (file)
@@ -105,7 +105,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
              get_in(activity.data, ["object", "context"])
 
     assert get_in(reply.data, ["object", "inReplyTo"]) == get_in(activity.data, ["object", "id"])
-    assert get_in(reply.data, ["object", "inReplyToStatusId"]) == activity.id
+    assert Activity.get_in_reply_to_activity(reply).id == activity.id
   end
 
   test "Follow another user using user_id" do
index a4b3d651af1a2b5a491e90a3a1744d15431fec10..c58b49ea4cad746c484a1befe66e459bfe6bd7f6 100644 (file)
@@ -26,6 +26,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
       assert response == "job started"
     end
 
+    test "it imports new-style mastodon follow lists", %{conn: conn} do
+      user1 = insert(:user)
+      user2 = insert(:user)
+
+      response =
+        conn
+        |> assign(:user, user1)
+        |> post("/api/pleroma/follow_import", %{
+          "list" => "Account address,Show boosts\n#{user2.ap_id},true"
+        })
+        |> json_response(:ok)
+
+      assert response == "job started"
+    end
+
     test "requires 'follow' permission", %{conn: conn} do
       token1 = insert(:oauth_token, scopes: ["read", "write"])
       token2 = insert(:oauth_token, scopes: ["follow"])