summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Felder <feld@FreeBSD.org>2020-07-02 09:57:57 -0500
committerMark Felder <feld@FreeBSD.org>2020-07-02 09:57:57 -0500
commit6b5563ed2cdb0bff95fbc42ba0e4687c8ed1311d (patch)
tree3dfb2172f49f7ca21f9adaf945897d869de8786d
parentf89390110b6b601fc505e63c3e36516d7ca96f5c (diff)
parent4c044f62258b33a95b8281e1eb42a5e0ce47d42d (diff)
Merge branch 'develop' into feature/1885-MRF-metadata
-rw-r--r--.gitlab/issue_templates/Bug.md2
-rw-r--r--CHANGELOG.md2
-rw-r--r--config/config.exs2
-rw-r--r--config/description.exs150
-rw-r--r--docs/API/differences_in_mastoapi_responses.md7
-rw-r--r--lib/pleroma/html.ex2
-rw-r--r--lib/pleroma/notification.ex1
-rw-r--r--lib/pleroma/object/fetcher.ex4
-rw-r--r--lib/pleroma/user.ex12
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex39
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex12
-rw-r--r--lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex5
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex20
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/block_validator.ex42
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex21
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex29
-rw-r--r--lib/pleroma/web/activity_pub/visibility.ex6
-rw-r--r--lib/pleroma/web/api_spec/cast_and_validate.ex2
-rw-r--r--lib/pleroma/web/api_spec/schemas/account.ex83
-rw-r--r--lib/pleroma/web/api_spec/schemas/status.ex4
-rw-r--r--lib/pleroma/web/common_api/common_api.ex7
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex3
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex5
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo.ex30
-rw-r--r--lib/pleroma/web/preload/instance.ex9
-rw-r--r--lib/pleroma/web/preload/status_net.ex11
-rw-r--r--lib/pleroma/web/preload/timelines.ex2
-rw-r--r--lib/pleroma/web/preload/user.ex11
-rw-r--r--lib/pleroma/web/streamer/streamer.ex1
-rw-r--r--lib/pleroma/web/views/masto_fe_view.ex2
-rw-r--r--mix.exs5
-rw-r--r--mix.lock4
-rw-r--r--priv/repo/migrations/20200630162024_rename_user_settings_col.exs11
-rw-r--r--test/fixtures/fetch_mocks/104410921027210069.json72
-rw-r--r--test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json59
-rw-r--r--test/fixtures/fetch_mocks/eal.json43
-rw-r--r--test/fixtures/fetch_mocks/tuxcrafting.json59
-rw-r--r--test/fixtures/preload_static/instance/panel.html1
-rw-r--r--test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json228
-rw-r--r--test/fixtures/tesla_mock/peertube.moe-vid.json188
-rw-r--r--test/html_test.exs14
-rw-r--r--test/notification_test.exs10
-rw-r--r--test/object/fetcher_test.exs40
-rw-r--r--test/user_test.exs25
-rw-r--r--test/web/activity_pub/activity_pub_test.exs48
-rw-r--r--test/web/activity_pub/mrf/anti_link_spam_policy_test.exs16
-rw-r--r--test/web/activity_pub/object_validator_test.exs27
-rw-r--r--test/web/activity_pub/side_effects_test.exs67
-rw-r--r--test/web/activity_pub/transmogrifier/block_handling_test.exs63
-rw-r--r--test/web/activity_pub/transmogrifier_test.exs50
-rw-r--r--test/web/activity_pub/utils_test.exs16
-rw-r--r--test/web/common_api/common_api_test.exs46
-rw-r--r--test/web/masto_fe_controller_test.exs2
-rw-r--r--test/web/mastodon_api/controllers/account_controller_test.exs1
-rw-r--r--test/web/mastodon_api/views/status_view_test.exs19
-rw-r--r--test/web/node_info_test.exs3
-rw-r--r--test/web/preload/instance_test.exs17
-rw-r--r--test/web/preload/status_net_test.exs5
-rw-r--r--test/web/preload/timeline_test.exs2
-rw-r--r--test/web/preload/user_test.exs14
-rw-r--r--test/web/streamer/streamer_test.exs12
61 files changed, 1363 insertions, 330 deletions
diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md
index 66fbc510e..9ce9b6918 100644
--- a/.gitlab/issue_templates/Bug.md
+++ b/.gitlab/issue_templates/Bug.md
@@ -14,7 +14,7 @@
* Pleroma version (could be found in the "Version" tab of settings in Pleroma-FE):
* Elixir version (`elixir -v` for from source installations, N/A for OTP):
* Operating system:
-* PostgreSQL version (`postgres -V`):
+* PostgreSQL version (`psql -V`):
### Bug description
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 71963d206..335d29195 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
<summary>API Changes</summary>
- **Breaking:** Emoji API: changed methods and renamed routes.
+- Streaming: Repeats of a user's posts will no longer be pushed to the user's stream.
</details>
<details>
@@ -51,6 +52,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
<details>
<summary>API Changes</summary>
+- Mastodon API: Add pleroma.parents_visible field to statuses.
- Mastodon API: Extended `/api/v1/instance`.
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
diff --git a/config/config.exs b/config/config.exs
index 5b1c576e7..9b550920c 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -437,8 +437,6 @@ config :pleroma, Pleroma.Web.Metadata,
config :pleroma, Pleroma.Web.Preload,
providers: [
Pleroma.Web.Preload.Providers.Instance,
- Pleroma.Web.Preload.Providers.User,
- Pleroma.Web.Preload.Providers.Timelines,
Pleroma.Web.Preload.Providers.StatusNet
]
diff --git a/config/description.exs b/config/description.exs
index e0c07bf78..39c6c5793 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -40,12 +40,13 @@ config :pleroma, :config_description, [
key: :link_name,
type: :boolean,
description:
- "If enabled, a name parameter will be added to the url of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`."
+ "If enabled, a name parameter will be added to the URL of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`."
},
%{
key: :base_url,
+ label: "Base URL",
type: :string,
- description: "Base url for the uploads, needed if you use CDN",
+ description: "Base URL for the uploads, needed if you use CDN",
suggestions: [
"https://cdn-host.com"
]
@@ -58,6 +59,7 @@ config :pleroma, :config_description, [
},
%{
key: :proxy_opts,
+ label: "Proxy Options",
type: :keyword,
description: "Options for Pleroma.ReverseProxy",
suggestions: [
@@ -85,6 +87,7 @@ config :pleroma, :config_description, [
},
%{
key: :http,
+ label: "HTTP",
type: :keyword,
description: "HTTP options",
children: [
@@ -481,6 +484,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :uri_schemes,
+ label: "URI Schemes",
type: :group,
description: "URI schemes related settings",
children: [
@@ -653,17 +657,17 @@ config :pleroma, :config_description, [
key: :invites_enabled,
type: :boolean,
description:
- "Enable user invitations for admins (depends on `registrations_open` being disabled)."
+ "Enable user invitations for admins (depends on `registrations_open` being disabled)"
},
%{
key: :account_activation_required,
type: :boolean,
- description: "Require users to confirm their emails before signing in."
+ description: "Require users to confirm their emails before signing in"
},
%{
key: :federating,
type: :boolean,
- description: "Enable federation with other instances."
+ description: "Enable federation with other instances"
},
%{
key: :federation_incoming_replies_max_depth,
@@ -681,7 +685,7 @@ config :pleroma, :config_description, [
label: "Fed. reachability timeout days",
type: :integer,
description:
- "Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.",
+ "Timeout (in days) of each external federation target being unreachable prior to pausing federating to it",
suggestions: [
7
]
@@ -803,6 +807,7 @@ config :pleroma, :config_description, [
},
%{
key: :safe_dm_mentions,
+ label: "Safe DM mentions",
type: :boolean,
description:
"If enabled, only mentions at the beginning of a post will be used to address people in direct messages." <>
@@ -842,7 +847,7 @@ config :pleroma, :config_description, [
%{
key: :skip_thread_containment,
type: :boolean,
- description: "Skip filtering out broken threads. Default: enabled"
+ description: "Skip filtering out broken threads. Default: enabled."
},
%{
key: :limit_to_local_content,
@@ -906,6 +911,7 @@ config :pleroma, :config_description, [
children: [
%{
key: :totp,
+ label: "TOTP settings",
type: :keyword,
description: "TOTP settings",
suggestions: [digits: 6, period: 30],
@@ -922,7 +928,7 @@ config :pleroma, :config_description, [
type: :integer,
suggestions: [30],
description:
- "a period for which the TOTP code will be valid, in seconds. Defaults to 30 seconds."
+ "A period for which the TOTP code will be valid, in seconds. Defaults to 30 seconds."
}
]
},
@@ -936,7 +942,7 @@ config :pleroma, :config_description, [
key: :number,
type: :integer,
suggestions: [5],
- description: "number of backup codes to generate."
+ description: "Number of backup codes to generate."
},
%{
key: :length,
@@ -976,6 +982,7 @@ config :pleroma, :config_description, [
group: :logger,
type: :group,
key: :ex_syslogger,
+ label: "ExSyslogger",
description: "ExSyslogger-related settings",
children: [
%{
@@ -994,7 +1001,7 @@ config :pleroma, :config_description, [
%{
key: :format,
type: :string,
- description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\".",
+ description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\"",
suggestions: ["$metadata[$level] $message"]
},
%{
@@ -1008,6 +1015,7 @@ config :pleroma, :config_description, [
group: :logger,
type: :group,
key: :console,
+ label: "Console Logger",
description: "Console logger settings",
children: [
%{
@@ -1019,7 +1027,7 @@ config :pleroma, :config_description, [
%{
key: :format,
type: :string,
- description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\".",
+ description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\"",
suggestions: ["$metadata[$level] $message"]
},
%{
@@ -1032,6 +1040,7 @@ config :pleroma, :config_description, [
%{
group: :quack,
type: :group,
+ label: "Quack Logger",
description: "Quack-related settings",
children: [
%{
@@ -1142,19 +1151,19 @@ config :pleroma, :config_description, [
key: :greentext,
label: "Greentext",
type: :boolean,
- description: "Enables green text on lines prefixed with the > character."
+ description: "Enables green text on lines prefixed with the > character"
},
%{
key: :hideFilteredStatuses,
label: "Hide Filtered Statuses",
type: :boolean,
- description: "Hides filtered statuses from timelines."
+ description: "Hides filtered statuses from timelines"
},
%{
key: :hideMutedPosts,
label: "Hide Muted Posts",
type: :boolean,
- description: "Hides muted statuses from timelines."
+ description: "Hides muted statuses from timelines"
},
%{
key: :hidePostStats,
@@ -1166,7 +1175,7 @@ config :pleroma, :config_description, [
key: :hideSitename,
label: "Hide Sitename",
type: :boolean,
- description: "Hides instance name from PleromaFE banner."
+ description: "Hides instance name from PleromaFE banner"
},
%{
key: :hideUserStats,
@@ -1211,14 +1220,14 @@ config :pleroma, :config_description, [
label: "NSFW Censor Image",
type: :string,
description:
- "URL of the image to use for hiding NSFW media attachments in the timeline.",
+ "URL of the image to use for hiding NSFW media attachments in the timeline",
suggestions: ["/static/img/nsfw.74818f9.png"]
},
%{
key: :postContentType,
label: "Post Content Type",
type: {:dropdown, :atom},
- description: "Default post formatting option.",
+ description: "Default post formatting option",
suggestions: ["text/plain", "text/html", "text/markdown", "text/bbcode"]
},
%{
@@ -1247,14 +1256,14 @@ config :pleroma, :config_description, [
key: :sidebarRight,
label: "Sidebar on Right",
type: :boolean,
- description: "Change alignment of sidebar and panels to the right."
+ description: "Change alignment of sidebar and panels to the right"
},
%{
key: :showFeaturesPanel,
label: "Show instance features panel",
type: :boolean,
description:
- "Enables panel displaying functionality of the instance on the About page."
+ "Enables panel displaying functionality of the instance on the About page"
},
%{
key: :showInstanceSpecificPanel,
@@ -1312,7 +1321,7 @@ config :pleroma, :config_description, [
key: :mascots,
type: {:keyword, :map},
description:
- "Keyword of mascots, each element must contain both an url and a mime_type key",
+ "Keyword of mascots, each element must contain both an URL and a mime_type key",
suggestions: [
pleroma_fox_tan: %{
url: "/images/pleroma-fox-tan-smol.png",
@@ -1336,7 +1345,7 @@ config :pleroma, :config_description, [
%{
key: :default_user_avatar,
type: :string,
- description: "URL of the default user avatar.",
+ description: "URL of the default user avatar",
suggestions: ["/images/avi.png"]
}
]
@@ -1346,7 +1355,7 @@ config :pleroma, :config_description, [
key: :manifest,
type: :group,
description:
- "This section describe PWA manifest instance-specific values. Currently this option relate only for MastoFE",
+ "This section describe PWA manifest instance-specific values. Currently this option relate only for MastoFE.",
children: [
%{
key: :icons,
@@ -1384,7 +1393,7 @@ config :pleroma, :config_description, [
group: :pleroma,
key: :mrf_simple,
tab: :mrf,
- label: "MRF simple",
+ label: "MRF Simple",
type: :group,
description: "Message Rewrite Facility",
children: [
@@ -1466,7 +1475,7 @@ config :pleroma, :config_description, [
group: :pleroma,
key: :mrf_subchain,
tab: :mrf,
- label: "MRF subchain",
+ label: "MRF Subchain",
type: :group,
description:
"This policy processes messages through an alternate pipeline when a given message matches certain criteria." <>
@@ -1490,7 +1499,7 @@ config :pleroma, :config_description, [
tab: :mrf,
description:
"MRF RejectNonPublic settings. RejectNonPublic drops posts with non-public visibility settings.",
- label: "MRF reject non public",
+ label: "MRF Reject Non Public",
type: :group,
children: [
%{
@@ -1510,7 +1519,7 @@ config :pleroma, :config_description, [
group: :pleroma,
key: :mrf_hellthread,
tab: :mrf,
- label: "MRF hellthread",
+ label: "MRF Hellthread",
type: :group,
description: "Block messages with too much mentions",
children: [
@@ -1535,7 +1544,7 @@ config :pleroma, :config_description, [
group: :pleroma,
key: :mrf_keyword,
tab: :mrf,
- label: "MRF keyword",
+ label: "MRF Keyword",
type: :group,
description: "Reject or Word-Replace messages with a keyword or regex",
children: [
@@ -1566,14 +1575,14 @@ config :pleroma, :config_description, [
group: :pleroma,
key: :mrf_mention,
tab: :mrf,
- label: "MRF mention",
+ label: "MRF Mention",
type: :group,
description: "Block messages which mention a user",
children: [
%{
key: :actors,
type: {:list, :string},
- description: "A list of actors for which any post mentioning them will be dropped.",
+ description: "A list of actors for which any post mentioning them will be dropped",
suggestions: ["actor1", "actor2"]
}
]
@@ -1582,7 +1591,7 @@ config :pleroma, :config_description, [
group: :pleroma,
key: :mrf_vocabulary,
tab: :mrf,
- label: "MRF vocabulary",
+ label: "MRF Vocabulary",
type: :group,
description: "Filter messages which belong to certain activity vocabularies",
children: [
@@ -1590,14 +1599,14 @@ config :pleroma, :config_description, [
key: :accept,
type: {:list, :string},
description:
- "A list of ActivityStreams terms to accept. If empty, all supported messages are accepted",
+ "A list of ActivityStreams terms to accept. If empty, all supported messages are accepted.",
suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
},
%{
key: :reject,
type: {:list, :string},
description:
- "A list of ActivityStreams terms to reject. If empty, no messages are rejected",
+ "A list of ActivityStreams terms to reject. If empty, no messages are rejected.",
suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
}
]
@@ -1627,6 +1636,7 @@ config :pleroma, :config_description, [
},
%{
key: :base_url,
+ label: "Base URL",
type: :string,
description:
"The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.",
@@ -1659,6 +1669,7 @@ config :pleroma, :config_description, [
},
%{
key: :proxy_opts,
+ label: "Proxy Options",
type: :keyword,
description: "Options for Pleroma.ReverseProxy",
suggestions: [
@@ -1686,6 +1697,7 @@ config :pleroma, :config_description, [
},
%{
key: :http,
+ label: "HTTP",
type: :keyword,
description: "HTTP options",
children: [
@@ -1781,6 +1793,7 @@ config :pleroma, :config_description, [
},
%{
key: :ip,
+ label: "IP",
type: :tuple,
description: "IP address to bind to",
suggestions: [{0, 0, 0, 0}]
@@ -1794,7 +1807,7 @@ config :pleroma, :config_description, [
%{
key: :dstport,
type: :integer,
- description: "Port advertised in urls (optional, defaults to port)",
+ description: "Port advertised in URLs (optional, defaults to port)",
suggestions: [9999]
}
]
@@ -1802,6 +1815,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :activitypub,
+ label: "ActivityPub",
type: :group,
description: "ActivityPub-related settings",
children: [
@@ -1824,7 +1838,7 @@ config :pleroma, :config_description, [
key: :note_replies_output_limit,
type: :integer,
description:
- "The number of Note replies' URIs to be included with outgoing federation (`5` to match Mastodon hardcoded value, `0` to disable the output)."
+ "The number of Note replies' URIs to be included with outgoing federation (`5` to match Mastodon hardcoded value, `0` to disable the output)"
},
%{
key: :follow_handshake_timeout,
@@ -1837,6 +1851,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :http_security,
+ label: "HTTP security",
type: :group,
description: "HTTP security settings",
children: [
@@ -1875,7 +1890,7 @@ config :pleroma, :config_description, [
key: :report_uri,
label: "Report URI",
type: :string,
- description: "Adds the specified url to report-uri and report-to group in CSP header",
+ description: "Adds the specified URL to report-uri and report-to group in CSP header",
suggestions: ["https://example.com/report-uri"]
}
]
@@ -1883,9 +1898,10 @@ config :pleroma, :config_description, [
%{
group: :web_push_encryption,
key: :vapid_details,
+ label: "Vapid Details",
type: :group,
description:
- "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it",
+ "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it.",
children: [
%{
key: :subject,
@@ -1952,6 +1968,7 @@ config :pleroma, :config_description, [
},
%{
group: :pleroma,
+ label: "Pleroma Admin Token",
type: :group,
description:
"Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the `admin_token` parameter",
@@ -1959,7 +1976,7 @@ config :pleroma, :config_description, [
%{
key: :admin_token,
type: :string,
- description: "Token",
+ description: "Admin token",
suggestions: ["We recommend a secure random string or UUID"]
}
]
@@ -2124,24 +2141,24 @@ config :pleroma, :config_description, [
key: :rich_media,
type: :group,
description:
- "If enabled the instance will parse metadata from attached links to generate link previews.",
+ "If enabled the instance will parse metadata from attached links to generate link previews",
children: [
%{
key: :enabled,
type: :boolean,
- description: "Enables RichMedia parsing of URLs."
+ description: "Enables RichMedia parsing of URLs"
},
%{
key: :ignore_hosts,
type: {:list, :string},
- description: "List of hosts which will be ignored by the metadata parser.",
+ description: "List of hosts which will be ignored by the metadata parser",
suggestions: ["accounts.google.com", "xss.website"]
},
%{
key: :ignore_tld,
label: "Ignore TLD",
type: {:list, :string},
- description: "List TLDs (top-level domains) which will ignore for parse metadata.",
+ description: "List TLDs (top-level domains) which will ignore for parse metadata",
suggestions: ["local", "localdomain", "lan"]
},
%{
@@ -2169,31 +2186,32 @@ config :pleroma, :config_description, [
%{
group: :auto_linker,
key: :opts,
+ label: "Auto Linker",
type: :group,
description: "Configuration for the auto_linker library",
children: [
%{
key: :class,
type: [:string, false],
- description: "Specify the class to be added to the generated link. Disable to clear",
+ description: "Specify the class to be added to the generated link. Disable to clear.",
suggestions: ["auto-linker", false]
},
%{
key: :rel,
type: [:string, false],
- description: "Override the rel attribute. Disable to clear",
+ description: "Override the rel attribute. Disable to clear.",
suggestions: ["ugc", "noopener noreferrer", false]
},
%{
key: :new_window,
type: :boolean,
- description: "Link urls will open in new window/tab"
+ description: "Link URLs will open in new window/tab"
},
%{
key: :truncate,
type: [:integer, false],
description:
- "Set to a number to truncate urls longer then the number. Truncated urls will end in `..`",
+ "Set to a number to truncate URLs longer then the number. Truncated URLs will end in `..`",
suggestions: [15, false]
},
%{
@@ -2204,7 +2222,7 @@ config :pleroma, :config_description, [
%{
key: :extra,
type: :boolean,
- description: "Link urls with rarely used schemes (magnet, ipfs, irc, etc.)"
+ description: "Link URLs with rarely used schemes (magnet, ipfs, irc, etc.)"
}
]
},
@@ -2250,6 +2268,7 @@ config :pleroma, :config_description, [
},
%{
group: :pleroma,
+ label: "Pleroma Authenticator",
type: :group,
description: "Authenticator",
children: [
@@ -2263,6 +2282,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :ldap,
+ label: "LDAP",
type: :group,
description:
"Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password" <>
@@ -2349,6 +2369,7 @@ config :pleroma, :config_description, [
},
%{
key: :uid,
+ label: "UID",
type: :string,
description:
"LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter will be \"cn=username,base\"",
@@ -2364,11 +2385,12 @@ config :pleroma, :config_description, [
children: [
%{
key: :enforce_oauth_admin_scope_usage,
+ label: "Enforce OAuth admin scope usage",
type: :boolean,
description:
"OAuth admin scope requirement toggle. " <>
"If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token " <>
- "(client app must support admin scopes). If disabled and token doesn't have admin scope(s)," <>
+ "(client app must support admin scopes). If disabled and token doesn't have admin scope(s), " <>
"`is_admin` user flag grants access to admin-specific actions."
},
%{
@@ -2380,6 +2402,7 @@ config :pleroma, :config_description, [
},
%{
key: :oauth_consumer_template,
+ label: "OAuth consumer template",
type: :string,
description:
"OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to" <>
@@ -2388,6 +2411,7 @@ config :pleroma, :config_description, [
},
%{
key: :oauth_consumer_strategies,
+ label: "OAuth consumer strategies",
type: {:list, :string},
description:
"The list of enabled OAuth consumer strategies. By default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
@@ -2516,7 +2540,7 @@ config :pleroma, :config_description, [
%{
key: :enabled,
type: :boolean,
- description: "enables new users admin digest email when `true`",
+ description: "Enables new users admin digest email when `true`",
suggestions: [false]
}
]
@@ -2524,6 +2548,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :oauth2,
+ label: "OAuth2",
type: :group,
description: "Configure OAuth 2 provider capabilities",
children: [
@@ -2542,7 +2567,7 @@ config :pleroma, :config_description, [
%{
key: :clean_expired_tokens,
type: :boolean,
- description: "Enable a background job to clean expired oauth tokens. Default: disabled."
+ description: "Enable a background job to clean expired OAuth tokens. Default: disabled."
}
]
},
@@ -2626,6 +2651,7 @@ config :pleroma, :config_description, [
},
%{
key: :relation_id_action,
+ label: "Relation ID action",
type: [:tuple, {:list, :tuple}],
description: "For actions on relation with a specific user (follow, unfollow)",
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
@@ -2639,6 +2665,7 @@ config :pleroma, :config_description, [
},
%{
key: :status_id_action,
+ label: "Status ID action",
type: [:tuple, {:list, :tuple}],
description:
"For fav / unfav or reblog / unreblog actions on the same status by the same user",
@@ -2654,6 +2681,7 @@ config :pleroma, :config_description, [
},
%{
group: :esshd,
+ label: "ESSHD",
type: :group,
description:
"Before enabling this you must add :esshd to mix.exs as one of the extra_applications " <>
@@ -2692,8 +2720,9 @@ config :pleroma, :config_description, [
},
%{
group: :mime,
+ label: "Mime Types",
type: :group,
- description: "Mime types",
+ description: "Mime Types settings",
children: [
%{
key: :types,
@@ -2752,6 +2781,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :http,
+ label: "HTTP",
type: :group,
description: "HTTP settings",
children: [
@@ -2800,6 +2830,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :markup,
+ label: "Markup Settings",
type: :group,
children: [
%{
@@ -2842,7 +2873,7 @@ config :pleroma, :config_description, [
group: :pleroma,
tab: :mrf,
key: :mrf_normalize_markup,
- label: "MRF normalize markup",
+ label: "MRF Normalize Markup",
description: "MRF NormalizeMarkup settings. Scrub configured hypertext markup.",
type: :group,
children: [
@@ -2898,6 +2929,7 @@ config :pleroma, :config_description, [
},
%{
group: :cors_plug,
+ label: "CORS plug config",
type: :group,
children: [
%{
@@ -2970,6 +3002,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :web_cache_ttl,
+ label: "Web cache TTL",
type: :group,
description:
"The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration.",
@@ -2992,9 +3025,10 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :static_fe,
+ label: "Static FE",
type: :group,
description:
- "Render profiles and posts using server-generated HTML that is viewable without using JavaScript.",
+ "Render profiles and posts using server-generated HTML that is viewable without using JavaScript",
children: [
%{
key: :enabled,
@@ -3012,18 +3046,18 @@ config :pleroma, :config_description, [
%{
key: :post_title,
type: :map,
- description: "Configure title rendering.",
+ description: "Configure title rendering",
children: [
%{
key: :max_length,
type: :integer,
- description: "Maximum number of characters before truncating title.",
+ description: "Maximum number of characters before truncating title",
suggestions: [100]
},
%{
key: :omission,
type: :string,
- description: "Replacement which will be used after truncating string.",
+ description: "Replacement which will be used after truncating string",
suggestions: ["..."]
}
]
@@ -3033,7 +3067,7 @@ config :pleroma, :config_description, [
%{
group: :pleroma,
key: :mrf_object_age,
- label: "MRF object age",
+ label: "MRF Object Age",
tab: :mrf,
type: :group,
description: "Rejects or delists posts based on their age when received.",
@@ -3077,13 +3111,13 @@ config :pleroma, :config_description, [
%{
key: :workers,
type: :integer,
- description: "Number of workers to send notifications.",
+ description: "Number of workers to send notifications",
suggestions: [3]
},
%{
key: :overflow_workers,
type: :integer,
- description: "Maximum number of workers created if pool is empty.",
+ description: "Maximum number of workers created if pool is empty",
suggestions: [2]
}
]
diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md
index 7c3546f4f..13920e5f9 100644
--- a/docs/API/differences_in_mastoapi_responses.md
+++ b/docs/API/differences_in_mastoapi_responses.md
@@ -27,6 +27,7 @@ Has these additional fields under the `pleroma` object:
- `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire
- `thread_muted`: true if the thread the post belongs to is muted
- `emoji_reactions`: A list with emoji / reaction maps. The format is `{name: "☕", count: 1, me: true}`. Contains no information about the reacting users, for that use the `/statuses/:id/reactions` endpoint.
+- `parent_visible`: If the parent of this post is visible to the user or not.
## Media Attachments
@@ -51,11 +52,14 @@ The `id` parameter can also be the `nickname` of the user. This only works in th
Has these additional fields under the `pleroma` object:
+- `ap_id`: nullable URL string, ActivityPub id of the user
+- `background_image`: nullable URL string, background image of the user
- `tags`: Lists an array of tags for the user
-- `relationship{}`: Includes fields as documented for Mastodon API https://docs.joinmastodon.org/entities/relationship/
+- `relationship` (object): Includes fields as documented for Mastodon API https://docs.joinmastodon.org/entities/relationship/
- `is_moderator`: boolean, nullable, true if user is a moderator
- `is_admin`: boolean, nullable, true if user is an admin
- `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated
+- `hide_favorites`: boolean, true when the user has hiding favorites enabled
- `hide_followers`: boolean, true when the user has follower hiding enabled
- `hide_follows`: boolean, true when the user has follow hiding enabled
- `hide_followers_count`: boolean, true when the user has follower stat hiding enabled
@@ -66,6 +70,7 @@ Has these additional fields under the `pleroma` object:
- `allow_following_move`: boolean, true when the user allows automatically follow moved following accounts
- `unread_conversation_count`: The count of unread conversations. Only returned to the account owner.
- `unread_notifications_count`: The count of unread notifications. Only returned to the account owner.
+- `notification_settings`: object, can be absent. See `/api/pleroma/notification_settings` for the parameters/keys returned.
### Source
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index d78c5f202..dc1b9b840 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -109,7 +109,7 @@ defmodule Pleroma.HTML do
result =
content
|> Floki.parse_fragment!()
- |> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"]")
+ |> Floki.filter_out("a.mention,a.hashtag,a.attachment,a[rel~=\"tag\"]")
|> Floki.attribute("a", "href")
|> Enum.at(0)
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index 9ee9606be..2ef1a80c5 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -367,6 +367,7 @@ defmodule Pleroma.Notification do
do_send = do_send && user in enabled_receivers
create_notification(activity, user, do_send)
end)
+ |> Enum.reject(&is_nil/1)
{:ok, notifications}
end
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index 263ded5dd..3e2949ee2 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -83,8 +83,8 @@ defmodule Pleroma.Object.Fetcher do
{:transmogrifier, {:error, {:reject, nil}}} ->
{:reject, nil}
- {:transmogrifier, _} ->
- {:error, "Transmogrifier failure."}
+ {:transmogrifier, _} = e ->
+ {:error, e}
{:object, data, nil} ->
reinject_object(%Object{}, data)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 1d70a37ef..8a54546d6 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -115,7 +115,7 @@ defmodule Pleroma.User do
field(:is_moderator, :boolean, default: false)
field(:is_admin, :boolean, default: false)
field(:show_role, :boolean, default: true)
- field(:settings, :map, default: nil)
+ field(:mastofe_settings, :map, default: nil)
field(:uri, ObjectValidators.Uri, default: nil)
field(:hide_followers_count, :boolean, default: false)
field(:hide_follows_count, :boolean, default: false)
@@ -1309,7 +1309,8 @@ defmodule Pleroma.User do
unsubscribe(blocked, blocker)
- if following?(blocked, blocker), do: unfollow(blocked, blocker)
+ unfollowing_blocked = Config.get([:activitypub, :unfollow_blocked], true)
+ if unfollowing_blocked && following?(blocked, blocker), do: unfollow(blocked, blocker)
{:ok, blocker} = update_follower_count(blocker)
{:ok, blocker, _} = Participation.mark_all_as_read(blocker, blocked)
@@ -1527,8 +1528,7 @@ defmodule Pleroma.User do
blocked_identifiers,
fn blocked_identifier ->
with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier),
- {:ok, _user_block} <- block(blocker, blocked),
- {:ok, _} <- ActivityPub.block(blocker, blocked) do
+ {:ok, _block} <- CommonAPI.block(blocker, blocked) do
blocked
else
err ->
@@ -2118,8 +2118,8 @@ defmodule Pleroma.User do
def mastodon_settings_update(user, settings) do
user
- |> cast(%{settings: settings}, [:settings])
- |> validate_required([:settings])
+ |> cast(%{mastofe_settings: settings}, [:mastofe_settings])
+ |> validate_required([:mastofe_settings])
|> update_and_set_cache()
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 7cd3eab39..94117202c 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -366,33 +366,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- @spec block(User.t(), User.t(), String.t() | nil, boolean()) ::
- {:ok, Activity.t()} | {:error, any()}
- def block(blocker, blocked, activity_id \\ nil, local \\ true) do
- with {:ok, result} <-
- Repo.transaction(fn -> do_block(blocker, blocked, activity_id, local) end) do
- result
- end
- end
-
- defp do_block(blocker, blocked, activity_id, local) do
- unfollow_blocked = Config.get([:activitypub, :unfollow_blocked])
-
- if unfollow_blocked and fetch_latest_follow(blocker, blocked) do
- unfollow(blocker, blocked, nil, local)
- end
-
- block_data = make_block_data(blocker, blocked, activity_id)
-
- with {:ok, activity} <- insert(block_data, local),
- _ <- notify_and_stream(activity),
- :ok <- maybe_federate(activity) do
- {:ok, activity}
- else
- {:error, error} -> Repo.rollback(error)
- end
- end
-
@spec flag(map()) :: {:ok, Activity.t()} | {:error, any()}
def flag(
%{
@@ -1398,6 +1371,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ def maybe_handle_clashing_nickname(nickname) do
+ with %User{} = old_user <- User.get_by_nickname(nickname) do
+ Logger.info("Found an old user for #{nickname}, ap id is #{old_user.ap_id}, renaming.")
+
+ old_user
+ |> User.remote_user_changeset(%{nickname: "#{old_user.id}.#{old_user.nickname}"})
+ |> User.update_and_set_cache()
+ end
+ end
+
def make_user_from_ap_id(ap_id) do
user = User.get_cached_by_ap_id(ap_id)
@@ -1410,6 +1393,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> User.remote_user_changeset(data)
|> User.update_and_set_cache()
else
+ maybe_handle_clashing_nickname(data[:nickname])
+
data
|> User.remote_user_changeset()
|> Repo.insert()
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 135a5c431..cabc28de9 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -138,6 +138,18 @@ defmodule Pleroma.Web.ActivityPub.Builder do
}, []}
end
+ @spec block(User.t(), User.t()) :: {:ok, map(), keyword()}
+ def block(blocker, blocked) do
+ {:ok,
+ %{
+ "id" => Utils.generate_activity_id(),
+ "type" => "Block",
+ "actor" => blocker.ap_id,
+ "object" => blocked.ap_id,
+ "to" => [blocked.ap_id]
+ }, []}
+ end
+
@spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()}
def announce(actor, object, options \\ []) do
public? = Keyword.get(options, :public, false)
diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex
index 9e7800997..a7e187b5e 100644
--- a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex
@@ -27,11 +27,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
@impl true
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do
- with {:ok, %User{} = u} <- User.get_or_fetch_by_ap_id(actor),
+ with {:ok, %User{local: false} = u} <- User.get_or_fetch_by_ap_id(actor),
{:contains_links, true} <- {:contains_links, contains_links?(object)},
{:old_user, true} <- {:old_user, old_user?(u)} do
{:ok, message}
else
+ {:ok, %User{local: true}} ->
+ {:ok, message}
+
{:contains_links, false} ->
{:ok, message}
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 2c657b467..bb6324460 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
@@ -24,6 +25,25 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
def validate(object, meta)
+ def validate(%{"type" => "Block"} = block_activity, meta) do
+ with {:ok, block_activity} <-
+ block_activity
+ |> BlockValidator.cast_and_validate()
+ |> Ecto.Changeset.apply_action(:insert) do
+ block_activity = stringify_keys(block_activity)
+ outgoing_blocks = Pleroma.Config.get([:activitypub, :outgoing_blocks])
+
+ meta =
+ if !outgoing_blocks do
+ Keyword.put(meta, :do_not_federate, true)
+ else
+ meta
+ end
+
+ {:ok, block_activity, meta}
+ end
+ end
+
def validate(%{"type" => "Update"} = update_activity, meta) do
with {:ok, update_activity} <-
update_activity
diff --git a/lib/pleroma/web/activity_pub/object_validators/block_validator.ex b/lib/pleroma/web/activity_pub/object_validators/block_validator.ex
new file mode 100644
index 000000000..1dde77198
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/block_validator.ex
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator do
+ use Ecto.Schema
+
+ alias Pleroma.EctoType.ActivityPub.ObjectValidators
+
+ import Ecto.Changeset
+ import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, ObjectValidators.ObjectID, primary_key: true)
+ field(:type, :string)
+ field(:actor, ObjectValidators.ObjectID)
+ field(:to, ObjectValidators.Recipients, default: [])
+ field(:cc, ObjectValidators.Recipients, default: [])
+ field(:object, ObjectValidators.ObjectID)
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> cast(data, __schema__(:fields))
+ end
+
+ def validate_data(cng) do
+ cng
+ |> validate_required([:id, :type, :actor, :to, :cc, :object])
+ |> validate_inclusion(:type, ["Block"])
+ |> validate_actor_presence()
+ |> validate_actor_presence(field_name: :object)
+ end
+
+ def cast_and_validate(data) do
+ data
+ |> cast_data
+ |> validate_data
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index de143b8f0..61feeae4d 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
collection, and so on.
"""
alias Pleroma.Activity
+ alias Pleroma.Activity.Ir.Topics
alias Pleroma.Chat
alias Pleroma.Chat.MessageReference
alias Pleroma.Notification
@@ -21,6 +22,21 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
def handle(object, meta \\ [])
# Tasks this handles:
+ # - Unfollow and block
+ def handle(
+ %{data: %{"type" => "Block", "object" => blocked_user, "actor" => blocking_user}} =
+ object,
+ meta
+ ) do
+ with %User{} = blocker <- User.get_cached_by_ap_id(blocking_user),
+ %User{} = blocked <- User.get_cached_by_ap_id(blocked_user) do
+ User.block(blocker, blocked)
+ end
+
+ {:ok, object, meta}
+ end
+
+ # Tasks this handles:
# - Update the user
#
# For a local user, we also get a changeset with the full information, so we
@@ -82,7 +98,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
if !User.is_internal_user?(user) do
Notification.create_notifications(object)
- ActivityPub.stream_out(object)
+
+ object
+ |> Topics.get_activity_topics()
+ |> Streamer.stream(object)
end
{:ok, object, meta}
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 4e318e89c..bc6fc4bd8 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -446,12 +446,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer", "Audio"] do
actor = Containment.get_actor(data)
- data =
- Map.put(data, "actor", actor)
- |> fix_addressing
-
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
- {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do
+ {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(actor),
+ data <- Map.put(data, "actor", actor) |> fix_addressing() do
object = fix_object(object, options)
params = %{
@@ -673,7 +670,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def handle_incoming(%{"type" => type} = data, _options)
- when type in ["Like", "EmojiReact", "Announce"] do
+ when type in ~w{Like EmojiReact Announce} do
with :ok <- ObjectValidator.fetch_actor_and_object(data),
{:ok, activity, _meta} <-
Pipeline.common_pipeline(data, local: false) do
@@ -684,9 +681,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def handle_incoming(
- %{"type" => "Update"} = data,
+ %{"type" => type} = data,
_options
- ) do
+ )
+ when type in ~w{Update Block} do
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
{:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
{:ok, activity}
@@ -766,21 +764,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def handle_incoming(
- %{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = _data,
- _options
- ) do
- with %User{local: true} = blocked = User.get_cached_by_ap_id(blocked),
- {:ok, %User{} = blocker} = User.get_or_fetch_by_ap_id(blocker),
- {:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do
- User.unfollow(blocker, blocked)
- User.block(blocker, blocked)
- {:ok, activity}
- else
- _e -> :error
- end
- end
-
- def handle_incoming(
%{
"type" => "Move",
"actor" => origin_actor,
diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex
index 453a6842e..343f41caa 100644
--- a/lib/pleroma/web/activity_pub/visibility.ex
+++ b/lib/pleroma/web/activity_pub/visibility.ex
@@ -47,6 +47,10 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
@spec visible_for_user?(Activity.t(), User.t() | nil) :: boolean()
def visible_for_user?(%{actor: ap_id}, %User{ap_id: ap_id}), do: true
+ def visible_for_user?(nil, _), do: false
+
+ def visible_for_user?(%{data: %{"listMessage" => _}}, nil), do: false
+
def visible_for_user?(%{data: %{"listMessage" => list_ap_id}} = activity, %User{} = user) do
user.ap_id in activity.data["to"] ||
list_ap_id
@@ -54,8 +58,6 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|> Pleroma.List.member?(user)
end
- def visible_for_user?(%{data: %{"listMessage" => _}}, nil), do: false
-
def visible_for_user?(%{local: local} = activity, nil) do
cfg_key =
if local,
diff --git a/lib/pleroma/web/api_spec/cast_and_validate.ex b/lib/pleroma/web/api_spec/cast_and_validate.ex
index bd9026237..fbfc27d6f 100644
--- a/lib/pleroma/web/api_spec/cast_and_validate.ex
+++ b/lib/pleroma/web/api_spec/cast_and_validate.ex
@@ -40,7 +40,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
|> List.first()
_ ->
- nil
+ "application/json"
end
private_data = Map.put(private_data, :operation_id, operation_id)
diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex
index d54e2158d..84f18f1b6 100644
--- a/lib/pleroma/web/api_spec/schemas/account.ex
+++ b/lib/pleroma/web/api_spec/schemas/account.ex
@@ -40,20 +40,53 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
pleroma: %Schema{
type: :object,
properties: %{
- allow_following_move: %Schema{type: :boolean},
- background_image: %Schema{type: :string, nullable: true},
+ allow_following_move: %Schema{
+ type: :boolean,
+ description: "whether the user allows automatically follow moved following accounts"
+ },
+ background_image: %Schema{type: :string, nullable: true, format: :uri},
chat_token: %Schema{type: :string},
- confirmation_pending: %Schema{type: :boolean},
+ confirmation_pending: %Schema{
+ type: :boolean,
+ description:
+ "whether the user account is waiting on email confirmation to be activated"
+ },
hide_favorites: %Schema{type: :boolean},
- hide_followers_count: %Schema{type: :boolean},
- hide_followers: %Schema{type: :boolean},
- hide_follows_count: %Schema{type: :boolean},
- hide_follows: %Schema{type: :boolean},
- is_admin: %Schema{type: :boolean},
- is_moderator: %Schema{type: :boolean},
+ hide_followers_count: %Schema{
+ type: :boolean,
+ description: "whether the user has follower stat hiding enabled"
+ },
+ hide_followers: %Schema{
+ type: :boolean,
+ description: "whether the user has follower hiding enabled"
+ },
+ hide_follows_count: %Schema{
+ type: :boolean,
+ description: "whether the user has follow stat hiding enabled"
+ },
+ hide_follows: %Schema{
+ type: :boolean,
+ description: "whether the user has follow hiding enabled"
+ },
+ is_admin: %Schema{
+ type: :boolean,
+ description: "whether the user is an admin of the local instance"
+ },
+ is_moderator: %Schema{
+ type: :boolean,
+ description: "whether the user is a moderator of the local instance"
+ },
skip_thread_containment: %Schema{type: :boolean},
- tags: %Schema{type: :array, items: %Schema{type: :string}},
- unread_conversation_count: %Schema{type: :integer},
+ tags: %Schema{
+ type: :array,
+ items: %Schema{type: :string},
+ description:
+ "List of tags being used for things like extra roles or moderation(ie. marking all media as nsfw all)."
+ },
+ unread_conversation_count: %Schema{
+ type: :integer,
+ description: "The count of unread conversations. Only returned to the account owner."
+ },
notification_settings: %Schema{
type: :object,
properties: %{
@@ -66,7 +99,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
},
relationship: AccountRelationship,
settings_store: %Schema{
- type: :object
+ type: :object,
+ description:
+ "A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials`"
}
}
},
@@ -74,16 +109,32 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
type: :object,
properties: %{
fields: %Schema{type: :array, items: AccountField},
- note: %Schema{type: :string},
+ note: %Schema{
+ type: :string,
+ description:
+ "Plaintext version of the bio without formatting applied by the backend, used for editing the bio."
+ },
privacy: VisibilityScope,
sensitive: %Schema{type: :boolean},
pleroma: %Schema{
type: :object,
properties: %{
actor_type: ActorType,
- discoverable: %Schema{type: :boolean},
- no_rich_text: %Schema{type: :boolean},
- show_role: %Schema{type: :boolean}
+ discoverable: %Schema{
+ type: :boolean,
+ description:
+ "whether the user allows discovery of the account in search results and other services."
+ },
+ no_rich_text: %Schema{
+ type: :boolean,
+ description:
+ "whether the HTML tags for rich-text formatting are stripped from all statuses requested from the API."
+ },
+ show_role: %Schema{
+ type: :boolean,
+ description:
+ "whether the user wants their role (e.g admin, moderator) to be shown"
+ }
}
}
}
diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex
index 8b87cb25b..28cde963e 100644
--- a/lib/pleroma/web/api_spec/schemas/status.ex
+++ b/lib/pleroma/web/api_spec/schemas/status.ex
@@ -184,6 +184,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
thread_muted: %Schema{
type: :boolean,
description: "`true` if the thread the post belongs to is muted"
+ },
+ parent_visible: %Schema{
+ type: :boolean,
+ description: "`true` if the parent post is visible to the user"
}
}
},
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 04e081a8e..fd7149079 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -25,6 +25,13 @@ defmodule Pleroma.Web.CommonAPI do
require Pleroma.Constants
require Logger
+ def block(blocker, blocked) do
+ with {:ok, block_data, _} <- Builder.block(blocker, blocked),
+ {:ok, block, _} <- Pipeline.common_pipeline(block_data, local: true) do
+ {:ok, block}
+ end
+ end
+
def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
with maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
:ok <- validate_chat_content_length(content, !!maybe_attachment),
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 7a88a847c..b5008d69b 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -385,8 +385,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "POST /api/v1/accounts/:id/block"
def block(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
- with {:ok, _user_block} <- User.block(blocker, blocked),
- {:ok, _activity} <- ActivityPub.block(blocker, blocked) do
+ with {:ok, _activity} <- CommonAPI.block(blocker, blocked) do
render(conn, "relationship.json", user: blocker, target: blocked)
else
{:error, message} -> json_response(conn, :forbidden, %{error: message})
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 2c49bedb3..6ee17f4dd 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MediaProxy
- import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1]
+ import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
# TODO: Add cached version.
defp get_replied_to_activities([]), do: %{}
@@ -364,7 +364,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
expires_at: expires_at,
direct_conversation_id: direct_conversation_id,
thread_muted: thread_muted?,
- emoji_reactions: emoji_reactions
+ emoji_reactions: emoji_reactions,
+ parent_visible: visible_for_user?(reply_to, opts[:for])
}
}
end
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex
index f7ab6d86a..47fa46376 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex
@@ -19,35 +19,7 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo do
|> Enum.map(fn u -> u.ap_id end)
federation = InstanceView.federation()
-
- features =
- [
- "pleroma_api",
- "mastodon_api",
- "mastodon_api_streaming",
- "polls",
- "pleroma_explicit_addressing",
- "shareable_emoji_packs",
- "multifetch",
- "pleroma:api/v1/notifications:include_types_filter",
- if Config.get([:media_proxy, :enabled]) do
- "media_proxy"
- end,
- if Config.get([:gopher, :enabled]) do
- "gopher"
- end,
- if Config.get([:chat, :enabled]) do
- "chat"
- end,
- if Config.get([:instance, :allow_relay]) do
- "relay"
- end,
- if Config.get([:instance, :safe_dm_mentions]) do
- "safe_dm_mentions"
- end,
- "pleroma_emoji_reactions"
- ]
- |> Enum.filter(& &1)
+ features = InstanceView.features()
%{
version: "2.0",
diff --git a/lib/pleroma/web/preload/instance.ex b/lib/pleroma/web/preload/instance.ex
index 0b6fd3313..50d1f3382 100644
--- a/lib/pleroma/web/preload/instance.ex
+++ b/lib/pleroma/web/preload/instance.ex
@@ -3,14 +3,15 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Preload.Providers.Instance do
+ alias Pleroma.Plugs.InstanceStatic
alias Pleroma.Web.MastodonAPI.InstanceView
alias Pleroma.Web.Nodeinfo.Nodeinfo
alias Pleroma.Web.Preload.Providers.Provider
@behaviour Provider
- @instance_url :"/api/v1/instance"
- @panel_url :"/instance/panel.html"
- @nodeinfo_url :"/nodeinfo/2.0"
+ @instance_url "/api/v1/instance"
+ @panel_url "/instance/panel.html"
+ @nodeinfo_url "/nodeinfo/2.0.json"
@impl Provider
def generate_terms(_params) do
@@ -27,7 +28,7 @@ defmodule Pleroma.Web.Preload.Providers.Instance do
end
defp build_panel_tag(acc) do
- instance_path = Path.join(:code.priv_dir(:pleroma), "static/instance/panel.html")
+ instance_path = InstanceStatic.file_path(@panel_url |> to_string())
if File.exists?(instance_path) do
panel_data = File.read!(instance_path)
diff --git a/lib/pleroma/web/preload/status_net.ex b/lib/pleroma/web/preload/status_net.ex
index 367442d5c..9b62f87a2 100644
--- a/lib/pleroma/web/preload/status_net.ex
+++ b/lib/pleroma/web/preload/status_net.ex
@@ -4,10 +4,10 @@
defmodule Pleroma.Web.Preload.Providers.StatusNet do
alias Pleroma.Web.Preload.Providers.Provider
- alias Pleroma.Web.TwitterAPI.UtilView
+ alias Pleroma.Web.TwitterAPI.UtilController
@behaviour Provider
- @config_url :"/api/statusnet/config.json"
+ @config_url "/api/statusnet/config.json"
@impl Provider
def generate_terms(_params) do
@@ -16,9 +16,10 @@ defmodule Pleroma.Web.Preload.Providers.StatusNet do
end
defp build_config_tag(acc) do
- instance = Pleroma.Config.get(:instance)
- info_data = UtilView.status_net_config(instance)
+ resp =
+ Plug.Test.conn(:get, @config_url |> to_string())
+ |> UtilController.config(nil)
- Map.put(acc, @config_url, info_data)
+ Map.put(acc, @config_url, resp.resp_body)
end
end
diff --git a/lib/pleroma/web/preload/timelines.ex b/lib/pleroma/web/preload/timelines.ex
index e531b8960..57de04051 100644
--- a/lib/pleroma/web/preload/timelines.ex
+++ b/lib/pleroma/web/preload/timelines.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.Web.Preload.Providers.Timelines do
alias Pleroma.Web.Preload.Providers.Provider
@behaviour Provider
- @public_url :"/api/v1/timelines/public"
+ @public_url "/api/v1/timelines/public"
@impl Provider
def generate_terms(params) do
diff --git a/lib/pleroma/web/preload/user.ex b/lib/pleroma/web/preload/user.ex
index 3a244845b..b3d2e9b8d 100644
--- a/lib/pleroma/web/preload/user.ex
+++ b/lib/pleroma/web/preload/user.ex
@@ -3,11 +3,12 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Preload.Providers.User do
+ alias Pleroma.User
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.Preload.Providers.Provider
@behaviour Provider
- @account_url :"/api/v1/accounts"
+ @account_url_base "/api/v1/accounts"
@impl Provider
def generate_terms(%{user: user}) do
@@ -16,10 +17,10 @@ defmodule Pleroma.Web.Preload.Providers.User do
def generate_terms(_params), do: %{}
- def build_accounts_tag(acc, nil), do: acc
-
- def build_accounts_tag(acc, user) do
+ def build_accounts_tag(acc, %User{} = user) do
account_data = AccountView.render("show.json", %{user: user, for: user})
- Map.put(acc, @account_url, account_data)
+ Map.put(acc, "#{@account_url_base}/#{user.id}", account_data)
end
+
+ def build_accounts_tag(acc, _), do: acc
end
diff --git a/lib/pleroma/web/streamer/streamer.ex b/lib/pleroma/web/streamer/streamer.ex
index d1d2c9b9c..73ee3e1e1 100644
--- a/lib/pleroma/web/streamer/streamer.ex
+++ b/lib/pleroma/web/streamer/streamer.ex
@@ -116,6 +116,7 @@ defmodule Pleroma.Web.Streamer do
true <-
Enum.all?([blocked_ap_ids, muted_ap_ids], &(item.actor not in &1)),
true <- item.data["type"] != "Announce" || item.actor not in reblog_muted_ap_ids,
+ true <- !(item.data["type"] == "Announce" && parent.data["actor"] == user.ap_id),
true <- Enum.all?([blocked_ap_ids, muted_ap_ids], &(parent.data["actor"] not in &1)),
true <- MapSet.disjoint?(recipients, recipient_blocks),
%{host: item_host} <- URI.parse(item.actor),
diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex
index c3096006e..f739dacb6 100644
--- a/lib/pleroma/web/views/masto_fe_view.ex
+++ b/lib/pleroma/web/views/masto_fe_view.ex
@@ -86,7 +86,7 @@ defmodule Pleroma.Web.MastoFEView do
"video\/mp4"
]
},
- settings: user.settings || @default_settings,
+ settings: user.mastofe_settings || @default_settings,
push_subscription: nil,
accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)},
custom_emojis: render(CustomEmojiView, "index.json", custom_emojis: custom_emojis),
diff --git a/mix.exs b/mix.exs
index b638be541..e2ab53bde 100644
--- a/mix.exs
+++ b/mix.exs
@@ -159,7 +159,10 @@ defmodule Pleroma.Mixfile do
{:cors_plug, "~> 1.5"},
{:ex_doc, "~> 0.21", only: :dev, runtime: false},
{:web_push_encryption, "~> 0.2.1"},
- {:swoosh, "~> 0.23.2"},
+ {:swoosh,
+ git: "https://github.com/swoosh/swoosh",
+ ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5",
+ override: true},
{:phoenix_swoosh, "~> 0.2"},
{:gen_smtp, "~> 0.13"},
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test},
diff --git a/mix.lock b/mix.lock
index 5ad49391d..4f2777fa7 100644
--- a/mix.lock
+++ b/mix.lock
@@ -104,9 +104,9 @@
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"},
- "swoosh": {:hex, :swoosh, "0.23.5", "bfd9404bbf5069b1be2ffd317923ce57e58b332e25dbca2a35dedd7820dfee5a", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "e3928e1d2889a308aaf3e42755809ac21cffd77cb58eef01cbfdab4ce2fd1e21"},
+ "swoosh": {:git, "https://github.com/swoosh/swoosh", "c96e0ca8a00d8f211ec1f042a4626b09f249caa5", [ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5"]},
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
- "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"},
+ "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
"tesla": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/tesla.git", "61b7503cef33f00834f78ddfafe0d5d9dec2270b", [ref: "61b7503cef33f00834f78ddfafe0d5d9dec2270b"]},
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "f354efb2400dd7a80fd9eb6c8419068c4f632da4ac47f3d8822d6e33f08bc852"},
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
diff --git a/priv/repo/migrations/20200630162024_rename_user_settings_col.exs b/priv/repo/migrations/20200630162024_rename_user_settings_col.exs
new file mode 100644
index 000000000..2355eb681
--- /dev/null
+++ b/priv/repo/migrations/20200630162024_rename_user_settings_col.exs
@@ -0,0 +1,11 @@
+defmodule Pleroma.Repo.Migrations.RenameUserSettingsCol do
+ use Ecto.Migration
+
+ def up do
+ rename(table(:users), :settings, to: :mastofe_settings)
+ end
+
+ def down do
+ rename(table(:users), :mastofe_settings, to: :settings)
+ end
+end
diff --git a/test/fixtures/fetch_mocks/104410921027210069.json b/test/fixtures/fetch_mocks/104410921027210069.json
new file mode 100644
index 000000000..583f7a4dc
--- /dev/null
+++ b/test/fixtures/fetch_mocks/104410921027210069.json
@@ -0,0 +1,72 @@
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ {
+ "atomUri" : "ostatus:atomUri",
+ "conversation" : "ostatus:conversation",
+ "inReplyToAtomUri" : "ostatus:inReplyToAtomUri",
+ "ostatus" : "http://ostatus.org#",
+ "sensitive" : "as:sensitive",
+ "toot" : "http://joinmastodon.org/ns#",
+ "votersCount" : "toot:votersCount"
+ }
+ ],
+ "atomUri" : "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069",
+ "attachment" : [],
+ "attributedTo" : "https://busshi.moe/users/tuxcrafting",
+ "cc" : [
+ "https://busshi.moe/users/tuxcrafting/followers",
+ "https://stereophonic.space/users/fixpoint",
+ "https://blob.cat/users/blobyoumu",
+ "https://cawfee.club/users/grips",
+ "https://jaeger.website/users/igel"
+ ],
+ "content" : "<p><span class=\"h-card\"><a href=\"https://stereophonic.space/users/fixpoint\" class=\"u-url mention\">@<span>fixpoint</span></a></span> <span class=\"h-card\"><a href=\"https://blob.cat/users/blobyoumu\" class=\"u-url mention\">@<span>blobyoumu</span></a></span> <span class=\"h-card\"><a href=\"https://cawfee.club/users/grips\" class=\"u-url mention\">@<span>grips</span></a></span> <span class=\"h-card\"><a href=\"https://jaeger.website/users/igel\" class=\"u-url mention\">@<span>igel</span></a></span> there&apos;s a difference between not liking nukes and not liking nuclear power<br />nukes are pretty bad as are all WMDs in general but disliking nuclear power just indicates you are unable of thought</p>",
+ "contentMap" : {
+ "en" : "<p><span class=\"h-card\"><a href=\"https://stereophonic.space/users/fixpoint\" class=\"u-url mention\">@<span>fixpoint</span></a></span> <span class=\"h-card\"><a href=\"https://blob.cat/users/blobyoumu\" class=\"u-url mention\">@<span>blobyoumu</span></a></span> <span class=\"h-card\"><a href=\"https://cawfee.club/users/grips\" class=\"u-url mention\">@<span>grips</span></a></span> <span class=\"h-card\"><a href=\"https://jaeger.website/users/igel\" class=\"u-url mention\">@<span>igel</span></a></span> there&apos;s a difference between not liking nukes and not liking nuclear power<br />nukes are pretty bad as are all WMDs in general but disliking nuclear power just indicates you are unable of thought</p>"
+ },
+ "conversation" : "https://cawfee.club/contexts/ad6c73d8-efc2-4e74-84ea-2dacf1a27a5e",
+ "id" : "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069",
+ "inReplyTo" : "https://stereophonic.space/objects/02997b83-3ea7-4b63-94af-ef3aa2d4ed17",
+ "inReplyToAtomUri" : "https://stereophonic.space/objects/02997b83-3ea7-4b63-94af-ef3aa2d4ed17",
+ "published" : "2020-06-26T15:10:19Z",
+ "replies" : {
+ "first" : {
+ "items" : [],
+ "next" : "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069/replies?only_other_accounts=true&page=true",
+ "partOf" : "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069/replies",
+ "type" : "CollectionPage"
+ },
+ "id" : "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069/replies",
+ "type" : "Collection"
+ },
+ "sensitive" : false,
+ "summary" : null,
+ "tag" : [
+ {
+ "href" : "https://stereophonic.space/users/fixpoint",
+ "name" : "@fixpoint@stereophonic.space",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://blob.cat/users/blobyoumu",
+ "name" : "@blobyoumu@blob.cat",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://cawfee.club/users/grips",
+ "name" : "@grips@cawfee.club",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://jaeger.website/users/igel",
+ "name" : "@igel@jaeger.website",
+ "type" : "Mention"
+ }
+ ],
+ "to" : [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type" : "Note",
+ "url" : "https://busshi.moe/@tuxcrafting/104410921027210069"
+}
diff --git a/test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json b/test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json
new file mode 100644
index 000000000..0226b058a
--- /dev/null
+++ b/test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json
@@ -0,0 +1,59 @@
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://social.sakamoto.gq/schemas/litepub-0.1.jsonld",
+ {
+ "@language" : "und"
+ }
+ ],
+ "actor" : "https://social.sakamoto.gq/users/eal",
+ "attachment" : [],
+ "attributedTo" : "https://social.sakamoto.gq/users/eal",
+ "cc" : [
+ "https://social.sakamoto.gq/users/eal/followers"
+ ],
+ "content" : "<span class=\"h-card\"><a data-user=\"9uw2wH0iTYAMV7XnLU\" class=\"u-url mention\" href=\"https://busshi.moe/@tuxcrafting\" rel=\"ugc\">@<span>tuxcrafting</span></a></span> <span class=\"h-card\"><a data-user=\"9r5l8j8x23NI9KUFu4\" class=\"u-url mention\" href=\"https://stereophonic.space/users/fixpoint\" rel=\"ugc\">@<span>fixpoint</span></a></span> <span class=\"h-card\"><a data-user=\"9orDK545JwjY4Lxjge\" class=\"u-url mention\" href=\"https://blob.cat/users/blobyoumu\" rel=\"ugc\">@<span>blobyoumu</span></a></span> <span class=\"h-card\"><a data-user=\"68184\" class=\"u-url mention\" href=\"https://cawfee.club/users/grips\" rel=\"ugc\">@<span>grips</span></a></span> <span class=\"h-card\"><a data-user=\"9sAmMgHVKjTXKpgx84\" class=\"u-url mention\" href=\"https://jaeger.website/users/igel\" rel=\"ugc\">@<span>igel</span></a></span> What&#39;s bad about nukes?",
+ "context" : "https://cawfee.club/contexts/ad6c73d8-efc2-4e74-84ea-2dacf1a27a5e",
+ "conversation" : "https://cawfee.club/contexts/ad6c73d8-efc2-4e74-84ea-2dacf1a27a5e",
+ "id" : "https://social.sakamoto.gq/objects/f20f2497-66d9-4a52-a2e1-1be2a39c32c1",
+ "inReplyTo" : "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069",
+ "published" : "2020-06-26T15:20:15.975737Z",
+ "sensitive" : false,
+ "summary" : "",
+ "tag" : [
+ {
+ "href" : "https://blob.cat/users/blobyoumu",
+ "name" : "@blobyoumu@blob.cat",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://busshi.moe/users/tuxcrafting",
+ "name" : "@tuxcrafting@busshi.moe",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://cawfee.club/users/grips",
+ "name" : "@grips@cawfee.club",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://jaeger.website/users/igel",
+ "name" : "@igel@jaeger.website",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://stereophonic.space/users/fixpoint",
+ "name" : "@fixpoint@stereophonic.space",
+ "type" : "Mention"
+ }
+ ],
+ "to" : [
+ "https://busshi.moe/users/tuxcrafting",
+ "https://www.w3.org/ns/activitystreams#Public",
+ "https://blob.cat/users/blobyoumu",
+ "https://stereophonic.space/users/fixpoint",
+ "https://cawfee.club/users/grips",
+ "https://jaeger.website/users/igel"
+ ],
+ "type" : "Note"
+}
diff --git a/test/fixtures/fetch_mocks/eal.json b/test/fixtures/fetch_mocks/eal.json
new file mode 100644
index 000000000..a605476e6
--- /dev/null
+++ b/test/fixtures/fetch_mocks/eal.json
@@ -0,0 +1,43 @@
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://social.sakamoto.gq/schemas/litepub-0.1.jsonld",
+ {
+ "@language" : "und"
+ }
+ ],
+ "attachment" : [],
+ "discoverable" : true,
+ "endpoints" : {
+ "oauthAuthorizationEndpoint" : "https://social.sakamoto.gq/oauth/authorize",
+ "oauthRegistrationEndpoint" : "https://social.sakamoto.gq/api/v1/apps",
+ "oauthTokenEndpoint" : "https://social.sakamoto.gq/oauth/token",
+ "sharedInbox" : "https://social.sakamoto.gq/inbox",
+ "uploadMedia" : "https://social.sakamoto.gq/api/ap/upload_media"
+ },
+ "followers" : "https://social.sakamoto.gq/users/eal/followers",
+ "following" : "https://social.sakamoto.gq/users/eal/following",
+ "icon" : {
+ "type" : "Image",
+ "url" : "https://social.sakamoto.gq/media/f1cb6f79bf6839f3223ca240441f766056b74ddd23c69bcaf8bb1ba1ecff6eec.jpg"
+ },
+ "id" : "https://social.sakamoto.gq/users/eal",
+ "image" : {
+ "type" : "Image",
+ "url" : "https://social.sakamoto.gq/media/e5cccf26421e8366f4e34be3c9d5042b8bc8dcceccc7c8e89785fa312dd9632c.jpg"
+ },
+ "inbox" : "https://social.sakamoto.gq/users/eal/inbox",
+ "manuallyApprovesFollowers" : false,
+ "name" : "에알",
+ "outbox" : "https://social.sakamoto.gq/users/eal/outbox",
+ "preferredUsername" : "eal",
+ "publicKey" : {
+ "id" : "https://social.sakamoto.gq/users/eal#main-key",
+ "owner" : "https://social.sakamoto.gq/users/eal",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz3pF85YOhhv2Zaxv9YQ7\nrCe1aEhetCMVHtrK63tUVGoGdsblyKnVeJNbFcr6k3y35OpHS3HXIi6GzgihYcTu\nONLP4eQMHTnLUNAQZi03mjJA4iIq8v/tm8ZkL2mXsQSAbWj6Iq518mHNN7OvCoNt\n3Xjepl/0kgkc2gsund7m8r+Wu0Fusx6UlUyyAk3PexdDRdSSlVLeskqtP8jtdQDo\nL70pMyL+VD+Qb9RKFdtgJ+M4OqYP+7FVzCqXN0QIPhFf/kvHSLr+c4Y3Wm0nAKHU\n9CwXWXz5Xqscpv41KlgnUCOkTXb5eBSt23lNulae5srVzWBiFb6guiCpNzBGa+Sq\nrwIDAQAB\n-----END PUBLIC KEY-----\n\n"
+ },
+ "summary" : "Pizza napoletana supremacist.<br><br>Any artworks posted here that are good are not mine.",
+ "tag" : [],
+ "type" : "Person",
+ "url" : "https://social.sakamoto.gq/users/eal"
+}
diff --git a/test/fixtures/fetch_mocks/tuxcrafting.json b/test/fixtures/fetch_mocks/tuxcrafting.json
new file mode 100644
index 000000000..5dce2a16d
--- /dev/null
+++ b/test/fixtures/fetch_mocks/tuxcrafting.json
@@ -0,0 +1,59 @@
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "IdentityProof" : "toot:IdentityProof",
+ "PropertyValue" : "schema:PropertyValue",
+ "alsoKnownAs" : {
+ "@id" : "as:alsoKnownAs",
+ "@type" : "@id"
+ },
+ "discoverable" : "toot:discoverable",
+ "featured" : {
+ "@id" : "toot:featured",
+ "@type" : "@id"
+ },
+ "focalPoint" : {
+ "@container" : "@list",
+ "@id" : "toot:focalPoint"
+ },
+ "manuallyApprovesFollowers" : "as:manuallyApprovesFollowers",
+ "movedTo" : {
+ "@id" : "as:movedTo",
+ "@type" : "@id"
+ },
+ "schema" : "http://schema.org#",
+ "toot" : "http://joinmastodon.org/ns#",
+ "value" : "schema:value"
+ }
+ ],
+ "attachment" : [],
+ "discoverable" : true,
+ "endpoints" : {
+ "sharedInbox" : "https://busshi.moe/inbox"
+ },
+ "featured" : "https://busshi.moe/users/tuxcrafting/collections/featured",
+ "followers" : "https://busshi.moe/users/tuxcrafting/followers",
+ "following" : "https://busshi.moe/users/tuxcrafting/following",
+ "icon" : {
+ "mediaType" : "image/jpeg",
+ "type" : "Image",
+ "url" : "https://blobcdn.busshi.moe/busshifiles/accounts/avatars/000/046/872/original/054f0806ccb303d0.jpg"
+ },
+ "id" : "https://busshi.moe/users/tuxcrafting",
+ "inbox" : "https://busshi.moe/users/tuxcrafting/inbox",
+ "manuallyApprovesFollowers" : true,
+ "name" : "@tuxcrafting@localhost:8080",
+ "outbox" : "https://busshi.moe/users/tuxcrafting/outbox",
+ "preferredUsername" : "tuxcrafting",
+ "publicKey" : {
+ "id" : "https://busshi.moe/users/tuxcrafting#main-key",
+ "owner" : "https://busshi.moe/users/tuxcrafting",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwqWWTBf9OizsBiBhGS/M\nQTT6fB1VvQP6vvxouGZ5cGg1a97V67ouhjJ+nGMuWr++DNYjJYkk2TOynfykk0H/\n8rRSujSe3BNRKYGNzdnRJu/4XxgIE847Fqx5SijSP23JGYcn8TjeSUsN2u2YYVXK\n+Eb3Bu7DjGiqwNon6YB0h5qkGjkMSMVIFn0hZx6Z21bkfYWgra96Ok5OWf7Ck3je\nCuErlCMZcbQcHtFpBueJAxYchjNvm6fqwZxLX/NtaHdr7Fm2kin89mqzliapBlFH\nCXk7Jln6xV5I6ryggPAMzm3fuHzeo0RWlu8lrxLfARBVwaQQZS99bwqp6N9O2aUp\nYwIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "summary" : "<p>expert procrastinator</p><p>trans(humanist|gender|istorized)</p><p>web: <a href=\"https://tuxcrafting.port0.org\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">tuxcrafting.port0.org</span><span class=\"invisible\"></span></a><br />pronouns: she/they<br />languages: french (native)/english (fluent)/hebrew (ok-ish)/esperanto (barely)</p>",
+ "tag" : [],
+ "type" : "Person",
+ "url" : "https://busshi.moe/@tuxcrafting"
+}
diff --git a/test/fixtures/preload_static/instance/panel.html b/test/fixtures/preload_static/instance/panel.html
new file mode 100644
index 000000000..fc58e4e93
--- /dev/null
+++ b/test/fixtures/preload_static/instance/panel.html
@@ -0,0 +1 @@
+HEY!
diff --git a/test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json b/test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json
index 3f3f0f4fb..b76ba96a5 100644
--- a/test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json
+++ b/test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json
@@ -1 +1,227 @@
-{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"Emoji":"toot:Emoji","Hashtag":"as:Hashtag","atomUri":"ostatus:atomUri","conversation":"ostatus:conversation","featured":"toot:featured","focalPoint":{"@container":"@list","@id":"toot:focalPoint"},"inReplyToAtomUri":"ostatus:inReplyToAtomUri","manuallyApprovesFollowers":"as:manuallyApprovesFollowers","movedTo":"as:movedTo","ostatus":"http://ostatus.org#","sensitive":"as:sensitive","toot":"http://joinmastodon.org/ns#"}],"attributedTo":["https://baptiste.gelez.xyz/@/BaptisteGelez"],"cc":[],"content":"<p>It has been one month since the last \"This Month in Plume\" article, so it is time for another edition of our monthly changelog!</p>\n<h2>Bug Fixes and Security</h2>\n<p>Let's start with the hidden, but still (very) important changes: bug fixes and security patches.</p>\n<p>First of all, <a href=\"/@/Trinity%20/\" title=\"Trinity \" rel=\"noopener noreferrer\">@Trinity </a> protected us against two major security flaws, called <em>XSS</em> and <em>CSRF</em>. The first one allows the attacker to run malicious code if you visit a Plume page where some of their personal data is present. The second one lets them post data with your Plume account by visiting one of their own website. It is two very common attack, and it is great we are now protected against them!</p>\n<p>The other big change in this area, is that we are now validating the data you are sending before doing anything with it. It means that, for instance, you will no longer be able to register with an empty username and to break everything.</p>\n<p>On the federation side, many issues were reported by <a href=\"/@/kaniini%20/\" title=\"kaniini \" rel=\"noopener noreferrer\">@kaniini </a> and <em>redmatrix</em> (respectively contributing to Pleroma and Hubzilla). By fixing some of them, we made it possible to <a href=\"https://baptiste.gelez.xyz/%7E/KaniiniTestBlog/current-status-of-plume-and-pleroma-federation/\" rel=\"noopener noreferrer\">federate Plume articles to Pleroma</a>!</p>\n<p><a href=\"/@/Trinity%20/\" title=\"Trinity \" rel=\"noopener noreferrer\">@Trinity </a> hopefully noticed that there was a bug in our password check code: we were not checking that your password was correct, but only that the verification process went without errors. Concretely, it means that you could login to any account with any password. I wrote this part of the code when I was still the only contributor to the project, so nobody could review my work. We will now be trying to check every change, especially when it deals with critical parts of Plume, to avoid similar issues in the future, and we I'm really sorry this happened (even if I think nobody exploited it).</p>\n<p><em>Zanfib</em> and <em>stephenburgess8</em> also commited some small bugfixes, improving the general experience.</p>\n<h2>New Features</h2>\n<p>Let's now talk about the features that we introduced during this month.</p>\n<p>One of the most easy to spot is the redesign of Plume, made by <a href=\"/@/Madeorsk.%20/\" title=\"Madeorsk. \" rel=\"noopener noreferrer\">@Madeorsk. </a> I personaly love what he did, it really improved the readability and gave Plume a bit more of identity than the previous design. And he is <a href=\"https://github.com/Plume-org/Plume/pull/104\" rel=\"noopener noreferrer\">still improving it</a>.</p>\n<p>We also enabled Mardown in comment, to let you write more structured and nicely formatted responses.</p>\n<p>As you may have noticed, I have used mentions in this post. Indeed, it is now possible to mention someone in your articles or in comments. It works exactly the same way as in other apps, and you should receive a notification if someone mentionned you.</p>\n<p>A dashboard to manage your blogs has also been introduced. In the future it may be used to manage your drafts, and eventually to show some statistics. The goal is to have a more specific homepage for authors.</p>\n<p>The federation with other ActivityPub softwares, like Mastodon or Pleroma is starting to work quite well, but the federation between Plume instances is far from being complete. However, we started to work on it, and it is now possible to view a distant user profile or blog from your instance, even if only basic informations are fetched yet (the articles are not loaded for instance).</p>\n<p>Another new feature that may not be visible for everyone, is the new NodeInfo endpoint. NodeInfo is a protocol allowing to get informations about a specific federated instance (whatever software it runs). It means that Plume instances can now be listed on sites like <a href=\"https://fediverse.network/plume\" rel=\"noopener noreferrer\">fediverse.network</a>.</p>\n<p>Maybe you wanted to host a Plume instance, but you don't like long install process during which you are just copy/pasting commands that you don't really understand from the documentation. That's why we introduced a setup script: the first you'll launch Plume, it will ask you a few questions and automatically setup your instance in a few minutes. We hope that this feature will help to host small instances, run by non-professional adminsys. You can see a demo of this tool on <a href=\"https://asciinema.org/a/tHktBK5iOd0zTulxmBX7LYQDc?t=32\" rel=\"noopener noreferrer\">asciinema</a>.</p>\n<p>Last but not least, Plume is now translatable! It is already available in English, French, Polish (thanks to <a href=\"/@/m4sk1n)/\" title=\"m4sk1n)\" rel=\"noopener noreferrer\">@m4sk1n)</a>) and German (thanks to <em>bitkeks</em>). If your browser is configured to display pages in these languages, you should normally see the interface in your language. And if your language is not present yet, feel free to <a href=\"https://github.com/Plume-org/Plume/blob/master/INTERNATIONALIZATION.md\" rel=\"noopener noreferrer\">add your translation</a>.</p>\n<h2>Other Changes</h2>\n<p>We also improved the code a lot. We tried to separate each part as much as possible, making it easier to re-use for other projects. For instance, our database code is now isolated from the rest of the app, which means it will be easier to make import tools from other blogging engines. Some parts of the code are even shared with another project, <a href=\"https://github.com/Aardwolf-Social/aardwolf\" rel=\"noopener noreferrer\">Aardwolf</a> a federated Facebook alternative. For instance, both of our projects use the same internationalization code, and once Aardwolf will implement federation, this part of the code will probably be shared too. Since the WebFinger module (used to find new users and blogs) and the CSRF protection code (see the \"Bug fixes and Security\" section) have been isolated in their own modules, they may be shared by both projects too.</p>\n<p>We also worked a lot on documentation. We now have articles explaining how to setup your Plume instance on various operating systems, but also documenting the translation process. I want to thank <em>BanjoFox</em> (who imported some documentation from their project, Aardwolf, as the setup is quite similar), <em>Kushal</em> and <a href=\"/@/gled@plume.mastodon.host%20/\" title=\"gled@plume.mastodon.host \" rel=\"noopener noreferrer\">@gled@plume.mastodon.host </a> for working on this.</p>\n<p>As you can see, there were many changes this month, but there still a lot to do. Your help will of course be welcome. If you want to contribute to the code, translate Plume in your language, write some documentation, or anything else (or even if you're just curious about the project), feel free to join our Matrix room: <a href=\"https://riot.im/app/#/room/#plume:disroot.org\" rel=\"noopener noreferrer\">#plume:disroot.org</a>. Otherwise, as <em>BanjoFox</em> <a href=\"https://glitch.social/@aardwolf/100329435838406278\" rel=\"noopener noreferrer\">said on the <em>Aardwolf Team</em> Mastodon account</a>, talking about the project around you is one of the easiest way to help.</p>\n","id":"https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/","likes":null,"name":"This Month in Plume: June 2018","published":"2018-07-10T20:16:24.087622Z","shares":null,"source":null,"tag":[{"href":"https://baptiste.gelez.xyz/@/Trinity","name":"@Trinity","type":"Mention"},{"href":"https://baptiste.gelez.xyz/@/kaniini/","name":"@kaniini","type":"Mention"},{"href":"https://baptiste.gelez.xyz/@/Trinity","name":"@Trinity","type":"Mention"}],"to":["https://unixcorn.xyz/users/Bat","https://mastodon.host/users/federationbot","https://social.tcit.fr/users/tcit","https://framapiaf.org/users/qwerty","https://mastodon.social/users/lthms","https://eldritch.cafe/users/Nausicaa","https://imaginair.es/users/Elanndelh","https://framapiaf.org/users/Drulac","https://mastodon.partipirate.org/users/NicolasConstant","https://aleph.land/users/Madeorsk","https://maly.io/users/Troll","https://hostux.social/users/superjey","https://mamot.fr/users/Phigger","https://mastodon.social/users/wakest","https://social.coop/users/wakest","https://unixcorn.xyz/users/Ce_lo","https://social.art-software.fr/users/Electron","https://framapiaf.org/users/Quenti","https://toot.plus.yt/users/Djyp","https://mastodon.social/users/brainblasted","https://social.mochi.academy/users/Ambraven","https://social.hacktivis.me/users/lanodan","https://mastodon.eliotberriot.com/users/eliotberriot","https://edolas.world/users/0x1C3B00DA","https://toot.cafe/users/zack","https://manowar.social/users/zatnosk","https://eldritch.cafe/users/fluffy","https://mastodon.social/users/david_ross","https://kosmos.social/users/xiroux","https://mastodon.art/users/EmergencyBattle","https://mastodon.social/users/trwnh","https://octodon.social/users/pybyte","https://anticapitalist.party/users/Trinity","https://mstdn.mx/users/xavavu","https://baptiste.gelez.xyz/@/m4sk1n","https://eldritch.cafe/users/milia","https://mastodon.zaclys.com/users/arx","https://toot.cafe/users/sivy","https://mastodon.social/users/ortegacmanuel","https://mastodon.observer/users/stephen","https://octodon.social/users/chloe","https://unixcorn.xyz/users/AmauryPi","https://cybre.space/users/rick_777","https://mastodon.social/users/wezm","https://baptiste.gelez.xyz/@/idlesong","https://mamot.fr/users/dr4Ke","https://imaginair.es/users/Phigger","https://mamot.fr/users/dlink","https://anticapitalist.party/users/a000d4f7a91939d0e71df1646d7a48","https://framapiaf.org/users/PhieLaidMignon","https://mastodon.social/users/y6nH","https://crazynoisybizarre.town/users/FederationBot","https://social.weho.st/users/dvn","https://mastodon.art/users/Wolthera","https://diaspodon.fr/users/dada","https://pachyder.me/users/Lanza","https://mastodon.xyz/users/ag","https://aleph.land/users/yahananxie","https://mstdn.io/users/chablis_social","https://mastodon.gougere.fr/users/fabien","https://functional.cafe/users/otini","https://social.coop/users/bhaugen","https://octodon.social/users/donblanco","https://chaos.social/users/astro","https://pachyder.me/users/sibear","https://mamot.fr/users/yohann","https://social.wxcafe.net/users/Bat","https://mastodon.social/users/dansup","https://chaos.social/users/juh","https://scifi.fyi/users/paeneultima","https://hostux.social/users/Deuchnord","https://mstdn.fr/users/taziden","https://mamot.fr/users/PifyZ","https://mastodon.social/users/plantabaja","https://mastodon.social/users/gitzgrog","https://mastodon.social/users/Syluban","https://masto.pt/users/eloisa","https://pleroma.soykaf.com/users/notclacke","https://mastodon.social/users/SiegfriedEhret","https://writing.exchange/users/write_as","https://mstdn.io/users/shellkr","https://mastodon.uy/users/jorge","https://mastodon.technology/users/bobstechsite","https://mastodon.social/users/hinterwaeldler","https://mastodon.xyz/users/mgdelacroix","https://mastodon.cloud/users/jjatria","https://baptiste.gelez.xyz/@/Jade/","https://edolas.world/users/pfm","https://mstdn.io/users/jort","https://mastodon.social/users/andreipetcu","https://mastodon.technology/users/0xf00fc7c8","https://mastodon.social/users/khanate","https://mastodon.technology/users/francois","https://mastodon.social/users/glherrmann","https://mastodon.host/users/gled","https://social.holdmybeer.solutions/users/kemonine","https://scholar.social/users/bgcarlisle","https://mastodon.social/users/oldgun","https://baptiste.gelez.xyz/@/snoe/","https://mastodon.at/users/switchingsocial","https://scifi.fyi/users/BrokenBiscuit","https://dev.glitch.social/users/hoodie","https://todon.nl/users/paulfree14","https://mastodon.social/users/aadilayub","https://social.fsck.club/users/anarchosaurus","https://mastodonten.de/users/GiantG","https://mastodon.technology/users/cj","https://cybre.space/users/sam","https://layer8.space/users/silkevicious","https://mastodon.xyz/users/Jimmyrwx","https://fosstodon.org/users/danyspin97","https://mstdn.io/users/cristhyano","https://mastodon.social/users/vanyok","https://hulvr.com/users/rook","https://niu.moe/users/Lucifer","https://mamot.fr/users/Thibaut","https://mastodont.cat/users/bgta","https://mstdn.io/users/hontoni","https://niu.moe/users/lionirdeadman","https://functional.cafe/users/phoe","https://mastodon.social/users/toontoet","https://mastodon.social/users/danipozo","https://scholar.social/users/robertson","https://mastodon.social/users/aldatsa","https://elekk.xyz/users/maloki","https://kitty.town/users/nursemchurt","https://neigh.horse/users/commagray","https://mastodon.social/users/hirojin","https://mastodon.xyz/users/mareklach","https://chaos.social/users/benthor","https://mastodon.social/users/djperreault","https://mastodon.art/users/eylul","https://mastodon.opportunis.me/users/bob","https://tootplanet.space/users/Shutsumon","https://toot.cat/users/woozle","https://mastodon.social/users/StephenLB","https://sleeping.town/users/oct2pus","https://mastodon.indie.host/users/stragu","https://social.coop/users/gilscottfitzgerald","https://icosahedron.website/users/joeld","https://mastodon.social/users/hellion","https://cybre.space/users/cooler_ranch","https://mastodon.social/users/kelsonv","https://mastodon.lat/users/scalpol","https://writing.exchange/users/hnb","https://hex.bz/users/Horst","https://mastodon.social/users/weddle","https://maly.io/users/sonya","https://social.coop/users/medusa","https://mastodon.social/users/DystopianK","https://mstdn.io/users/d_io","https://fosstodon.org/users/brandon","https://fosstodon.org/users/Cando","https://mastodon.host/users/panina","https://floss.social/users/tuxether","https://social.tchncs.de/users/suitbertmonz","https://mastodon.social/users/jrt","https://mastodon.social/users/sirikon","https://mstdn.io/users/yabirgb","https://mastodon.cloud/users/FerdiZ","https://mastodon.social/users/carlchenet","https://social.polonkai.eu/users/calendar_social","https://social.polonkai.eu/users/gergely","https://mastodon.social/users/Jelv","https://mastodon.social/users/srinicame","https://cybre.space/users/mastoabed","https://mastodon.social/users/tagomago","https://lgbt.io/users/bootblackCub","https://niu.moe/users/Nopplyy","https://mastodon.social/users/bpugh","https://www.w3.org/ns/activitystreams#Public"],"type":"Article","uploadMedia":null,"url":"https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"} \ No newline at end of file
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "Emoji" : "toot:Emoji",
+ "Hashtag" : "as:Hashtag",
+ "atomUri" : "ostatus:atomUri",
+ "conversation" : "ostatus:conversation",
+ "featured" : "toot:featured",
+ "focalPoint" : {
+ "@container" : "@list",
+ "@id" : "toot:focalPoint"
+ },
+ "inReplyToAtomUri" : "ostatus:inReplyToAtomUri",
+ "manuallyApprovesFollowers" : "as:manuallyApprovesFollowers",
+ "movedTo" : "as:movedTo",
+ "ostatus" : "http://ostatus.org#",
+ "sensitive" : "as:sensitive",
+ "toot" : "http://joinmastodon.org/ns#"
+ }
+ ],
+ "attributedTo" : [
+ "https://baptiste.gelez.xyz/@/BaptisteGelez"
+ ],
+ "cc" : [],
+ "content" : "<p>It has been one month since the last \"This Month in Plume\" article, so it is time for another edition of our monthly changelog!</p>\n<h2>Bug Fixes and Security</h2>\n<p>Let's start with the hidden, but still (very) important changes: bug fixes and security patches.</p>\n<p>First of all, <a href=\"/@/Trinity%20/\" title=\"Trinity \" rel=\"noopener noreferrer\">@Trinity </a> protected us against two major security flaws, called <em>XSS</em> and <em>CSRF</em>. The first one allows the attacker to run malicious code if you visit a Plume page where some of their personal data is present. The second one lets them post data with your Plume account by visiting one of their own website. It is two very common attack, and it is great we are now protected against them!</p>\n<p>The other big change in this area, is that we are now validating the data you are sending before doing anything with it. It means that, for instance, you will no longer be able to register with an empty username and to break everything.</p>\n<p>On the federation side, many issues were reported by <a href=\"/@/kaniini%20/\" title=\"kaniini \" rel=\"noopener noreferrer\">@kaniini </a> and <em>redmatrix</em> (respectively contributing to Pleroma and Hubzilla). By fixing some of them, we made it possible to <a href=\"https://baptiste.gelez.xyz/%7E/KaniiniTestBlog/current-status-of-plume-and-pleroma-federation/\" rel=\"noopener noreferrer\">federate Plume articles to Pleroma</a>!</p>\n<p><a href=\"/@/Trinity%20/\" title=\"Trinity \" rel=\"noopener noreferrer\">@Trinity </a> hopefully noticed that there was a bug in our password check code: we were not checking that your password was correct, but only that the verification process went without errors. Concretely, it means that you could login to any account with any password. I wrote this part of the code when I was still the only contributor to the project, so nobody could review my work. We will now be trying to check every change, especially when it deals with critical parts of Plume, to avoid similar issues in the future, and we I'm really sorry this happened (even if I think nobody exploited it).</p>\n<p><em>Zanfib</em> and <em>stephenburgess8</em> also commited some small bugfixes, improving the general experience.</p>\n<h2>New Features</h2>\n<p>Let's now talk about the features that we introduced during this month.</p>\n<p>One of the most easy to spot is the redesign of Plume, made by <a href=\"/@/Madeorsk.%20/\" title=\"Madeorsk. \" rel=\"noopener noreferrer\">@Madeorsk. </a> I personaly love what he did, it really improved the readability and gave Plume a bit more of identity than the previous design. And he is <a href=\"https://github.com/Plume-org/Plume/pull/104\" rel=\"noopener noreferrer\">still improving it</a>.</p>\n<p>We also enabled Mardown in comment, to let you write more structured and nicely formatted responses.</p>\n<p>As you may have noticed, I have used mentions in this post. Indeed, it is now possible to mention someone in your articles or in comments. It works exactly the same way as in other apps, and you should receive a notification if someone mentionned you.</p>\n<p>A dashboard to manage your blogs has also been introduced. In the future it may be used to manage your drafts, and eventually to show some statistics. The goal is to have a more specific homepage for authors.</p>\n<p>The federation with other ActivityPub softwares, like Mastodon or Pleroma is starting to work quite well, but the federation between Plume instances is far from being complete. However, we started to work on it, and it is now possible to view a distant user profile or blog from your instance, even if only basic informations are fetched yet (the articles are not loaded for instance).</p>\n<p>Another new feature that may not be visible for everyone, is the new NodeInfo endpoint. NodeInfo is a protocol allowing to get informations about a specific federated instance (whatever software it runs). It means that Plume instances can now be listed on sites like <a href=\"https://fediverse.network/plume\" rel=\"noopener noreferrer\">fediverse.network</a>.</p>\n<p>Maybe you wanted to host a Plume instance, but you don't like long install process during which you are just copy/pasting commands that you don't really understand from the documentation. That's why we introduced a setup script: the first you'll launch Plume, it will ask you a few questions and automatically setup your instance in a few minutes. We hope that this feature will help to host small instances, run by non-professional adminsys. You can see a demo of this tool on <a href=\"https://asciinema.org/a/tHktBK5iOd0zTulxmBX7LYQDc?t=32\" rel=\"noopener noreferrer\">asciinema</a>.</p>\n<p>Last but not least, Plume is now translatable! It is already available in English, French, Polish (thanks to <a href=\"/@/m4sk1n)/\" title=\"m4sk1n)\" rel=\"noopener noreferrer\">@m4sk1n)</a>) and German (thanks to <em>bitkeks</em>). If your browser is configured to display pages in these languages, you should normally see the interface in your language. And if your language is not present yet, feel free to <a href=\"https://github.com/Plume-org/Plume/blob/master/INTERNATIONALIZATION.md\" rel=\"noopener noreferrer\">add your translation</a>.</p>\n<h2>Other Changes</h2>\n<p>We also improved the code a lot. We tried to separate each part as much as possible, making it easier to re-use for other projects. For instance, our database code is now isolated from the rest of the app, which means it will be easier to make import tools from other blogging engines. Some parts of the code are even shared with another project, <a href=\"https://github.com/Aardwolf-Social/aardwolf\" rel=\"noopener noreferrer\">Aardwolf</a> a federated Facebook alternative. For instance, both of our projects use the same internationalization code, and once Aardwolf will implement federation, this part of the code will probably be shared too. Since the WebFinger module (used to find new users and blogs) and the CSRF protection code (see the \"Bug fixes and Security\" section) have been isolated in their own modules, they may be shared by both projects too.</p>\n<p>We also worked a lot on documentation. We now have articles explaining how to setup your Plume instance on various operating systems, but also documenting the translation process. I want to thank <em>BanjoFox</em> (who imported some documentation from their project, Aardwolf, as the setup is quite similar), <em>Kushal</em> and <a href=\"/@/gled@plume.mastodon.host%20/\" title=\"gled@plume.mastodon.host \" rel=\"noopener noreferrer\">@gled@plume.mastodon.host </a> for working on this.</p>\n<p>As you can see, there were many changes this month, but there still a lot to do. Your help will of course be welcome. If you want to contribute to the code, translate Plume in your language, write some documentation, or anything else (or even if you're just curious about the project), feel free to join our Matrix room: <a href=\"https://riot.im/app/#/room/#plume:disroot.org\" rel=\"noopener noreferrer\">#plume:disroot.org</a>. Otherwise, as <em>BanjoFox</em> <a href=\"https://glitch.social/@aardwolf/100329435838406278\" rel=\"noopener noreferrer\">said on the <em>Aardwolf Team</em> Mastodon account</a>, talking about the project around you is one of the easiest way to help.</p>\n",
+ "id" : "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/",
+ "likes" : null,
+ "name" : "This Month in Plume: June 2018",
+ "published" : "2018-07-10T20:16:24.087622Z",
+ "shares" : null,
+ "source" : null,
+ "tag" : [
+ {
+ "href" : "https://baptiste.gelez.xyz/@/Trinity",
+ "name" : "@Trinity",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://baptiste.gelez.xyz/@/kaniini/",
+ "name" : "@kaniini",
+ "type" : "Mention"
+ },
+ {
+ "href" : "https://baptiste.gelez.xyz/@/Trinity",
+ "name" : "@Trinity",
+ "type" : "Mention"
+ }
+ ],
+ "to" : [
+ "https://unixcorn.xyz/users/Bat",
+ "https://mastodon.host/users/federationbot",
+ "https://social.tcit.fr/users/tcit",
+ "https://framapiaf.org/users/qwerty",
+ "https://mastodon.social/users/lthms",
+ "https://eldritch.cafe/users/Nausicaa",
+ "https://imaginair.es/users/Elanndelh",
+ "https://framapiaf.org/users/Drulac",
+ "https://mastodon.partipirate.org/users/NicolasConstant",
+ "https://aleph.land/users/Madeorsk",
+ "https://maly.io/users/Troll",
+ "https://hostux.social/users/superjey",
+ "https://mamot.fr/users/Phigger",
+ "https://mastodon.social/users/wakest",
+ "https://social.coop/users/wakest",
+ "https://unixcorn.xyz/users/Ce_lo",
+ "https://social.art-software.fr/users/Electron",
+ "https://framapiaf.org/users/Quenti",
+ "https://toot.plus.yt/users/Djyp",
+ "https://mastodon.social/users/brainblasted",
+ "https://social.mochi.academy/users/Ambraven",
+ "https://social.hacktivis.me/users/lanodan",
+ "https://mastodon.eliotberriot.com/users/eliotberriot",
+ "https://edolas.world/users/0x1C3B00DA",
+ "https://toot.cafe/users/zack",
+ "https://manowar.social/users/zatnosk",
+ "https://eldritch.cafe/users/fluffy",
+ "https://mastodon.social/users/david_ross",
+ "https://kosmos.social/users/xiroux",
+ "https://mastodon.art/users/EmergencyBattle",
+ "https://mastodon.social/users/trwnh",
+ "https://octodon.social/users/pybyte",
+ "https://anticapitalist.party/users/Trinity",
+ "https://mstdn.mx/users/xavavu",
+ "https://baptiste.gelez.xyz/@/m4sk1n",
+ "https://eldritch.cafe/users/milia",
+ "https://mastodon.zaclys.com/users/arx",
+ "https://toot.cafe/users/sivy",
+ "https://mastodon.social/users/ortegacmanuel",
+ "https://mastodon.observer/users/stephen",
+ "https://octodon.social/users/chloe",
+ "https://unixcorn.xyz/users/AmauryPi",
+ "https://cybre.space/users/rick_777",
+ "https://mastodon.social/users/wezm",
+ "https://baptiste.gelez.xyz/@/idlesong",
+ "https://mamot.fr/users/dr4Ke",
+ "https://imaginair.es/users/Phigger",
+ "https://mamot.fr/users/dlink",
+ "https://anticapitalist.party/users/a000d4f7a91939d0e71df1646d7a48",
+ "https://framapiaf.org/users/PhieLaidMignon",
+ "https://mastodon.social/users/y6nH",
+ "https://crazynoisybizarre.town/users/FederationBot",
+ "https://social.weho.st/users/dvn",
+ "https://mastodon.art/users/Wolthera",
+ "https://diaspodon.fr/users/dada",
+ "https://pachyder.me/users/Lanza",
+ "https://mastodon.xyz/users/ag",
+ "https://aleph.land/users/yahananxie",
+ "https://mstdn.io/users/chablis_social",
+ "https://mastodon.gougere.fr/users/fabien",
+ "https://functional.cafe/users/otini",
+ "https://social.coop/users/bhaugen",
+ "https://octodon.social/users/donblanco",
+ "https://chaos.social/users/astro",
+ "https://pachyder.me/users/sibear",
+ "https://mamot.fr/users/yohann",
+ "https://social.wxcafe.net/users/Bat",
+ "https://mastodon.social/users/dansup",
+ "https://chaos.social/users/juh",
+ "https://scifi.fyi/users/paeneultima",
+ "https://hostux.social/users/Deuchnord",
+ "https://mstdn.fr/users/taziden",
+ "https://mamot.fr/users/PifyZ",
+ "https://mastodon.social/users/plantabaja",
+ "https://mastodon.social/users/gitzgrog",
+ "https://mastodon.social/users/Syluban",
+ "https://masto.pt/users/eloisa",
+ "https://pleroma.soykaf.com/users/notclacke",
+ "https://mastodon.social/users/SiegfriedEhret",
+ "https://writing.exchange/users/write_as",
+ "https://mstdn.io/users/shellkr",
+ "https://mastodon.uy/users/jorge",
+ "https://mastodon.technology/users/bobstechsite",
+ "https://mastodon.social/users/hinterwaeldler",
+ "https://mastodon.xyz/users/mgdelacroix",
+ "https://mastodon.cloud/users/jjatria",
+ "https://baptiste.gelez.xyz/@/Jade/",
+ "https://edolas.world/users/pfm",
+ "https://mstdn.io/users/jort",
+ "https://mastodon.social/users/andreipetcu",
+ "https://mastodon.technology/users/0xf00fc7c8",
+ "https://mastodon.social/users/khanate",
+ "https://mastodon.technology/users/francois",
+ "https://mastodon.social/users/glherrmann",
+ "https://mastodon.host/users/gled",
+ "https://social.holdmybeer.solutions/users/kemonine",
+ "https://scholar.social/users/bgcarlisle",
+ "https://mastodon.social/users/oldgun",
+ "https://baptiste.gelez.xyz/@/snoe/",
+ "https://mastodon.at/users/switchingsocial",
+ "https://scifi.fyi/users/BrokenBiscuit",
+ "https://dev.glitch.social/users/hoodie",
+ "https://todon.nl/users/paulfree14",
+ "https://mastodon.social/users/aadilayub",
+ "https://social.fsck.club/users/anarchosaurus",
+ "https://mastodonten.de/users/GiantG",
+ "https://mastodon.technology/users/cj",
+ "https://cybre.space/users/sam",
+ "https://layer8.space/users/silkevicious",
+ "https://mastodon.xyz/users/Jimmyrwx",
+ "https://fosstodon.org/users/danyspin97",
+ "https://mstdn.io/users/cristhyano",
+ "https://mastodon.social/users/vanyok",
+ "https://hulvr.com/users/rook",
+ "https://niu.moe/users/Lucifer",
+ "https://mamot.fr/users/Thibaut",
+ "https://mastodont.cat/users/bgta",
+ "https://mstdn.io/users/hontoni",
+ "https://niu.moe/users/lionirdeadman",
+ "https://functional.cafe/users/phoe",
+ "https://mastodon.social/users/toontoet",
+ "https://mastodon.social/users/danipozo",
+ "https://scholar.social/users/robertson",
+ "https://mastodon.social/users/aldatsa",
+ "https://elekk.xyz/users/maloki",
+ "https://kitty.town/users/nursemchurt",
+ "https://neigh.horse/users/commagray",
+ "https://mastodon.social/users/hirojin",
+ "https://mastodon.xyz/users/mareklach",
+ "https://chaos.social/users/benthor",
+ "https://mastodon.social/users/djperreault",
+ "https://mastodon.art/users/eylul",
+ "https://mastodon.opportunis.me/users/bob",
+ "https://tootplanet.space/users/Shutsumon",
+ "https://toot.cat/users/woozle",
+ "https://mastodon.social/users/StephenLB",
+ "https://sleeping.town/users/oct2pus",
+ "https://mastodon.indie.host/users/stragu",
+ "https://social.coop/users/gilscottfitzgerald",
+ "https://icosahedron.website/users/joeld",
+ "https://mastodon.social/users/hellion",
+ "https://cybre.space/users/cooler_ranch",
+ "https://mastodon.social/users/kelsonv",
+ "https://mastodon.lat/users/scalpol",
+ "https://writing.exchange/users/hnb",
+ "https://hex.bz/users/Horst",
+ "https://mastodon.social/users/weddle",
+ "https://maly.io/users/sonya",
+ "https://social.coop/users/medusa",
+ "https://mastodon.social/users/DystopianK",
+ "https://mstdn.io/users/d_io",
+ "https://fosstodon.org/users/brandon",
+ "https://fosstodon.org/users/Cando",
+ "https://mastodon.host/users/panina",
+ "https://floss.social/users/tuxether",
+ "https://social.tchncs.de/users/suitbertmonz",
+ "https://mastodon.social/users/jrt",
+ "https://mastodon.social/users/sirikon",
+ "https://mstdn.io/users/yabirgb",
+ "https://mastodon.cloud/users/FerdiZ",
+ "https://mastodon.social/users/carlchenet",
+ "https://social.polonkai.eu/users/calendar_social",
+ "https://social.polonkai.eu/users/gergely",
+ "https://mastodon.social/users/Jelv",
+ "https://mastodon.social/users/srinicame",
+ "https://cybre.space/users/mastoabed",
+ "https://mastodon.social/users/tagomago",
+ "https://lgbt.io/users/bootblackCub",
+ "https://niu.moe/users/Nopplyy",
+ "https://mastodon.social/users/bpugh",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type" : "Article",
+ "uploadMedia" : null,
+ "url" : "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
+}
diff --git a/test/fixtures/tesla_mock/peertube.moe-vid.json b/test/fixtures/tesla_mock/peertube.moe-vid.json
index 76296eb7d..ceebb90b7 100644
--- a/test/fixtures/tesla_mock/peertube.moe-vid.json
+++ b/test/fixtures/tesla_mock/peertube.moe-vid.json
@@ -1 +1,187 @@
-{"type":"Video","id":"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3","name":"Friday Night","duration":"PT29S","uuid":"df5f464b-be8d-46fb-ad81-2d4c2d1630e3","tag":[{"type":"Hashtag","name":"feels"}],"views":12,"sensitive":false,"commentsEnabled":true,"published":"2018-03-23T16:43:22.988Z","updated":"2018-03-24T16:28:46.002Z","mediaType":"text/markdown","content":"tfw\r\n\r\n\r\nsong is 'my old piano' by diana ross","support":null,"icon":{"type":"Image","url":"https://peertube.moe/static/thumbnails/df5f464b-be8d-46fb-ad81-2d4c2d1630e3.jpg","mediaType":"image/jpeg","width":200,"height":110},"url":[{"type":"Link","mimeType":"video/mp4","href":"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4","width":480,"size":5015880},{"type":"Link","mimeType":"application/x-bittorrent","href":"https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.torrent","width":480},{"type":"Link","mimeType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.torrent&xt=urn:btih:11d3af6b5c812a376c2b29cdbd46e5fb42ee730e&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4","width":480},{"type":"Link","mimeType":"video/mp4","href":"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.mp4","width":360,"size":3620040},{"type":"Link","mimeType":"application/x-bittorrent","href":"https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.torrent","width":360},{"type":"Link","mimeType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.torrent&xt=urn:btih:1c3885b4d7cdb46193b62b9b76e72b1409cfb297&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.mp4","width":360},{"type":"Link","mimeType":"video/mp4","href":"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.mp4","width":240,"size":2305488},{"type":"Link","mimeType":"application/x-bittorrent","href":"https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.torrent","width":240},{"type":"Link","mimeType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.torrent&xt=urn:btih:ac5773352d9e26f982d2da63acfb244f01ccafa4&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.mp4","width":240},{"type":"Link","mimeType":"video/mp4","href":"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.mp4","width":720,"size":7928231},{"type":"Link","mimeType":"application/x-bittorrent","href":"https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.torrent","width":720},{"type":"Link","mimeType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.torrent&xt=urn:btih:b591068f4533c4e2865bb4cbb89887aecccdc523&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.mp4","width":720},{"type":"Link","mimeType":"text/html","href":"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"}],"likes":{"id":"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/likes","type":"OrderedCollection","totalItems":0,"orderedItems":[]},"dislikes":{"id":"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/dislikes","type":"OrderedCollection","totalItems":0,"orderedItems":[]},"shares":{"id":"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/announces","type":"OrderedCollection","totalItems":2,"orderedItems":["https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/announces/465","https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/announces/1"]},"comments":{"id":"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/comments","type":"OrderedCollection","totalItems":0,"orderedItems":[]},"attributedTo":[{"type":"Group","id":"https://peertube.moe/video-channels/5224869f-aa63-4c83-ab3a-87c3a5ac440e"},{"type":"Person","id":"https://peertube.moe/accounts/7even"}],"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":[],"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"RsaSignature2017":"https://w3id.org/security#RsaSignature2017","Hashtag":"as:Hashtag","uuid":"http://schema.org/identifier","category":"http://schema.org/category","licence":"http://schema.org/license","sensitive":"as:sensitive","language":"http://schema.org/inLanguage","views":"http://schema.org/Number","size":"http://schema.org/Number","commentsEnabled":"http://schema.org/Boolean","support":"http://schema.org/Text"},{"likes":{"@id":"as:likes","@type":"@id"},"dislikes":{"@id":"as:dislikes","@type":"@id"},"shares":{"@id":"as:shares","@type":"@id"},"comments":{"@id":"as:comments","@type":"@id"}}]} \ No newline at end of file
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "Hashtag" : "as:Hashtag",
+ "RsaSignature2017" : "https://w3id.org/security#RsaSignature2017",
+ "category" : "http://schema.org/category",
+ "commentsEnabled" : "http://schema.org/Boolean",
+ "language" : "http://schema.org/inLanguage",
+ "licence" : "http://schema.org/license",
+ "sensitive" : "as:sensitive",
+ "size" : "http://schema.org/Number",
+ "support" : "http://schema.org/Text",
+ "uuid" : "http://schema.org/identifier",
+ "views" : "http://schema.org/Number"
+ },
+ {
+ "comments" : {
+ "@id" : "as:comments",
+ "@type" : "@id"
+ },
+ "dislikes" : {
+ "@id" : "as:dislikes",
+ "@type" : "@id"
+ },
+ "likes" : {
+ "@id" : "as:likes",
+ "@type" : "@id"
+ },
+ "shares" : {
+ "@id" : "as:shares",
+ "@type" : "@id"
+ }
+ }
+ ],
+ "attributedTo" : [
+ {
+ "id" : "https://peertube.moe/video-channels/5224869f-aa63-4c83-ab3a-87c3a5ac440e",
+ "type" : "Group"
+ },
+ {
+ "id" : "https://peertube.moe/accounts/7even",
+ "type" : "Person"
+ }
+ ],
+ "cc" : [],
+ "comments" : {
+ "id" : "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/comments",
+ "orderedItems" : [],
+ "totalItems" : 0,
+ "type" : "OrderedCollection"
+ },
+ "commentsEnabled" : true,
+ "content" : "tfw\r\n\r\n\r\nsong is 'my old piano' by diana ross",
+ "dislikes" : {
+ "id" : "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/dislikes",
+ "orderedItems" : [],
+ "totalItems" : 0,
+ "type" : "OrderedCollection"
+ },
+ "duration" : "PT29S",
+ "icon" : {
+ "height" : 110,
+ "mediaType" : "image/jpeg",
+ "type" : "Image",
+ "url" : "https://peertube.moe/static/thumbnails/df5f464b-be8d-46fb-ad81-2d4c2d1630e3.jpg",
+ "width" : 200
+ },
+ "id" : "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3",
+ "likes" : {
+ "id" : "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/likes",
+ "orderedItems" : [],
+ "totalItems" : 0,
+ "type" : "OrderedCollection"
+ },
+ "mediaType" : "text/markdown",
+ "name" : "Friday Night",
+ "published" : "2018-03-23T16:43:22.988Z",
+ "sensitive" : false,
+ "shares" : {
+ "id" : "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/announces",
+ "orderedItems" : [
+ "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/announces/465",
+ "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3/announces/1"
+ ],
+ "totalItems" : 2,
+ "type" : "OrderedCollection"
+ },
+ "support" : null,
+ "tag" : [
+ {
+ "name" : "feels",
+ "type" : "Hashtag"
+ }
+ ],
+ "to" : [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type" : "Video",
+ "updated" : "2018-03-24T16:28:46.002Z",
+ "url" : [
+ {
+ "href" : "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
+ "mimeType" : "video/mp4",
+ "size" : 5015880,
+ "type" : "Link",
+ "width" : 480
+ },
+ {
+ "href" : "https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.torrent",
+ "mimeType" : "application/x-bittorrent",
+ "type" : "Link",
+ "width" : 480
+ },
+ {
+ "href" : "magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.torrent&xt=urn:btih:11d3af6b5c812a376c2b29cdbd46e5fb42ee730e&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
+ "mimeType" : "application/x-bittorrent;x-scheme-handler/magnet",
+ "type" : "Link",
+ "width" : 480
+ },
+ {
+ "href" : "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.mp4",
+ "mimeType" : "video/mp4",
+ "size" : 3620040,
+ "type" : "Link",
+ "width" : 360
+ },
+ {
+ "href" : "https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.torrent",
+ "mimeType" : "application/x-bittorrent",
+ "type" : "Link",
+ "width" : 360
+ },
+ {
+ "href" : "magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.torrent&xt=urn:btih:1c3885b4d7cdb46193b62b9b76e72b1409cfb297&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-360.mp4",
+ "mimeType" : "application/x-bittorrent;x-scheme-handler/magnet",
+ "type" : "Link",
+ "width" : 360
+ },
+ {
+ "href" : "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.mp4",
+ "mimeType" : "video/mp4",
+ "size" : 2305488,
+ "type" : "Link",
+ "width" : 240
+ },
+ {
+ "href" : "https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.torrent",
+ "mimeType" : "application/x-bittorrent",
+ "type" : "Link",
+ "width" : 240
+ },
+ {
+ "href" : "magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.torrent&xt=urn:btih:ac5773352d9e26f982d2da63acfb244f01ccafa4&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-240.mp4",
+ "mimeType" : "application/x-bittorrent;x-scheme-handler/magnet",
+ "type" : "Link",
+ "width" : 240
+ },
+ {
+ "href" : "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.mp4",
+ "mimeType" : "video/mp4",
+ "size" : 7928231,
+ "type" : "Link",
+ "width" : 720
+ },
+ {
+ "href" : "https://peertube.moe/static/torrents/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.torrent",
+ "mimeType" : "application/x-bittorrent",
+ "type" : "Link",
+ "width" : 720
+ },
+ {
+ "href" : "magnet:?xs=https%3A%2F%2Fpeertube.moe%2Fstatic%2Ftorrents%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.torrent&xt=urn:btih:b591068f4533c4e2865bb4cbb89887aecccdc523&dn=Friday+Night&tr=wss%3A%2F%2Fpeertube.moe%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.moe%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.moe%2Fstatic%2Fwebseed%2Fdf5f464b-be8d-46fb-ad81-2d4c2d1630e3-720.mp4",
+ "mimeType" : "application/x-bittorrent;x-scheme-handler/magnet",
+ "type" : "Link",
+ "width" : 720
+ },
+ {
+ "href" : "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3",
+ "mimeType" : "text/html",
+ "type" : "Link"
+ }
+ ],
+ "uuid" : "df5f464b-be8d-46fb-ad81-2d4c2d1630e3",
+ "views" : 12
+}
diff --git a/test/html_test.exs b/test/html_test.exs
index 0a4b4ebbc..f8907c8b4 100644
--- a/test/html_test.exs
+++ b/test/html_test.exs
@@ -237,5 +237,19 @@ defmodule Pleroma.HTMLTest do
assert {:ok, nil} = HTML.extract_first_external_url(object, object.data["content"])
end
+
+ test "skips attachment links" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ status:
+ "<a href=\"https://pleroma.gov/media/d24caa3a498e21e0298377a9ca0149a4f4f8b767178aacf837542282e2d94fb1.png?name=image.png\" class=\"attachment\">image.png</a>"
+ })
+
+ object = Object.normalize(activity)
+
+ assert {:ok, nil} = HTML.extract_first_external_url(object, object.data["content"])
+ end
end
end
diff --git a/test/notification_test.exs b/test/notification_test.exs
index 526f43fab..6add3f7eb 100644
--- a/test/notification_test.exs
+++ b/test/notification_test.exs
@@ -22,6 +22,16 @@ defmodule Pleroma.NotificationTest do
alias Pleroma.Web.Streamer
describe "create_notifications" do
+ test "never returns nil" do
+ user = insert(:user)
+ other_user = insert(:user, %{invisible: true})
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
+ {:ok, activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
+
+ refute {:ok, [nil]} == Notification.create_notifications(activity)
+ end
+
test "creates a notification for an emoji reaction" do
user = insert(:user)
other_user = insert(:user)
diff --git a/test/object/fetcher_test.exs b/test/object/fetcher_test.exs
index c06e91f12..d9098ea1b 100644
--- a/test/object/fetcher_test.exs
+++ b/test/object/fetcher_test.exs
@@ -26,6 +26,46 @@ defmodule Pleroma.Object.FetcherTest do
:ok
end
+ describe "error cases" do
+ setup do
+ mock(fn
+ %{method: :get, url: "https://social.sakamoto.gq/notice/9wTkLEnuq47B25EehM"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json")
+ }
+
+ %{method: :get, url: "https://social.sakamoto.gq/users/eal"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/fetch_mocks/eal.json")
+ }
+
+ %{method: :get, url: "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/fetch_mocks/104410921027210069.json")
+ }
+
+ %{method: :get, url: "https://busshi.moe/users/tuxcrafting"} ->
+ %Tesla.Env{
+ status: 500
+ }
+ end)
+
+ :ok
+ end
+
+ @tag capture_log: true
+ test "it works when fetching the OP actor errors out" do
+ # Here we simulate a case where the author of the OP can't be read
+ assert {:ok, _} =
+ Fetcher.fetch_object_from_id(
+ "https://social.sakamoto.gq/notice/9wTkLEnuq47B25EehM"
+ )
+ end
+ end
+
describe "max thread distance restriction" do
@ap_id "http://mastodon.example.org/@admin/99541947525187367"
setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
diff --git a/test/user_test.exs b/test/user_test.exs
index 9b66f3f51..7126bb539 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -597,6 +597,31 @@ defmodule Pleroma.UserTest do
refute user.last_refreshed_at == orig_user.last_refreshed_at
end
+ test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
+ a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
+
+ orig_user =
+ insert(
+ :user,
+ local: false,
+ nickname: "admin@mastodon.example.org",
+ ap_id: "http://mastodon.example.org/users/harinezumigari",
+ last_refreshed_at: a_week_ago
+ )
+
+ assert orig_user.last_refreshed_at == a_week_ago
+
+ {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
+
+ assert user.inbox
+
+ refute user.id == orig_user.id
+
+ orig_user = User.get_by_id(orig_user.id)
+
+ assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
+ end
+
@tag capture_log: true
test "it returns the old user if stale, but unfetchable" do
a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index be7ab2ae4..575e0c5db 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -992,54 +992,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
- describe "blocking" do
- test "reverts block activity on error" do
- [blocker, blocked] = insert_list(2, :user)
-
- with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
- assert {:error, :reverted} = ActivityPub.block(blocker, blocked)
- end
-
- assert Repo.aggregate(Activity, :count, :id) == 0
- assert Repo.aggregate(Object, :count, :id) == 0
- end
-
- test "creates a block activity" do
- clear_config([:instance, :federating], true)
- blocker = insert(:user)
- blocked = insert(:user)
-
- with_mock Pleroma.Web.Federator,
- publish: fn _ -> nil end do
- {:ok, activity} = ActivityPub.block(blocker, blocked)
-
- assert activity.data["type"] == "Block"
- assert activity.data["actor"] == blocker.ap_id
- assert activity.data["object"] == blocked.ap_id
-
- assert called(Pleroma.Web.Federator.publish(activity))
- end
- end
-
- test "works with outgoing blocks disabled, but doesn't federate" do
- clear_config([:instance, :federating], true)
- clear_config([:activitypub, :outgoing_blocks], false)
- blocker = insert(:user)
- blocked = insert(:user)
-
- with_mock Pleroma.Web.Federator,
- publish: fn _ -> nil end do
- {:ok, activity} = ActivityPub.block(blocker, blocked)
-
- assert activity.data["type"] == "Block"
- assert activity.data["actor"] == blocker.ap_id
- assert activity.data["object"] == blocked.ap_id
-
- refute called(Pleroma.Web.Federator.publish(:_))
- end
- end
- end
-
describe "timeline post-processing" do
test "it filters broken threads" do
user1 = insert(:user)
diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs
index 1a13699be..6867c9853 100644
--- a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs
+++ b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs
@@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
describe "with new user" do
test "it allows posts without links" do
- user = insert(:user)
+ user = insert(:user, local: false)
assert user.note_count == 0
@@ -45,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
end
test "it disallows posts with links" do
- user = insert(:user)
+ user = insert(:user, local: false)
assert user.note_count == 0
@@ -55,6 +55,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
{:reject, _} = AntiLinkSpamPolicy.filter(message)
end
+
+ test "it allows posts with links for local users" do
+ user = insert(:user)
+
+ assert user.note_count == 0
+
+ message =
+ @linkful_message
+ |> Map.put("actor", user.ap_id)
+
+ {:ok, _message} = AntiLinkSpamPolicy.filter(message)
+ end
end
describe "with old user" do
diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs
index 770a8dcf8..f38bf7e08 100644
--- a/test/web/activity_pub/object_validator_test.exs
+++ b/test/web/activity_pub/object_validator_test.exs
@@ -654,4 +654,31 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
assert {:error, _cng} = ObjectValidator.validate(update, [])
end
end
+
+ describe "blocks" do
+ setup do
+ user = insert(:user, local: false)
+ blocked = insert(:user)
+
+ {:ok, valid_block, []} = Builder.block(user, blocked)
+
+ %{user: user, valid_block: valid_block}
+ end
+
+ test "validates a basic object", %{
+ valid_block: valid_block
+ } do
+ assert {:ok, _block, []} = ObjectValidator.validate(valid_block, [])
+ end
+
+ test "returns an error if we don't know the blocked user", %{
+ valid_block: valid_block
+ } do
+ block =
+ valid_block
+ |> Map.put("object", "https://gensokyo.2hu/users/raymoo")
+
+ assert {:error, _cng} = ObjectValidator.validate(block, [])
+ end
+ end
end
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
index 12c9ef1da..2649b060a 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -64,6 +64,47 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
end
end
+ describe "blocking users" do
+ setup do
+ user = insert(:user)
+ blocked = insert(:user)
+ User.follow(blocked, user)
+ User.follow(user, blocked)
+
+ {:ok, block_data, []} = Builder.block(user, blocked)
+ {:ok, block, _meta} = ActivityPub.persist(block_data, local: true)
+
+ %{user: user, blocked: blocked, block: block}
+ end
+
+ test "it unfollows and blocks", %{user: user, blocked: blocked, block: block} do
+ assert User.following?(user, blocked)
+ assert User.following?(blocked, user)
+
+ {:ok, _, _} = SideEffects.handle(block)
+
+ refute User.following?(user, blocked)
+ refute User.following?(blocked, user)
+ assert User.blocks?(user, blocked)
+ end
+
+ test "it blocks but does not unfollow if the relevant setting is set", %{
+ user: user,
+ blocked: blocked,
+ block: block
+ } do
+ clear_config([:activitypub, :unfollow_blocked], false)
+ assert User.following?(user, blocked)
+ assert User.following?(blocked, user)
+
+ {:ok, _, _} = SideEffects.handle(block)
+
+ refute User.following?(user, blocked)
+ assert User.following?(blocked, user)
+ assert User.blocks?(user, blocked)
+ end
+ end
+
describe "update users" do
setup do
user = insert(:user)
@@ -242,8 +283,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
{:ok, like} = CommonAPI.favorite(user, post.id)
{:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
{:ok, announce} = CommonAPI.repeat(post.id, user)
- {:ok, block} = ActivityPub.block(user, poster)
- User.block(user, poster)
+ {:ok, block} = CommonAPI.block(user, poster)
{:ok, undo_data, _meta} = Builder.undo(user, like)
{:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
@@ -549,10 +589,29 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
end
test "it streams out the announce", %{announce: announce} do
- with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], stream_out: fn _ -> nil end do
+ with_mocks([
+ {
+ Pleroma.Web.Streamer,
+ [],
+ [
+ stream: fn _, _ -> nil end
+ ]
+ },
+ {
+ Pleroma.Web.Push,
+ [],
+ [
+ send: fn _ -> nil end
+ ]
+ }
+ ]) do
{:ok, announce, _} = SideEffects.handle(announce)
- assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(announce))
+ assert called(
+ Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], announce)
+ )
+
+ assert called(Pleroma.Web.Push.send(:_))
end
end
end
diff --git a/test/web/activity_pub/transmogrifier/block_handling_test.exs b/test/web/activity_pub/transmogrifier/block_handling_test.exs
new file mode 100644
index 000000000..71f1a0ed5
--- /dev/null
+++ b/test/web/activity_pub/transmogrifier/block_handling_test.exs
@@ -0,0 +1,63 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Activity
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+
+ import Pleroma.Factory
+
+ test "it works for incoming blocks" do
+ user = insert(:user)
+
+ data =
+ File.read!("test/fixtures/mastodon-block-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
+
+ blocker = insert(:user, ap_id: data["actor"])
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["type"] == "Block"
+ assert data["object"] == user.ap_id
+ assert data["actor"] == "http://mastodon.example.org/users/admin"
+
+ assert User.blocks?(blocker, user)
+ end
+
+ test "incoming blocks successfully tear down any follow relationship" do
+ blocker = insert(:user)
+ blocked = insert(:user)
+
+ data =
+ File.read!("test/fixtures/mastodon-block-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", blocked.ap_id)
+ |> Map.put("actor", blocker.ap_id)
+
+ {:ok, blocker} = User.follow(blocker, blocked)
+ {:ok, blocked} = User.follow(blocked, blocker)
+
+ assert User.following?(blocker, blocked)
+ assert User.following?(blocked, blocker)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["type"] == "Block"
+ assert data["object"] == blocked.ap_id
+ assert data["actor"] == blocker.ap_id
+
+ blocker = User.get_cached_by_ap_id(data["actor"])
+ blocked = User.get_cached_by_ap_id(data["object"])
+
+ assert User.blocks?(blocker, blocked)
+
+ refute User.following?(blocker, blocked)
+ refute User.following?(blocked, blocker)
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 100821056..6a53fd3f0 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -445,56 +445,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert [^pending_follower] = User.get_follow_requests(user)
end
- test "it works for incoming blocks" do
- user = insert(:user)
-
- data =
- File.read!("test/fixtures/mastodon-block-activity.json")
- |> Poison.decode!()
- |> Map.put("object", user.ap_id)
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["type"] == "Block"
- assert data["object"] == user.ap_id
- assert data["actor"] == "http://mastodon.example.org/users/admin"
-
- blocker = User.get_cached_by_ap_id(data["actor"])
-
- assert User.blocks?(blocker, user)
- end
-
- test "incoming blocks successfully tear down any follow relationship" do
- blocker = insert(:user)
- blocked = insert(:user)
-
- data =
- File.read!("test/fixtures/mastodon-block-activity.json")
- |> Poison.decode!()
- |> Map.put("object", blocked.ap_id)
- |> Map.put("actor", blocker.ap_id)
-
- {:ok, blocker} = User.follow(blocker, blocked)
- {:ok, blocked} = User.follow(blocked, blocker)
-
- assert User.following?(blocker, blocked)
- assert User.following?(blocked, blocker)
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["type"] == "Block"
- assert data["object"] == blocked.ap_id
- assert data["actor"] == blocker.ap_id
-
- blocker = User.get_cached_by_ap_id(data["actor"])
- blocked = User.get_cached_by_ap_id(data["object"])
-
- assert User.blocks?(blocker, blocked)
-
- refute User.following?(blocker, blocked)
- refute User.following?(blocked, blocker)
- end
-
test "it works for incoming accepts which were pre-accepted" do
follower = insert(:user)
followed = insert(:user)
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
index 15f03f193..2f9ecb5a3 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/web/activity_pub/utils_test.exs
@@ -27,16 +27,6 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
end
end
- describe "fetch the latest Block" do
- test "fetches the latest Block activity" do
- blocker = insert(:user)
- blocked = insert(:user)
- {:ok, activity} = ActivityPub.block(blocker, blocked)
-
- assert activity == Utils.fetch_latest_block(blocker, blocked)
- end
- end
-
describe "determine_explicit_mentions()" do
test "works with an object that has mentions" do
object = %{
@@ -344,9 +334,9 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
user1 = insert(:user)
user2 = insert(:user)
- assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
- assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
- assert {:ok, %Activity{} = activity} = ActivityPub.block(user1, user2)
+ assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
+ assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
+ assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2)
assert Utils.fetch_latest_block(user1, user2) == activity
end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 6bd26050e..fc3bb845d 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -25,6 +25,52 @@ defmodule Pleroma.Web.CommonAPITest do
setup do: clear_config([:instance, :limit])
setup do: clear_config([:instance, :max_pinned_statuses])
+ describe "blocking" do
+ setup do
+ blocker = insert(:user)
+ blocked = insert(:user)
+ User.follow(blocker, blocked)
+ User.follow(blocked, blocker)
+ %{blocker: blocker, blocked: blocked}
+ end
+
+ test "it blocks and federates", %{blocker: blocker, blocked: blocked} do
+ clear_config([:instance, :federating], true)
+
+ with_mock Pleroma.Web.Federator,
+ publish: fn _ -> nil end do
+ assert {:ok, block} = CommonAPI.block(blocker, blocked)
+
+ assert block.local
+ assert User.blocks?(blocker, blocked)
+ refute User.following?(blocker, blocked)
+ refute User.following?(blocked, blocker)
+
+ assert called(Pleroma.Web.Federator.publish(block))
+ end
+ end
+
+ test "it blocks and does not federate if outgoing blocks are disabled", %{
+ blocker: blocker,
+ blocked: blocked
+ } do
+ clear_config([:instance, :federating], true)
+ clear_config([:activitypub, :outgoing_blocks], false)
+
+ with_mock Pleroma.Web.Federator,
+ publish: fn _ -> nil end do
+ assert {:ok, block} = CommonAPI.block(blocker, blocked)
+
+ assert block.local
+ assert User.blocks?(blocker, blocked)
+ refute User.following?(blocker, blocked)
+ refute User.following?(blocked, blocker)
+
+ refute called(Pleroma.Web.Federator.publish(block))
+ end
+ end
+ end
+
describe "posting chat messages" do
setup do: clear_config([:instance, :chat_limit])
diff --git a/test/web/masto_fe_controller_test.exs b/test/web/masto_fe_controller_test.exs
index 1d107d56c..f3b54b5f2 100644
--- a/test/web/masto_fe_controller_test.exs
+++ b/test/web/masto_fe_controller_test.exs
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.MastodonAPI.MastoFEController do
assert _result = json_response(conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
- assert user.settings == %{"programming" => "socks"}
+ assert user.mastofe_settings == %{"programming" => "socks"}
end
describe "index/2 redirections" do
diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs
index ebfcedd01..260ad2306 100644
--- a/test/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/web/mastodon_api/controllers/account_controller_test.exs
@@ -780,7 +780,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
conn
- |> put_req_header("content-type", "application/json")
|> post("/api/v1/accounts/#{other_user.id}/mute")
|> json_response_and_validate_schema(200)
diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs
index 5cbadf0fc..f90a0c273 100644
--- a/test/web/mastodon_api/views/status_view_test.exs
+++ b/test/web/mastodon_api/views/status_view_test.exs
@@ -226,7 +226,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
expires_at: nil,
direct_conversation_id: nil,
thread_muted: false,
- emoji_reactions: []
+ emoji_reactions: [],
+ parent_visible: false
}
}
@@ -620,4 +621,20 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
assert status.visibility == "list"
end
+
+ test "has a field for parent visibility" do
+ user = insert(:user)
+ poster = insert(:user)
+
+ {:ok, invisible} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
+
+ {:ok, visible} =
+ CommonAPI.post(poster, %{status: "hey", visibility: "private", in_reply_to_id: invisible.id})
+
+ status = StatusView.render("show.json", activity: visible, for: user)
+ refute status.pleroma.parent_visible
+
+ status = StatusView.render("show.json", activity: visible, for: poster)
+ assert status.pleroma.parent_visible
+ end
end
diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs
index 8b3b6177d..06b33607f 100644
--- a/test/web/node_info_test.exs
+++ b/test/web/node_info_test.exs
@@ -142,7 +142,8 @@ defmodule Pleroma.Web.NodeInfoTest do
"shareable_emoji_packs",
"multifetch",
"pleroma_emoji_reactions",
- "pleroma:api/v1/notifications:include_types_filter"
+ "pleroma:api/v1/notifications:include_types_filter",
+ "pleroma_chat_messages"
]
assert MapSet.subset?(
diff --git a/test/web/preload/instance_test.exs b/test/web/preload/instance_test.exs
index 42a0d87bc..a46f28312 100644
--- a/test/web/preload/instance_test.exs
+++ b/test/web/preload/instance_test.exs
@@ -8,7 +8,7 @@ defmodule Pleroma.Web.Preload.Providers.InstanceTest do
setup do: {:ok, Instance.generate_terms(nil)}
- test "it renders the info", %{"/api/v1/instance": info} do
+ test "it renders the info", %{"/api/v1/instance" => info} do
assert %{
description: description,
email: "admin@example.com",
@@ -18,14 +18,25 @@ defmodule Pleroma.Web.Preload.Providers.InstanceTest do
assert String.equivalent?(description, "Pleroma: An efficient and flexible fediverse server")
end
- test "it renders the panel", %{"/instance/panel.html": panel} do
+ test "it renders the panel", %{"/instance/panel.html" => panel} do
assert String.contains?(
panel,
"<p>Welcome to <a href=\"https://pleroma.social\" target=\"_blank\">Pleroma!</a></p>"
)
end
- test "it renders the node_info", %{"/nodeinfo/2.0": nodeinfo} do
+ test "it works with overrides" do
+ clear_config([:instance, :static_dir], "test/fixtures/preload_static")
+
+ %{"/instance/panel.html" => panel} = Instance.generate_terms(nil)
+
+ assert String.contains?(
+ panel,
+ "HEY!"
+ )
+ end
+
+ test "it renders the node_info", %{"/nodeinfo/2.0.json" => nodeinfo} do
%{
metadata: metadata,
version: "2.0"
diff --git a/test/web/preload/status_net_test.exs b/test/web/preload/status_net_test.exs
index ab6823a7e..df7acdb11 100644
--- a/test/web/preload/status_net_test.exs
+++ b/test/web/preload/status_net_test.exs
@@ -8,7 +8,8 @@ defmodule Pleroma.Web.Preload.Providers.StatusNetTest do
setup do: {:ok, StatusNet.generate_terms(nil)}
- test "it renders the info", %{"/api/statusnet/config.json": info} do
- assert info =~ "<name>Pleroma</name>"
+ test "it renders the info", %{"/api/statusnet/config.json" => info} do
+ assert {:ok, res} = Jason.decode(info)
+ assert res["site"]
end
end
diff --git a/test/web/preload/timeline_test.exs b/test/web/preload/timeline_test.exs
index da6a3aded..fea95a6a4 100644
--- a/test/web/preload/timeline_test.exs
+++ b/test/web/preload/timeline_test.exs
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.Preload.Providers.TimelineTest do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Preload.Providers.Timelines
- @public_url :"/api/v1/timelines/public"
+ @public_url "/api/v1/timelines/public"
describe "unauthenticated timeliness when restricted" do
setup do
diff --git a/test/web/preload/user_test.exs b/test/web/preload/user_test.exs
index 99232cdfa..83f065e27 100644
--- a/test/web/preload/user_test.exs
+++ b/test/web/preload/user_test.exs
@@ -9,13 +9,11 @@ defmodule Pleroma.Web.Preload.Providers.UserTest do
describe "returns empty when user doesn't exist" do
test "nil user specified" do
- refute User.generate_terms(%{user: nil})
- |> Map.has_key?("/api/v1/accounts")
+ assert User.generate_terms(%{user: nil}) == %{}
end
test "missing user specified" do
- refute User.generate_terms(%{user: :not_a_user})
- |> Map.has_key?("/api/v1/accounts")
+ assert User.generate_terms(%{user: :not_a_user}) == %{}
end
end
@@ -23,11 +21,13 @@ defmodule Pleroma.Web.Preload.Providers.UserTest do
setup do
user = insert(:user)
- {:ok, User.generate_terms(%{user: user})}
+ terms = User.generate_terms(%{user: user})
+ %{terms: terms, user: user}
end
- test "account is rendered", %{"/api/v1/accounts": accounts} do
- assert %{acct: user, username: user} = accounts
+ test "account is rendered", %{terms: terms, user: user} do
+ account = terms["/api/v1/accounts/#{user.id}"]
+ assert %{acct: user, username: user} = account
end
end
end
diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs
index 245f6e63f..dfe341b34 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/web/streamer/streamer_test.exs
@@ -116,6 +116,18 @@ defmodule Pleroma.Web.StreamerTest do
refute Streamer.filtered_by_user?(user, announce)
end
+ test "it does not stream announces of the user's own posts in the 'user' stream", %{
+ user: user
+ } do
+ Streamer.get_topic_and_add_socket("user", user)
+
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
+ {:ok, announce} = CommonAPI.repeat(activity.id, other_user)
+
+ assert Streamer.filtered_by_user?(user, announce)
+ end
+
test "it streams boosts of mastodon user in the 'user' stream", %{user: user} do
Streamer.get_topic_and_add_socket("user", user)