forked from AkkomaGang/akkoma
Merge branch 'develop' into gun
This commit is contained in:
commit
13918cb545
56 changed files with 860 additions and 223 deletions
|
@ -72,8 +72,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- User notification settings: Add `privacy_option` option.
|
- User notification settings: Add `privacy_option` option.
|
||||||
- Support for custom Elixir modules (such as MRF policies)
|
- Support for custom Elixir modules (such as MRF policies)
|
||||||
- User settings: Add _This account is a_ option.
|
- User settings: Add _This account is a_ option.
|
||||||
|
- A new users admin digest email
|
||||||
- OAuth: admin scopes support (relevant setting: `[:auth, :enforce_oauth_admin_scope_usage]`).
|
- OAuth: admin scopes support (relevant setting: `[:auth, :enforce_oauth_admin_scope_usage]`).
|
||||||
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma won’t start. For hackney OTP update is not required.
|
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma won’t start. For hackney OTP update is not required.
|
||||||
|
- Add an option `authorized_fetch_mode` to require HTTP signatures for AP fetches.
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
|
|
||||||
|
@ -115,6 +117,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Configuration: `feed.logo` option for tag feed.
|
- Configuration: `feed.logo` option for tag feed.
|
||||||
- Tag feed: `/tags/:tag.rss` - list public statuses by hashtag.
|
- Tag feed: `/tags/:tag.rss` - list public statuses by hashtag.
|
||||||
- Mastodon API: Add `reacted` property to `emoji_reactions`
|
- Mastodon API: Add `reacted` property to `emoji_reactions`
|
||||||
|
- Pleroma API: Add reactions for a single emoji.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -49,7 +49,8 @@
|
||||||
config :pleroma, Pleroma.Repo,
|
config :pleroma, Pleroma.Repo,
|
||||||
types: Pleroma.PostgresTypes,
|
types: Pleroma.PostgresTypes,
|
||||||
telemetry_event: [Pleroma.Repo.Instrumenter],
|
telemetry_event: [Pleroma.Repo.Instrumenter],
|
||||||
migration_lock: nil
|
migration_lock: nil,
|
||||||
|
parameters: [gin_fuzzy_search_limit: "500"]
|
||||||
|
|
||||||
config :pleroma, Pleroma.Captcha,
|
config :pleroma, Pleroma.Captcha,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
@ -304,7 +305,8 @@
|
||||||
unfollow_blocked: true,
|
unfollow_blocked: true,
|
||||||
outgoing_blocks: true,
|
outgoing_blocks: true,
|
||||||
follow_handshake_timeout: 500,
|
follow_handshake_timeout: 500,
|
||||||
sign_object_fetches: true
|
sign_object_fetches: true,
|
||||||
|
authorized_fetch_mode: false
|
||||||
|
|
||||||
config :pleroma, :streamer,
|
config :pleroma, :streamer,
|
||||||
workers: 3,
|
workers: 3,
|
||||||
|
@ -458,13 +460,15 @@
|
||||||
transmogrifier: 20,
|
transmogrifier: 20,
|
||||||
scheduled_activities: 10,
|
scheduled_activities: 10,
|
||||||
background: 5,
|
background: 5,
|
||||||
attachments_cleanup: 5
|
attachments_cleanup: 5,
|
||||||
|
new_users_digest: 1
|
||||||
],
|
],
|
||||||
crontab: [
|
crontab: [
|
||||||
{"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
|
{"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
|
||||||
{"0 * * * *", Pleroma.Workers.Cron.StatsWorker},
|
{"0 * * * *", Pleroma.Workers.Cron.StatsWorker},
|
||||||
{"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker},
|
{"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker},
|
||||||
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker}
|
{"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
|
||||||
|
{"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}
|
||||||
]
|
]
|
||||||
|
|
||||||
config :pleroma, :workers,
|
config :pleroma, :workers,
|
||||||
|
@ -538,6 +542,8 @@
|
||||||
text_muted_color: "#b9b9ba"
|
text_muted_color: "#b9b9ba"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: false
|
||||||
|
|
||||||
config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics"
|
config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics"
|
||||||
|
|
||||||
config :pleroma, Pleroma.ScheduledActivity,
|
config :pleroma, Pleroma.ScheduledActivity,
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
%{
|
%{
|
||||||
key: :versions,
|
key: :versions,
|
||||||
type: {:list, :atom},
|
type: {:list, :atom},
|
||||||
description: "List of TLS version to use",
|
description: "List of TLS versions to use",
|
||||||
suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"]
|
suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -534,7 +534,8 @@
|
||||||
%{
|
%{
|
||||||
key: :description,
|
key: :description,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "The instance's description, can be seen in nodeinfo and /api/v1/instance",
|
description:
|
||||||
|
"The instance's description. It can be seen in nodeinfo and `/api/v1/instance`",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"Very cool instance"
|
"Very cool instance"
|
||||||
]
|
]
|
||||||
|
@ -770,7 +771,7 @@
|
||||||
key: :cleanup_attachments,
|
key: :cleanup_attachments,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: """
|
description: """
|
||||||
"Enable to remove associated attachments when status is removed.
|
Enable to remove associated attachments when status is removed.
|
||||||
This will not affect duplicates and attachments without status.
|
This will not affect duplicates and attachments without status.
|
||||||
Enabling this will increase load to database when deleting statuses on larger instances.
|
Enabling this will increase load to database when deleting statuses on larger instances.
|
||||||
"""
|
"""
|
||||||
|
@ -838,7 +839,7 @@
|
||||||
%{
|
%{
|
||||||
key: :healthcheck,
|
key: :healthcheck,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "If enabled, system data will be shown on /api/pleroma/healthcheck"
|
description: "If enabled, system data will be shown on `/api/pleroma/healthcheck`"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :remote_post_retention_days,
|
key: :remote_post_retention_days,
|
||||||
|
@ -1296,14 +1297,14 @@
|
||||||
%{
|
%{
|
||||||
key: :media_removal,
|
key: :media_removal,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description: "List of instances to remove medias from",
|
description: "List of instances to strip media attachments from",
|
||||||
suggestions: ["example.com", "*.example.com"]
|
suggestions: ["example.com", "*.example.com"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :media_nsfw,
|
key: :media_nsfw,
|
||||||
label: "Media NSFW",
|
label: "Media NSFW",
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description: "List of instances to put medias as NSFW (sensitive) from",
|
description: "List of instances to tag all media as NSFW (sensitive) from",
|
||||||
suggestions: ["example.com", "*.example.com"]
|
suggestions: ["example.com", "*.example.com"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1422,21 +1423,21 @@
|
||||||
key: :reject,
|
key: :reject,
|
||||||
type: [:string, :regex],
|
type: [:string, :regex],
|
||||||
description:
|
description:
|
||||||
"A list of patterns which result in message being rejected, each pattern can be a string or a regular expression.",
|
"A list of patterns which result in message being rejected. Each pattern can be a string or a regular expression.",
|
||||||
suggestions: ["foo", ~r/foo/iu]
|
suggestions: ["foo", ~r/foo/iu]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :federated_timeline_removal,
|
key: :federated_timeline_removal,
|
||||||
type: [:string, :regex],
|
type: [:string, :regex],
|
||||||
description:
|
description:
|
||||||
"A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a regular expression.",
|
"A list of patterns which result in message being removed from federated timelines (a.k.a unlisted). Each pattern can be a string or a regular expression.",
|
||||||
suggestions: ["foo", ~r/foo/iu]
|
suggestions: ["foo", ~r/foo/iu]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :replace,
|
key: :replace,
|
||||||
type: [{:tuple, :string, :string}, {:tuple, :regex, :string}],
|
type: [{:tuple, :string, :string}, {:tuple, :regex, :string}],
|
||||||
description:
|
description:
|
||||||
"A list of tuples containing {pattern, replacement}, pattern can be a string or a regular expression.",
|
"A list of tuples containing {pattern, replacement}. Each pattern can be a string or a regular expression.",
|
||||||
suggestions: [{"foo", "bar"}, {~r/foo/iu, "bar"}]
|
suggestions: [{"foo", "bar"}, {~r/foo/iu, "bar"}]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1451,7 +1452,7 @@
|
||||||
%{
|
%{
|
||||||
key: :actors,
|
key: :actors,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description: "A list of actors, for which to drop any posts mentioning",
|
description: "A list of actors for which any post mentioning them will be dropped.",
|
||||||
suggestions: ["actor1", "actor2"]
|
suggestions: ["actor1", "actor2"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1855,9 +1856,8 @@
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"A mailto link for the administrative contact." <>
|
"A mailto link for the administrative contact." <>
|
||||||
" It's best if this email is not a personal email address, but rather a group email so that if a person leaves an organization," <>
|
" It's best if this email is not a personal email address, but rather a group email to the instance moderation team.",
|
||||||
" is unavailable for an extended period, or otherwise can't respond, someone else on the list can.",
|
suggestions: ["mailto:moderators@pleroma.com"]
|
||||||
suggestions: ["Subject"]
|
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :public_key,
|
key: :public_key,
|
||||||
|
@ -1924,7 +1924,7 @@
|
||||||
key: :admin_token,
|
key: :admin_token,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "Token",
|
description: "Token",
|
||||||
suggestions: ["some_random_token"]
|
suggestions: ["We recommend a secure random string or UUID"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1986,6 +1986,7 @@
|
||||||
"Background jobs queues (keys: queues, values: max numbers of concurrent jobs)",
|
"Background jobs queues (keys: queues, values: max numbers of concurrent jobs)",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
activity_expiration: 10,
|
activity_expiration: 10,
|
||||||
|
attachments_cleanup: 5,
|
||||||
background: 5,
|
background: 5,
|
||||||
federator_incoming: 50,
|
federator_incoming: 50,
|
||||||
federator_outgoing: 50,
|
federator_outgoing: 50,
|
||||||
|
@ -2001,6 +2002,12 @@
|
||||||
description: "Activity expiration queue",
|
description: "Activity expiration queue",
|
||||||
suggestions: [10]
|
suggestions: [10]
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :attachments_cleanup,
|
||||||
|
type: :integer,
|
||||||
|
description: "Attachment deletion queue",
|
||||||
|
suggestions: [5]
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :background,
|
key: :background,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
|
@ -2099,7 +2106,7 @@
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enables/disables RichMedia."
|
description: "Enables RichMedia parsing of URLs."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :ignore_hosts,
|
key: :ignore_hosts,
|
||||||
|
@ -2145,8 +2152,7 @@
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description: "Fetch posts when a new user is federated with"
|
||||||
"If enabled, when a new user is federated with, fetch some of their latest posts"
|
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :pages,
|
key: :pages,
|
||||||
|
@ -2165,13 +2171,13 @@
|
||||||
%{
|
%{
|
||||||
key: :class,
|
key: :class,
|
||||||
type: [:string, false],
|
type: [:string, false],
|
||||||
description: "Specify the class to be added to the generated link. `False` to clear",
|
description: "Specify the class to be added to the generated link. Disable to clear",
|
||||||
suggestions: ["auto-linker", false]
|
suggestions: ["auto-linker", false]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :rel,
|
key: :rel,
|
||||||
type: [:string, false],
|
type: [:string, false],
|
||||||
description: "Override the rel attribute. `False` to clear",
|
description: "Override the rel attribute. Disable to clear",
|
||||||
suggestions: ["ugc", "noopener noreferrer", false]
|
suggestions: ["ugc", "noopener noreferrer", false]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2281,7 +2287,7 @@
|
||||||
key: :ssl,
|
key: :ssl,
|
||||||
label: "SSL",
|
label: "SSL",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "`True` to use SSL, usually implies the port 636"
|
description: "Enable to use SSL, usually implies the port 636"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :sslopts,
|
key: :sslopts,
|
||||||
|
@ -2308,7 +2314,7 @@
|
||||||
key: :tls,
|
key: :tls,
|
||||||
label: "TLS",
|
label: "TLS",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "`True` to start TLS, usually implies the port 389"
|
description: "Enable to use STARTTLS, usually implies the port 389"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :tlsopts,
|
key: :tlsopts,
|
||||||
|
@ -2358,7 +2364,7 @@
|
||||||
description:
|
description:
|
||||||
"OAuth admin scope requirement toggle. " <>
|
"OAuth admin scope requirement toggle. " <>
|
||||||
"If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token " <>
|
"If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token " <>
|
||||||
"(client app must support admin scopes). If `false` 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."
|
"`is_admin` user flag grants access to admin-specific actions."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2380,7 +2386,7 @@
|
||||||
key: :oauth_consumer_strategies,
|
key: :oauth_consumer_strategies,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description:
|
description:
|
||||||
"The list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
|
"The list of enabled OAuth consumer strategies. By default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
|
||||||
" Each entry in this space-delimited string should be of format \"strategy\" or \"strategy:dependency\"" <>
|
" Each entry in this space-delimited string should be of format \"strategy\" or \"strategy:dependency\"" <>
|
||||||
" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_<strategy>).",
|
" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_<strategy>).",
|
||||||
suggestions: ["twitter", "keycloak:ueberauth_keycloak_strategy"]
|
suggestions: ["twitter", "keycloak:ueberauth_keycloak_strategy"]
|
||||||
|
@ -2496,6 +2502,20 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
group: :pleroma,
|
||||||
|
key: Pleroma.Emails.NewUsersDigestEmail,
|
||||||
|
type: :group,
|
||||||
|
description: "New users admin email digest",
|
||||||
|
children: [
|
||||||
|
%{
|
||||||
|
key: :enabled,
|
||||||
|
type: :boolean,
|
||||||
|
description: "enables new users admin digest email when `true`",
|
||||||
|
suggestions: [false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
group: :pleroma,
|
group: :pleroma,
|
||||||
key: :oauth2,
|
key: :oauth2,
|
||||||
|
@ -2517,7 +2537,7 @@
|
||||||
%{
|
%{
|
||||||
key: :clean_expired_tokens,
|
key: :clean_expired_tokens,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable a background job to clean expired oauth tokens. Default: `false`."
|
description: "Enable a background job to clean expired oauth tokens. Default: disabled."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2577,7 +2597,7 @@
|
||||||
%{
|
%{
|
||||||
key: :rum_enabled,
|
key: :rum_enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "If RUM indexes should be used. Default: `false`"
|
description: "If RUM indexes should be used. Default: disabled"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2963,7 +2983,7 @@
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable/disable the plug. Default: `false`."
|
description: "Enable/disable the plug. Default: disabled."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :headers,
|
key: :headers,
|
||||||
|
@ -3017,7 +3037,7 @@
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enables the rendering of static HTML. Defaults to `false`."
|
description: "Enables the rendering of static HTML. Default: disabled."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -3093,7 +3113,7 @@
|
||||||
key: :configurable_from_database,
|
key: :configurable_from_database,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Allow transferring configuration to DB with the subsequent customization from Admin api. Defaults to `false`"
|
"Allow transferring configuration to DB with the subsequent customization from Admin api. Default: disabled"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,8 @@
|
||||||
|
|
||||||
config :pleroma, Pleroma.Gun.API, Pleroma.Gun.API.Mock
|
config :pleroma, Pleroma.Gun.API, Pleroma.Gun.API.Mock
|
||||||
|
|
||||||
|
config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true
|
||||||
|
|
||||||
if File.exists?("./config/test.secret.exs") do
|
if File.exists?("./config/test.secret.exs") do
|
||||||
import_config "test.secret.exs"
|
import_config "test.secret.exs"
|
||||||
else
|
else
|
||||||
|
|
|
@ -459,3 +459,16 @@ Emoji reactions work a lot like favourites do. They make it possible to react to
|
||||||
{"name": "☕", "count": 1, "me": false, "accounts": [{"id" => "abc..."}]}
|
{"name": "☕", "count": 1, "me": false, "accounts": [{"id" => "abc..."}]}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `GET /api/v1/pleroma/statuses/:id/reactions/:emoji`
|
||||||
|
### Get an object of emoji to account mappings with accounts that reacted to the post for a specific emoji`
|
||||||
|
* Method: `GET`
|
||||||
|
* Authentication: optional
|
||||||
|
* Params: None
|
||||||
|
* Response: JSON, a list of emoji/account list tuples
|
||||||
|
* Example Response:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"name": "😀", "count": 2, "me": true, "accounts": [{"id" => "xyz.."...}, {"id" => "zyx..."}]}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
|
@ -1,4 +1,21 @@
|
||||||
# Updating your instance
|
# Updating your instance
|
||||||
|
|
||||||
|
You should **always check the release notes/changelog** in case there are config deprecations, special update special update steps, etc.
|
||||||
|
|
||||||
|
Besides that, doing the following is generally enough:
|
||||||
|
|
||||||
|
## For OTP installations
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Download the new release
|
||||||
|
su pleroma -s $SHELL -lc "./bin/pleroma_ctl update"
|
||||||
|
|
||||||
|
# Migrate the database, you are advised to stop the instance before doing that
|
||||||
|
su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
|
||||||
|
```
|
||||||
|
|
||||||
|
## For from source installations (using git)
|
||||||
|
|
||||||
1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
|
1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
|
||||||
2. Run `git pull`. This pulls the latest changes from upstream.
|
2. Run `git pull`. This pulls the latest changes from upstream.
|
||||||
3. Run `mix deps.get`. This pulls in any new dependencies.
|
3. Run `mix deps.get`. This pulls in any new dependencies.
|
||||||
|
|
|
@ -143,10 +143,11 @@ config :pleroma, :mrf_user_allowlist,
|
||||||
* `:reject` rejects the message entirely
|
* `:reject` rejects the message entirely
|
||||||
|
|
||||||
### :activitypub
|
### :activitypub
|
||||||
* ``unfollow_blocked``: Whether blocks result in people getting unfollowed
|
* `unfollow_blocked`: Whether blocks result in people getting unfollowed
|
||||||
* ``outgoing_blocks``: Whether to federate blocks to other instances
|
* `outgoing_blocks`: Whether to federate blocks to other instances
|
||||||
* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question
|
* `deny_follow_blocked`: Whether to disallow following an account that has blocked the user in question
|
||||||
* ``sign_object_fetches``: Sign object fetches with HTTP signatures
|
* `sign_object_fetches`: Sign object fetches with HTTP signatures
|
||||||
|
* `authorized_fetch_mode`: Require HTTP signatures for AP fetches
|
||||||
|
|
||||||
### :fetch_initial_posts
|
### :fetch_initial_posts
|
||||||
* `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts
|
* `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts
|
||||||
|
@ -533,6 +534,10 @@ Email notifications settings.
|
||||||
- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo.
|
- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo.
|
||||||
- `:styling` - a map with color settings for email templates.
|
- `:styling` - a map with color settings for email templates.
|
||||||
|
|
||||||
|
### Pleroma.Emails.NewUsersDigestEmail
|
||||||
|
|
||||||
|
- `:enabled` - a boolean, enables new users admin digest email when `true`. Defaults to `false`.
|
||||||
|
|
||||||
## Background jobs
|
## Background jobs
|
||||||
|
|
||||||
### Oban
|
### Oban
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Message Rewrite Facility
|
# Message Rewrite Facility
|
||||||
|
|
||||||
The Message Rewrite Facility (MRF) is a subsystem that is implemented as a series of hooks that allows the administrator to rewrite or discard messages.
|
The Message Rewrite Facility (MRF) is a subsystem that is implemented as a series of hooks that allows the administrator to rewrite or discard messages.
|
||||||
|
|
||||||
Possible uses include:
|
Possible uses include:
|
||||||
|
@ -11,6 +12,7 @@ Possible uses include:
|
||||||
* sending only public messages to a specific instance
|
* sending only public messages to a specific instance
|
||||||
|
|
||||||
The MRF provides user-configurable policies. The default policy is `NoOpPolicy`, which disables the MRF functionality. Pleroma also includes an easy to use policy called `SimplePolicy` which maps messages matching certain pre-defined criterion to actions built into the policy module.
|
The MRF provides user-configurable policies. The default policy is `NoOpPolicy`, which disables the MRF functionality. Pleroma also includes an easy to use policy called `SimplePolicy` which maps messages matching certain pre-defined criterion to actions built into the policy module.
|
||||||
|
|
||||||
It is possible to use multiple, active MRF policies at the same time.
|
It is possible to use multiple, active MRF policies at the same time.
|
||||||
|
|
||||||
## Quarantine Instances
|
## Quarantine Instances
|
||||||
|
@ -18,7 +20,8 @@ It is possible to use multiple, active MRF policies at the same time.
|
||||||
You have the ability to prevent from private / followers-only messages from federating with specific instances. Which means they will only get the public or unlisted messages from your instance.
|
You have the ability to prevent from private / followers-only messages from federating with specific instances. Which means they will only get the public or unlisted messages from your instance.
|
||||||
|
|
||||||
If, for example, you're using `MIX_ENV=prod` aka using production mode, you would open your configuration file located in `config/prod.secret.exs` and edit or add the option under your `:instance` config object. Then you would specify the instance within quotes.
|
If, for example, you're using `MIX_ENV=prod` aka using production mode, you would open your configuration file located in `config/prod.secret.exs` and edit or add the option under your `:instance` config object. Then you would specify the instance within quotes.
|
||||||
```
|
|
||||||
|
```elixir
|
||||||
config :pleroma, :instance,
|
config :pleroma, :instance,
|
||||||
[...]
|
[...]
|
||||||
quarantined_instances: ["instance.example", "other.example"]
|
quarantined_instances: ["instance.example", "other.example"]
|
||||||
|
@ -30,7 +33,7 @@ config :pleroma, :instance,
|
||||||
|
|
||||||
To use `SimplePolicy`, you must enable it. Do so by adding the following to your `:instance` config object, so that it looks like this:
|
To use `SimplePolicy`, you must enable it. Do so by adding the following to your `:instance` config object, so that it looks like this:
|
||||||
|
|
||||||
```
|
```elixir
|
||||||
config :pleroma, :instance,
|
config :pleroma, :instance,
|
||||||
[...]
|
[...]
|
||||||
rewrite_policy: Pleroma.Web.ActivityPub.MRF.SimplePolicy
|
rewrite_policy: Pleroma.Web.ActivityPub.MRF.SimplePolicy
|
||||||
|
@ -50,7 +53,7 @@ Servers should be configured as lists.
|
||||||
|
|
||||||
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`:
|
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`:
|
||||||
|
|
||||||
```
|
```elixir
|
||||||
config :pleroma, :instance,
|
config :pleroma, :instance,
|
||||||
rewrite_policy: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
|
rewrite_policy: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
|
||||||
|
|
||||||
|
@ -60,7 +63,6 @@ config :pleroma, :mrf_simple,
|
||||||
reject: ["spam.com"],
|
reject: ["spam.com"],
|
||||||
federated_timeline_removal: ["spam.university"],
|
federated_timeline_removal: ["spam.university"],
|
||||||
report_removal: ["whiny.whiner"]
|
report_removal: ["whiny.whiner"]
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use with Care
|
### Use with Care
|
||||||
|
@ -74,16 +76,18 @@ As discussed above, the MRF system is a modular system that supports pluggable p
|
||||||
For example, here is a sample policy module which rewrites all messages to "new message content":
|
For example, here is a sample policy module which rewrites all messages to "new message content":
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
# This is a sample MRF policy which rewrites all Notes to have "new message
|
defmodule Pleroma.Web.ActivityPub.MRF.RewritePolicy do
|
||||||
# content."
|
@moduledoc "MRF policy which rewrites all Notes to have 'new message content'."
|
||||||
defmodule Site.RewritePolicy do
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
@behavior Pleroma.Web.ActivityPub.MRF
|
|
||||||
|
|
||||||
# Catch messages which contain Note objects with actual data to filter.
|
# Catch messages which contain Note objects with actual data to filter.
|
||||||
# Capture the object as `object`, the message content as `content` and the
|
# Capture the object as `object`, the message content as `content` and the
|
||||||
# message itself as `message`.
|
# message itself as `message`.
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => Create", "object" => {"type" => "Note", "content" => content} = object} = message)
|
def filter(
|
||||||
|
%{"type" => "Create", "object" => %{"type" => "Note", "content" => content} = object} =
|
||||||
|
message
|
||||||
|
)
|
||||||
when is_binary(content) do
|
when is_binary(content) do
|
||||||
# Subject / CW is stored as summary instead of `name` like other AS2 objects
|
# Subject / CW is stored as summary instead of `name` like other AS2 objects
|
||||||
# because of Mastodon doing it that way.
|
# because of Mastodon doing it that way.
|
||||||
|
@ -106,16 +110,21 @@ defmodule Site.RewritePolicy do
|
||||||
# Let all other messages through without modifying them.
|
# Let all other messages through without modifying them.
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe do
|
||||||
|
{:ok, %{mrf_sample: %{content: "new message content"}}}`
|
||||||
|
end
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
If you save this file as `lib/site/mrf/rewrite_policy.ex`, it will be included when you next rebuild Pleroma. You can enable it in the configuration like so:
|
If you save this file as `lib/pleroma/web/activity_pub/mrf/rewrite_policy.ex`, it will be included when you next rebuild Pleroma. You can enable it in the configuration like so:
|
||||||
|
|
||||||
```
|
```elixir
|
||||||
config :pleroma, :instance,
|
config :pleroma, :instance,
|
||||||
rewrite_policy: [
|
rewrite_policy: [
|
||||||
Pleroma.Web.ActivityPub.MRF.SimplePolicy,
|
Pleroma.Web.ActivityPub.MRF.SimplePolicy,
|
||||||
Site.RewritePolicy
|
Pleroma.Web.ActivityPub.MRF.RewritePolicy
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -259,19 +259,14 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl user new joeuser joeuser@sld.tld --a
|
||||||
```
|
```
|
||||||
This will create an account withe the username of 'joeuser' with the email address of joeuser@sld.tld, and set that user's account as an admin. This will result in a link that you can paste into the browser, which logs you in and enables you to set the password.
|
This will create an account withe the username of 'joeuser' with the email address of joeuser@sld.tld, and set that user's account as an admin. This will result in a link that you can paste into the browser, which logs you in and enables you to set the password.
|
||||||
|
|
||||||
### Updating
|
|
||||||
Generally, doing the following is enough:
|
|
||||||
```sh
|
|
||||||
# Download the new release
|
|
||||||
su pleroma -s $SHELL -lc "./bin/pleroma_ctl update"
|
|
||||||
|
|
||||||
# Migrate the database, you are advised to stop the instance before doing that
|
|
||||||
su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
|
|
||||||
```
|
|
||||||
But you should **always check the release notes/changelog** in case there are config deprecations, special update steps, etc.
|
|
||||||
|
|
||||||
## Further reading
|
## Further reading
|
||||||
|
|
||||||
* [Backup your instance](../administration/backup.md)
|
* [Backup your instance](../administration/backup.md)
|
||||||
* [Hardening your instance](../configuration/hardening.md)
|
* [Hardening your instance](../configuration/hardening.md)
|
||||||
* [How to activate mediaproxy](../configuration/howto_mediaproxy.md)
|
* [How to activate mediaproxy](../configuration/howto_mediaproxy.md)
|
||||||
|
* [Updating your instance](../administration/updating.md)
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
|
||||||
|
|
||||||
|
|
32
lib/pleroma/emails/new_users_digest_email.ex
Normal file
32
lib/pleroma/emails/new_users_digest_email.ex
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Emails.NewUsersDigestEmail do
|
||||||
|
use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email_styled}
|
||||||
|
|
||||||
|
defp instance_notify_email do
|
||||||
|
Pleroma.Config.get([:instance, :notify_email]) || Pleroma.Config.get([:instance, :email])
|
||||||
|
end
|
||||||
|
|
||||||
|
def new_users(to, users_and_statuses) do
|
||||||
|
instance_name = Pleroma.Config.get([:instance, :name])
|
||||||
|
styling = Pleroma.Config.get([Pleroma.Emails.UserEmail, :styling])
|
||||||
|
|
||||||
|
logo_url =
|
||||||
|
Pleroma.Web.Endpoint.url() <>
|
||||||
|
Pleroma.Config.get([:frontend_configurations, :pleroma_fe, :logo])
|
||||||
|
|
||||||
|
new()
|
||||||
|
|> to({to.name, to.email})
|
||||||
|
|> from({instance_name, instance_notify_email()})
|
||||||
|
|> subject("#{instance_name} New Users")
|
||||||
|
|> render_body("new_users_digest.html", %{
|
||||||
|
title: "New Users",
|
||||||
|
users_and_statuses: users_and_statuses,
|
||||||
|
instance: instance_name,
|
||||||
|
styling: styling,
|
||||||
|
logo_url: logo_url
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
import Phoenix.Controller, only: [get_format: 1, text: 2]
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def init(options) do
|
def init(options) do
|
||||||
|
@ -15,26 +16,28 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(conn, _opts) do
|
def call(conn, _opts) do
|
||||||
headers = get_req_header(conn, "signature")
|
if get_format(conn) == "activity+json" do
|
||||||
signature = Enum.at(headers, 0)
|
|
||||||
|
|
||||||
if signature do
|
|
||||||
# set (request-target) header to the appropriate value
|
|
||||||
# we also replace the digest header with the one we computed
|
|
||||||
conn =
|
|
||||||
conn
|
conn
|
||||||
|> put_req_header(
|
|> maybe_assign_valid_signature()
|
||||||
"(request-target)",
|
|> maybe_require_signature()
|
||||||
String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
|
||||||
)
|
|
||||||
|
|
||||||
conn =
|
|
||||||
if conn.assigns[:digest] do
|
|
||||||
conn
|
|
||||||
|> put_req_header("digest", conn.assigns[:digest])
|
|
||||||
else
|
else
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp maybe_assign_valid_signature(conn) do
|
||||||
|
if has_signature_header?(conn) do
|
||||||
|
# set (request-target) header to the appropriate value
|
||||||
|
# we also replace the digest header with the one we computed
|
||||||
|
request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> put_req_header("(request-target)", request_target)
|
||||||
|
|> case do
|
||||||
|
%{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest)
|
||||||
|
conn -> conn
|
||||||
|
end
|
||||||
|
|
||||||
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
|
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
|
||||||
else
|
else
|
||||||
|
@ -42,4 +45,21 @@ def call(conn, _opts) do
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp has_signature_header?(conn) do
|
||||||
|
conn |> get_req_header("signature") |> Enum.at(0, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp maybe_require_signature(%{assigns: %{valid_signature: true}} = conn), do: conn
|
||||||
|
|
||||||
|
defp maybe_require_signature(conn) do
|
||||||
|
if Pleroma.Config.get([:activitypub, :authorized_fetch_mode], false) do
|
||||||
|
conn
|
||||||
|
|> put_status(:unauthorized)
|
||||||
|
|> text("Request not signed")
|
||||||
|
|> halt()
|
||||||
|
else
|
||||||
|
conn
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,13 +41,16 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
||||||
|
|
||||||
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
||||||
|
|
||||||
def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
|
def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id} = params) do
|
||||||
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
|
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
|
||||||
%Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
|
%Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
|
||||||
Object.normalize(activity) do
|
Object.normalize(activity) do
|
||||||
reactions =
|
reactions =
|
||||||
emoji_reactions
|
emoji_reactions
|
||||||
|> Enum.map(fn [emoji, user_ap_ids] ->
|
|> Enum.map(fn [emoji, user_ap_ids] ->
|
||||||
|
if params["emoji"] && params["emoji"] != emoji do
|
||||||
|
nil
|
||||||
|
else
|
||||||
users =
|
users =
|
||||||
Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
|
Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
|
||||||
|> Enum.filter(& &1)
|
|> Enum.filter(& &1)
|
||||||
|
@ -58,7 +61,9 @@ def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id})
|
||||||
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
|
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
|
||||||
me: !!(user && user.ap_id in user_ap_ids)
|
me: !!(user && user.ap_id in user_ap_ids)
|
||||||
}
|
}
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|> Enum.filter(& &1)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> json(reactions)
|
|> json(reactions)
|
||||||
|
|
|
@ -271,6 +271,7 @@ defmodule Pleroma.Web.Router do
|
||||||
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
|
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
|
||||||
pipe_through(:api)
|
pipe_through(:api)
|
||||||
|
|
||||||
|
get("/statuses/:id/reactions/:emoji", PleromaAPIController, :emoji_reactions_by)
|
||||||
get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by)
|
get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
158
lib/pleroma/web/templates/email/new_users_digest.html.eex
Normal file
158
lib/pleroma/web/templates/email/new_users_digest.html.eex
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
<%= for {user, total_statuses, latest_status} <- @users_and_statuses do %>
|
||||||
|
<%# user card START %>
|
||||||
|
<div style="background-color:transparent;">
|
||||||
|
<div class="block-grid mixed-two-up no-stack"
|
||||||
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
<div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
|
||||||
|
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]><td align="center" width="147" style="background-color:<%= @styling.content_background_color%>;width:76px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 20px; padding-top:5px; padding-bottom:5px;"><![endif]-->
|
||||||
|
<div class="col num3"
|
||||||
|
style="display: table-cell; vertical-align: top; max-width: 320px; min-width: 76px; width: 76px;">
|
||||||
|
<div style="width:100% !important;">
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
<div
|
||||||
|
style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 20px;">
|
||||||
|
<!--<![endif]-->
|
||||||
|
<div align="left" class="img-container left "
|
||||||
|
style="padding-right: 0px;padding-left: 0px;">
|
||||||
|
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr style="line-height:0px"><td style="padding-right: 0px;padding-left: 0px;" align="left"><![endif]--><img
|
||||||
|
alt="<%= user.name %>" border="0" class="left " src="<%= avatar_url(user) %>"
|
||||||
|
style="text-decoration: none; -ms-interpolation-mode: bicubic; border: 0; height: auto; width: 100%; max-width: 76px; display: block;"
|
||||||
|
title="<%= user.name %>" width="76" />
|
||||||
|
<!--[if mso]></td></tr></table><![endif]-->
|
||||||
|
</div>
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
</div>
|
||||||
|
<!--<![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]></td><td align="center" width="442" style="background-color:<%= @styling.content_background_color%>;width:442px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
|
||||||
|
<div class="col num9"
|
||||||
|
style="display: table-cell; vertical-align: top; min-width: 320px; max-width: 441px; width: 442px;">
|
||||||
|
<div style="width:100% !important;">
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
<div
|
||||||
|
style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
|
||||||
|
<!--<![endif]-->
|
||||||
|
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
|
||||||
|
<div
|
||||||
|
style="color:<%= @styling.text_color %>;font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||||
|
<div
|
||||||
|
style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 12px; line-height: 14px; color: <%= @styling.text_color %>;">
|
||||||
|
<p style="font-size: 14px; line-height: 19px; margin: 0;"><span
|
||||||
|
style="font-size: 16px; color: <%= @styling.text_color %>;"><%= user.name %></span></p>
|
||||||
|
<p style="font-size: 14px; line-height: 19px; margin: 0;"><span
|
||||||
|
style="font-size: 16px;"><%= link "@" <> user.nickname, style: "color: #{@styling.link_color};text-decoration: none;", to: admin_user_url(user) %></span></p>
|
||||||
|
<p style="font-size: 14px; line-height: 19px; margin: 0;"><span
|
||||||
|
style="font-size: 16px;">Total: <%= total_statuses %></span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if mso]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
</div>
|
||||||
|
<!--<![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%# user card END %>
|
||||||
|
|
||||||
|
<%= if latest_status do %>
|
||||||
|
<div style="background-color:transparent;">
|
||||||
|
<div class="block-grid"
|
||||||
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
<div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
|
||||||
|
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 15px; padding-left: 15px; padding-top:5px; padding-bottom:5px;"><![endif]-->
|
||||||
|
<div class="col num12"
|
||||||
|
style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
|
||||||
|
<div style="width:100% !important;">
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
<div
|
||||||
|
style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 15px; padding-left: 15px;">
|
||||||
|
<!--<![endif]-->
|
||||||
|
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
|
||||||
|
<div
|
||||||
|
style="color:<%= @styling.text_color %>;font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||||
|
<div
|
||||||
|
style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 12px; line-height: 14px; color: <%= @styling.text_color %>;">
|
||||||
|
<span style="font-size: 16px; line-height: 19px;"><%= raw latest_status.object.data["content"] %></span></div>
|
||||||
|
</div>
|
||||||
|
<!--[if mso]></td></tr></table><![endif]-->
|
||||||
|
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 15px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
|
||||||
|
<div
|
||||||
|
style="color:<%= @styling.text_muted_color %>;font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:15px;">
|
||||||
|
<div
|
||||||
|
style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 12px; line-height: 14px; color: <%= @styling.text_muted_color %>;">
|
||||||
|
<p style="font-size: 14px; line-height: 16px; margin: 0;"><%= format_date latest_status.object.data["published"] %></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if mso]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
</div>
|
||||||
|
<!--<![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<%# divider start %>
|
||||||
|
<div style="background-color:transparent;">
|
||||||
|
<div class="block-grid"
|
||||||
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
<div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
|
||||||
|
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
|
||||||
|
<div class="col num12"
|
||||||
|
style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
|
||||||
|
<div style="width:100% !important;">
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
<div
|
||||||
|
style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
|
||||||
|
<!--<![endif]-->
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" class="divider" role="presentation"
|
||||||
|
style="table-layout: fixed; vertical-align: top; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; min-width: 100%; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"
|
||||||
|
valign="top" width="100%">
|
||||||
|
<tbody>
|
||||||
|
<tr style="vertical-align: top;" valign="top">
|
||||||
|
<td class="divider_inner"
|
||||||
|
style="word-break: break-word; vertical-align: top; min-width: 100%; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; padding-top: 10px; padding-right: 10px; padding-bottom: 10px; padding-left: 10px;"
|
||||||
|
valign="top">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" class="divider_content"
|
||||||
|
height="0" role="presentation"
|
||||||
|
style="table-layout: fixed; vertical-align: top; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; border-top: 1px solid <%= @styling.text_color %>; height: 0px;"
|
||||||
|
valign="top" width="100%">
|
||||||
|
<tbody>
|
||||||
|
<tr style="vertical-align: top;" valign="top">
|
||||||
|
<td height="0"
|
||||||
|
style="word-break: break-word; vertical-align: top; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"
|
||||||
|
valign="top"><span></span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
</div>
|
||||||
|
<!--<![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%# divider end %>
|
||||||
|
<%# user card END %>
|
||||||
|
<% end %>
|
193
lib/pleroma/web/templates/layout/email_styled.html.eex
Normal file
193
lib/pleroma/web/templates/layout/email_styled.html.eex
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||||
|
xmlns:v="urn:schemas-microsoft-com:vml">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<!--[if gte mso 9]><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
||||||
|
<meta content="width=device-width" name="viewport" />
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
|
||||||
|
<!--<![endif]-->
|
||||||
|
<title><%= @email.subject %></title>
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<!--<![endif]-->
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
|
||||||
|
color: <%= @styling.link_color %>;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table,
|
||||||
|
td,
|
||||||
|
tr {
|
||||||
|
vertical-align: top;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[x-apple-data-detectors=true] {
|
||||||
|
color: inherit !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style id="media-query" type="text/css">
|
||||||
|
@media (max-width: 610px) {
|
||||||
|
|
||||||
|
.block-grid,
|
||||||
|
.col {
|
||||||
|
min-width: 320px !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-grid {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col>div {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack .col {
|
||||||
|
min-width: 0 !important;
|
||||||
|
display: table-cell !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack.two-up .col {
|
||||||
|
width: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack .col.num4 {
|
||||||
|
width: 33% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack .col.num8 {
|
||||||
|
width: 66% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack .col.num4 {
|
||||||
|
width: 33% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack .col.num3 {
|
||||||
|
width: 25% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack .col.num6 {
|
||||||
|
width: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-stack .col.num9 {
|
||||||
|
width: 75% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="clean-body" style="margin: 0; padding: 0; -webkit-text-size-adjust: 100%; background-color: <%= @styling.background_color %>;">
|
||||||
|
<!--[if IE]><div class="ie-browser"><![endif]-->
|
||||||
|
<table bgcolor="<%= @styling.background_color %>" cellpadding="0" cellspacing="0" class="nl-container" role="presentation"
|
||||||
|
style="table-layout: fixed; vertical-align: top; min-width: 320px; Margin: 0 auto; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: <%= @styling.background_color %>; width: 100%;"
|
||||||
|
valign="top" width="100%">
|
||||||
|
<tbody>
|
||||||
|
<tr style="vertical-align: top;" valign="top">
|
||||||
|
<td style="word-break: break-word; vertical-align: top;" valign="top">
|
||||||
|
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color:<%= @styling.background_color %>"><![endif]-->
|
||||||
|
|
||||||
|
<%# header %>
|
||||||
|
<div style="background-color:transparent;">
|
||||||
|
<div class="block-grid"
|
||||||
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
<div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
|
||||||
|
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
|
||||||
|
<div class="col num12"
|
||||||
|
style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
|
||||||
|
<div style="width:100% !important;">
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
<div
|
||||||
|
style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
|
||||||
|
<!--<![endif]-->
|
||||||
|
<div align="center" class="img-container center"
|
||||||
|
style="padding-right: 0px;padding-left: 0px;">
|
||||||
|
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr style="line-height:0px"><td style="padding-right: 0px;padding-left: 0px;" align="center"><![endif]--><img
|
||||||
|
align="center" alt="Image" border="0" class="center" src="<%= @logo_url %>"
|
||||||
|
style="text-decoration: none; -ms-interpolation-mode: bicubic; border: 0; height: 80px; width: auto; max-height: 80px; display: block;"
|
||||||
|
title="Image" height="80" />
|
||||||
|
<!--[if mso]></td></tr></table><![endif]-->
|
||||||
|
</div>
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
</div>
|
||||||
|
<!--<![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<%# title %>
|
||||||
|
<%= if @title do %>
|
||||||
|
<div style="background-color:transparent;">
|
||||||
|
<div class="block-grid"
|
||||||
|
style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
|
||||||
|
<div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
|
||||||
|
<!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
|
||||||
|
<div class="col num12"
|
||||||
|
style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
|
||||||
|
<div style="width:100% !important;">
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
<div
|
||||||
|
style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
|
||||||
|
<!--<![endif]-->
|
||||||
|
<!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
|
||||||
|
<div
|
||||||
|
style="line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||||
|
<div
|
||||||
|
style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height: 14px; color: <%= @styling.header_color %>;">
|
||||||
|
<p style="line-height: 36px; text-align: center; margin: 0;"><span
|
||||||
|
style="font-size: 30px; color: <%= @styling.header_color %>;"><%= @title %></span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if mso]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (!mso)&(!IE)]><!-->
|
||||||
|
</div>
|
||||||
|
<!--<![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||||
|
<!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<%= render @view_module, @view_template, assigns %>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!--[if (IE)]></div><![endif]-->
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
||||||
|
@ -69,7 +69,7 @@ defp is_status?(acct) do
|
||||||
def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do
|
def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do
|
||||||
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||||
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||||
render(conn, "followed.html", %{error: false})
|
redirect(conn, to: "/users/#{followee.id}")
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
handle_follow_error(conn, error)
|
handle_follow_error(conn, error)
|
||||||
|
@ -80,7 +80,7 @@ def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" =>
|
||||||
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||||
{_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
|
{_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
|
||||||
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||||
render(conn, "followed.html", %{error: false})
|
redirect(conn, to: "/users/#{followee.id}")
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
handle_follow_error(conn, error)
|
handle_follow_error(conn, error)
|
||||||
|
|
|
@ -12,4 +12,8 @@ def format_date(date) when is_binary(date) do
|
||||||
|> Timex.parse!("{ISO:Extended:Z}")
|
|> Timex.parse!("{ISO:Extended:Z}")
|
||||||
|> Timex.format!("{Mshort} {D}, {YYYY} {h24}:{m}")
|
|> Timex.format!("{Mshort} {D}, {YYYY} {h24}:{m}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def admin_user_url(%{id: id}) do
|
||||||
|
Pleroma.Web.Endpoint.url() <> "/pleroma/admin/#/users/" <> id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
60
lib/pleroma/workers/cron/new_users_digest_worker.ex
Normal file
60
lib/pleroma/workers/cron/new_users_digest_worker.ex
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Workers.Cron.NewUsersDigestWorker do
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
use Pleroma.Workers.WorkerHelper, queue: "new_users_digest"
|
||||||
|
|
||||||
|
@impl Oban.Worker
|
||||||
|
def perform(_args, _job) do
|
||||||
|
if Pleroma.Config.get([Pleroma.Emails.NewUsersDigestEmail, :enabled]) do
|
||||||
|
today = NaiveDateTime.utc_now() |> Timex.beginning_of_day()
|
||||||
|
|
||||||
|
a_day_ago =
|
||||||
|
today
|
||||||
|
|> Timex.shift(days: -1)
|
||||||
|
|> Timex.beginning_of_day()
|
||||||
|
|
||||||
|
users_and_statuses =
|
||||||
|
%{
|
||||||
|
local: true,
|
||||||
|
order_by: :inserted_at
|
||||||
|
}
|
||||||
|
|> User.Query.build()
|
||||||
|
|> where([u], u.inserted_at >= ^a_day_ago and u.inserted_at < ^today)
|
||||||
|
|> Repo.all()
|
||||||
|
|> Enum.map(fn user ->
|
||||||
|
latest_status =
|
||||||
|
Activity
|
||||||
|
|> Activity.Queries.by_actor(user.ap_id)
|
||||||
|
|> Activity.Queries.by_type("Create")
|
||||||
|
|> Activity.with_preloaded_object()
|
||||||
|
|> order_by(desc: :inserted_at)
|
||||||
|
|> limit(1)
|
||||||
|
|> Repo.one()
|
||||||
|
|
||||||
|
total_statuses =
|
||||||
|
Activity
|
||||||
|
|> Activity.Queries.by_actor(user.ap_id)
|
||||||
|
|> Activity.Queries.by_type("Create")
|
||||||
|
|> Repo.aggregate(:count, :id)
|
||||||
|
|
||||||
|
{user, total_statuses, latest_status}
|
||||||
|
end)
|
||||||
|
|
||||||
|
if users_and_statuses != [] do
|
||||||
|
%{is_admin: true}
|
||||||
|
|> User.Query.build()
|
||||||
|
|> Repo.all()
|
||||||
|
|> Enum.map(&Pleroma.Emails.NewUsersDigestEmail.new_users(&1, users_and_statuses))
|
||||||
|
|> Enum.each(&Pleroma.Emails.Mailer.deliver/1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,7 +17,11 @@ def up do
|
||||||
Repo.stream(query)
|
Repo.stream(query)
|
||||||
|> Enum.each(fn %{id: user_id, bookmarks: bookmarks} ->
|
|> Enum.each(fn %{id: user_id, bookmarks: bookmarks} ->
|
||||||
Enum.each(bookmarks, fn ap_id ->
|
Enum.each(bookmarks, fn ap_id ->
|
||||||
activity = Activity.get_create_by_object_ap_id(ap_id)
|
activity =
|
||||||
|
ap_id
|
||||||
|
|> Activity.create_by_object_ap_id()
|
||||||
|
|> Repo.one()
|
||||||
|
|
||||||
unless is_nil(activity), do: {:ok, _} = Bookmark.create(user_id, activity.id)
|
unless is_nil(activity), do: {:ok, _} = Bookmark.create(user_id, activity.id)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
defmodule Pleroma.Repo.Migrations.AddFollowingAddressFromSourceData do
|
defmodule Pleroma.Repo.Migrations.AddFollowingAddressFromSourceData do
|
||||||
use Ecto.Migration
|
|
||||||
import Ecto.Query
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
import Ecto.Query
|
||||||
|
require Logger
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
def change do
|
def change do
|
||||||
query =
|
query =
|
||||||
|
@ -19,6 +20,9 @@ def change do
|
||||||
:following_address
|
:following_address
|
||||||
])
|
])
|
||||||
|> Pleroma.Repo.update()
|
|> Pleroma.Repo.update()
|
||||||
|
|
||||||
|
user ->
|
||||||
|
Logger.warn("User #{user.id} / #{user.nickname} does not seem to have source_data")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,8 @@ defmodule Pleroma.Repo.Migrations.CopyMutedToMutedNotifications do
|
||||||
use Ecto.Migration
|
use Ecto.Migration
|
||||||
|
|
||||||
def change do
|
def change do
|
||||||
|
execute("update users set info = '{}' where info is null")
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
"update users set info = safe_jsonb_set(info, '{muted_notifications}', info->'mutes', true) where local = true"
|
"update users set info = safe_jsonb_set(info, '{muted_notifications}', info->'mutes', true) where local = true"
|
||||||
)
|
)
|
||||||
|
|
|
@ -138,6 +138,8 @@ test "when association is not loaded" do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
clear_config([:instance, :limit_to_local_content])
|
||||||
|
|
||||||
test "finds utf8 text in statuses", %{
|
test "finds utf8 text in statuses", %{
|
||||||
japanese_activity: japanese_activity,
|
japanese_activity: japanese_activity,
|
||||||
user: user
|
user: user
|
||||||
|
@ -165,7 +167,6 @@ test "find only local statuses for unauthenticated users when `limit_to_local_c
|
||||||
%{local_activity: local_activity} do
|
%{local_activity: local_activity} do
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], :all)
|
Pleroma.Config.put([:instance, :limit_to_local_content], :all)
|
||||||
assert [^local_activity] = Activity.search(nil, "find me")
|
assert [^local_activity] = Activity.search(nil, "find me")
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "find all statuses for unauthenticated users when `limit_to_local_content` is `false`",
|
test "find all statuses for unauthenticated users when `limit_to_local_content` is `false`",
|
||||||
|
@ -178,8 +179,6 @@ test "find all statuses for unauthenticated users when `limit_to_local_content`
|
||||||
activities = Enum.sort_by(Activity.search(nil, "find me"), & &1.id)
|
activities = Enum.sort_by(Activity.search(nil, "find me"), & &1.id)
|
||||||
|
|
||||||
assert [^local_activity, ^remote_activity] = activities
|
assert [^local_activity, ^remote_activity] = activities
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.HTTP.RequestBuilderTest do
|
||||||
|
|
||||||
describe "headers/2" do
|
describe "headers/2" do
|
||||||
clear_config([:http, :send_user_agent])
|
clear_config([:http, :send_user_agent])
|
||||||
|
clear_config([:http, :user_agent])
|
||||||
|
|
||||||
test "don't send pleroma user agent" do
|
test "don't send pleroma user agent" do
|
||||||
assert RequestBuilder.headers(%Request{}, []) == %Request{headers: []}
|
assert RequestBuilder.headers(%Request{}, []) == %Request{headers: []}
|
||||||
|
|
|
@ -75,6 +75,7 @@ test "ensures cache is cleared for the object" do
|
||||||
|
|
||||||
describe "delete attachments" do
|
describe "delete attachments" do
|
||||||
clear_config([Pleroma.Upload])
|
clear_config([Pleroma.Upload])
|
||||||
|
clear_config([:instance, :cleanup_attachments])
|
||||||
|
|
||||||
test "Disabled via config" do
|
test "Disabled via config" do
|
||||||
Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
|
Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
|
||||||
|
|
|
@ -23,6 +23,8 @@ test "does nothing if a user is assigned", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "when secret set it assigns an admin user" do
|
describe "when secret set it assigns an admin user" do
|
||||||
|
clear_config([:admin_token])
|
||||||
|
|
||||||
test "with `admin_token` query parameter", %{conn: conn} do
|
test "with `admin_token` query parameter", %{conn: conn} do
|
||||||
Pleroma.Config.put(:admin_token, "password123")
|
Pleroma.Config.put(:admin_token, "password123")
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
|
||||||
|
|
||||||
clear_config([:http_securiy, :enabled])
|
clear_config([:http_securiy, :enabled])
|
||||||
clear_config([:http_security, :sts])
|
clear_config([:http_security, :sts])
|
||||||
|
clear_config([:http_security, :referrer_policy])
|
||||||
|
|
||||||
describe "http security enabled" do
|
describe "http security enabled" do
|
||||||
setup do
|
setup do
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
|
||||||
alias Pleroma.Web.Plugs.HTTPSignaturePlug
|
alias Pleroma.Web.Plugs.HTTPSignaturePlug
|
||||||
|
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
|
import Phoenix.Controller, only: [put_format: 2]
|
||||||
import Mock
|
import Mock
|
||||||
|
|
||||||
test "it call HTTPSignatures to check validity if the actor sighed it" do
|
test "it call HTTPSignatures to check validity if the actor sighed it" do
|
||||||
|
@ -20,10 +21,69 @@ test "it call HTTPSignatures to check validity if the actor sighed it" do
|
||||||
"signature",
|
"signature",
|
||||||
"keyId=\"http://mastodon.example.org/users/admin#main-key"
|
"keyId=\"http://mastodon.example.org/users/admin#main-key"
|
||||||
)
|
)
|
||||||
|
|> put_format("activity+json")
|
||||||
|> HTTPSignaturePlug.call(%{})
|
|> HTTPSignaturePlug.call(%{})
|
||||||
|
|
||||||
assert conn.assigns.valid_signature == true
|
assert conn.assigns.valid_signature == true
|
||||||
|
assert conn.halted == false
|
||||||
assert called(HTTPSignatures.validate_conn(:_))
|
assert called(HTTPSignatures.validate_conn(:_))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "requires a signature when `authorized_fetch_mode` is enabled" do
|
||||||
|
setup do
|
||||||
|
Pleroma.Config.put([:activitypub, :authorized_fetch_mode], true)
|
||||||
|
|
||||||
|
on_exit(fn ->
|
||||||
|
Pleroma.Config.put([:activitypub, :authorized_fetch_mode], false)
|
||||||
|
end)
|
||||||
|
|
||||||
|
params = %{"actor" => "http://mastodon.example.org/users/admin"}
|
||||||
|
conn = build_conn(:get, "/doesntmattter", params) |> put_format("activity+json")
|
||||||
|
|
||||||
|
[conn: conn]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "when signature header is present", %{conn: conn} do
|
||||||
|
with_mock HTTPSignatures, validate_conn: fn _ -> false end do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> put_req_header(
|
||||||
|
"signature",
|
||||||
|
"keyId=\"http://mastodon.example.org/users/admin#main-key"
|
||||||
|
)
|
||||||
|
|> HTTPSignaturePlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.assigns.valid_signature == false
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.status == 401
|
||||||
|
assert conn.state == :sent
|
||||||
|
assert conn.resp_body == "Request not signed"
|
||||||
|
assert called(HTTPSignatures.validate_conn(:_))
|
||||||
|
end
|
||||||
|
|
||||||
|
with_mock HTTPSignatures, validate_conn: fn _ -> true end do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> put_req_header(
|
||||||
|
"signature",
|
||||||
|
"keyId=\"http://mastodon.example.org/users/admin#main-key"
|
||||||
|
)
|
||||||
|
|> HTTPSignaturePlug.call(%{})
|
||||||
|
|
||||||
|
assert conn.assigns.valid_signature == true
|
||||||
|
assert conn.halted == false
|
||||||
|
assert called(HTTPSignatures.validate_conn(:_))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "halts the connection when `signature` header is not present", %{conn: conn} do
|
||||||
|
conn = HTTPSignaturePlug.call(conn, %{})
|
||||||
|
assert conn.assigns[:valid_signature] == nil
|
||||||
|
assert conn.halted == true
|
||||||
|
assert conn.status == 401
|
||||||
|
assert conn.state == :sent
|
||||||
|
assert conn.resp_body == "Request not signed"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,10 @@ defmodule Pleroma.Plugs.RemoteIpTest do
|
||||||
|
|
||||||
alias Pleroma.Plugs.RemoteIp
|
alias Pleroma.Plugs.RemoteIp
|
||||||
|
|
||||||
|
import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2]
|
||||||
|
|
||||||
|
clear_config(RemoteIp)
|
||||||
|
|
||||||
test "disabled" do
|
test "disabled" do
|
||||||
Pleroma.Config.put(RemoteIp, enabled: false)
|
Pleroma.Config.put(RemoteIp, enabled: false)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ defmodule Pleroma.Plugs.UserEnabledPlugTest do
|
||||||
alias Pleroma.Plugs.UserEnabledPlug
|
alias Pleroma.Plugs.UserEnabledPlug
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
clear_config([:instance, :account_activation_required])
|
||||||
|
|
||||||
test "doesn't do anything if the user isn't set", %{conn: conn} do
|
test "doesn't do anything if the user isn't set", %{conn: conn} do
|
||||||
ret_conn =
|
ret_conn =
|
||||||
conn
|
conn
|
||||||
|
@ -18,7 +20,6 @@ test "doesn't do anything if the user isn't set", %{conn: conn} do
|
||||||
|
|
||||||
test "with a user that's not confirmed and a config requiring confirmation, it removes that user",
|
test "with a user that's not confirmed and a config requiring confirmation, it removes that user",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
old = Pleroma.Config.get([:instance, :account_activation_required])
|
|
||||||
Pleroma.Config.put([:instance, :account_activation_required], true)
|
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||||
|
|
||||||
user = insert(:user, confirmation_pending: true)
|
user = insert(:user, confirmation_pending: true)
|
||||||
|
@ -29,8 +30,6 @@ test "with a user that's not confirmed and a config requiring confirmation, it r
|
||||||
|> UserEnabledPlug.call(%{})
|
|> UserEnabledPlug.call(%{})
|
||||||
|
|
||||||
assert conn.assigns.user == nil
|
assert conn.assigns.user == nil
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :account_activation_required], old)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "with a user that is deactivated, it removes that user", %{conn: conn} do
|
test "with a user that is deactivated, it removes that user", %{conn: conn} do
|
||||||
|
|
|
@ -67,6 +67,8 @@ test "return error if has not assoc " do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check])
|
||||||
|
|
||||||
test "raises if it detects unapplied migrations" do
|
test "raises if it detects unapplied migrations" do
|
||||||
assert_raise Pleroma.Repo.UnappliedMigrationsError, fn ->
|
assert_raise Pleroma.Repo.UnappliedMigrationsError, fn ->
|
||||||
capture_log(&Repo.check_migrations_applied!/0)
|
capture_log(&Repo.check_migrations_applied!/0)
|
||||||
|
@ -74,18 +76,8 @@ test "raises if it detects unapplied migrations" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "doesn't do anything if disabled" do
|
test "doesn't do anything if disabled" do
|
||||||
disable_migration_check =
|
|
||||||
Pleroma.Config.get([:i_am_aware_this_may_cause_data_loss, :disable_migration_check])
|
|
||||||
|
|
||||||
Pleroma.Config.put([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true)
|
Pleroma.Config.put([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true)
|
||||||
|
|
||||||
on_exit(fn ->
|
|
||||||
Pleroma.Config.put(
|
|
||||||
[:i_am_aware_this_may_cause_data_loss, :disable_migration_check],
|
|
||||||
disable_migration_check
|
|
||||||
)
|
|
||||||
end)
|
|
||||||
|
|
||||||
assert :ok == Repo.check_migrations_applied!()
|
assert :ok == Repo.check_migrations_applied!()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,6 +26,7 @@ defmacro clear_config(config_path, do: yield) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc "Stores initial config value and restores it after *all* test examples are executed."
|
||||||
defmacro clear_config_all(config_path) do
|
defmacro clear_config_all(config_path) do
|
||||||
quote do
|
quote do
|
||||||
clear_config_all(unquote(config_path)) do
|
clear_config_all(unquote(config_path)) do
|
||||||
|
@ -33,6 +34,11 @@ defmacro clear_config_all(config_path) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Stores initial config value and restores it after *all* test examples are executed.
|
||||||
|
Only use if *all* test examples should work with the same stubbed value
|
||||||
|
(*no* examples set a different value).
|
||||||
|
"""
|
||||||
defmacro clear_config_all(config_path, do: yield) do
|
defmacro clear_config_all(config_path, do: yield) do
|
||||||
quote do
|
quote do
|
||||||
setup_all do
|
setup_all do
|
||||||
|
|
|
@ -15,6 +15,8 @@ defmodule Pleroma.UserSearchTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "User.search" do
|
describe "User.search" do
|
||||||
|
clear_config([:instance, :limit_to_local_content])
|
||||||
|
|
||||||
test "excluded invisible users from results" do
|
test "excluded invisible users from results" do
|
||||||
user = insert(:user, %{nickname: "john t1000"})
|
user = insert(:user, %{nickname: "john t1000"})
|
||||||
insert(:user, %{invisible: true, nickname: "john t800"})
|
insert(:user, %{invisible: true, nickname: "john t800"})
|
||||||
|
@ -127,8 +129,6 @@ test "find only local users for authenticated users when `limit_to_local_content
|
||||||
insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
|
insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
|
||||||
|
|
||||||
assert [%{id: ^id}] = User.search("lain")
|
assert [%{id: ^id}] = User.search("lain")
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "find all users for unauthenticated users when `limit_to_local_content` is `false`" do
|
test "find all users for unauthenticated users when `limit_to_local_content` is `false`" do
|
||||||
|
@ -145,8 +145,6 @@ test "find all users for unauthenticated users when `limit_to_local_content` is
|
||||||
|> Enum.sort()
|
|> Enum.sort()
|
||||||
|
|
||||||
assert [u1.id, u2.id, u3.id] == results
|
assert [u1.id, u2.id, u3.id] == results
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not yield false-positive matches" do
|
test "does not yield false-positive matches" do
|
||||||
|
|
|
@ -297,15 +297,7 @@ test "local users do not automatically follow local locked accounts" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "unfollow/2" do
|
describe "unfollow/2" do
|
||||||
setup do
|
clear_config([:instance, :external_user_synchronization])
|
||||||
setting = Pleroma.Config.get([:instance, :external_user_synchronization])
|
|
||||||
|
|
||||||
on_exit(fn ->
|
|
||||||
Pleroma.Config.put([:instance, :external_user_synchronization], setting)
|
|
||||||
end)
|
|
||||||
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
|
|
||||||
test "unfollow with syncronizes external user" do
|
test "unfollow with syncronizes external user" do
|
||||||
Pleroma.Config.put([:instance, :external_user_synchronization], true)
|
Pleroma.Config.put([:instance, :external_user_synchronization], true)
|
||||||
|
@ -383,6 +375,7 @@ test "fetches correct profile for nickname beginning with number" do
|
||||||
password_confirmation: "test",
|
password_confirmation: "test",
|
||||||
email: "email@example.com"
|
email: "email@example.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_config([:instance, :autofollowed_nicknames])
|
clear_config([:instance, :autofollowed_nicknames])
|
||||||
clear_config([:instance, :welcome_message])
|
clear_config([:instance, :welcome_message])
|
||||||
clear_config([:instance, :welcome_user_nickname])
|
clear_config([:instance, :welcome_user_nickname])
|
||||||
|
@ -1754,17 +1747,14 @@ test "changes email", %{user: user} do
|
||||||
|
|
||||||
describe "get_cached_by_nickname_or_id" do
|
describe "get_cached_by_nickname_or_id" do
|
||||||
setup do
|
setup do
|
||||||
limit_to_local_content = Pleroma.Config.get([:instance, :limit_to_local_content])
|
|
||||||
local_user = insert(:user)
|
local_user = insert(:user)
|
||||||
remote_user = insert(:user, nickname: "nickname@example.com", local: false)
|
remote_user = insert(:user, nickname: "nickname@example.com", local: false)
|
||||||
|
|
||||||
on_exit(fn ->
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local_content)
|
|
||||||
end)
|
|
||||||
|
|
||||||
[local_user: local_user, remote_user: remote_user]
|
[local_user: local_user, remote_user: remote_user]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
clear_config([:instance, :limit_to_local_content])
|
||||||
|
|
||||||
test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
|
test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
|
||||||
remote_user: remote_user
|
remote_user: remote_user
|
||||||
} do
|
} do
|
||||||
|
|
|
@ -1224,6 +1224,8 @@ test "creates an undo activity for the last block" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "deletion" do
|
describe "deletion" do
|
||||||
|
clear_config([:instance, :rewrite_policy])
|
||||||
|
|
||||||
test "it creates a delete activity and deletes the original object" do
|
test "it creates a delete activity and deletes the original object" do
|
||||||
note = insert(:note_activity)
|
note = insert(:note_activity)
|
||||||
object = Object.normalize(note)
|
object = Object.normalize(note)
|
||||||
|
@ -1327,11 +1329,8 @@ test "decreases reply count" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it passes delete activity through MRF before deleting the object" do
|
test "it passes delete activity through MRF before deleting the object" do
|
||||||
rewrite_policy = Pleroma.Config.get([:instance, :rewrite_policy])
|
|
||||||
Pleroma.Config.put([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.DropPolicy)
|
Pleroma.Config.put([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.DropPolicy)
|
||||||
|
|
||||||
on_exit(fn -> Pleroma.Config.put([:instance, :rewrite_policy], rewrite_policy) end)
|
|
||||||
|
|
||||||
note = insert(:note_activity)
|
note = insert(:note_activity)
|
||||||
object = Object.normalize(note)
|
object = Object.normalize(note)
|
||||||
|
|
||||||
|
@ -1396,6 +1395,8 @@ test "it filters broken threads" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "update" do
|
describe "update" do
|
||||||
|
clear_config([:instance, :max_pinned_statuses])
|
||||||
|
|
||||||
test "it creates an update activity with the new user data" do
|
test "it creates an update activity with the new user data" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
{:ok, user} = User.ensure_keys_present(user)
|
{:ok, user} = User.ensure_keys_present(user)
|
||||||
|
|
|
@ -26,6 +26,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
|
||||||
[user: user, message: message]
|
[user: user, message: message]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
clear_config(:mrf_hellthread)
|
||||||
|
|
||||||
describe "reject" do
|
describe "reject" do
|
||||||
test "rejects the message if the recipient count is above reject_threshold", %{
|
test "rejects the message if the recipient count is above reject_threshold", %{
|
||||||
message: message
|
message: message
|
||||||
|
|
|
@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
|
||||||
|
|
||||||
alias Pleroma.Web.ActivityPub.MRF.KeywordPolicy
|
alias Pleroma.Web.ActivityPub.MRF.KeywordPolicy
|
||||||
|
|
||||||
|
clear_config(:mrf_keyword)
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []})
|
Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []})
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
|
||||||
|
|
||||||
alias Pleroma.Web.ActivityPub.MRF.MentionPolicy
|
alias Pleroma.Web.ActivityPub.MRF.MentionPolicy
|
||||||
|
|
||||||
|
clear_config(:mrf_mention)
|
||||||
|
|
||||||
test "pass filter if allow list is empty" do
|
test "pass filter if allow list is empty" do
|
||||||
Pleroma.Config.delete([:mrf_mention])
|
Pleroma.Config.delete([:mrf_mention])
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do
|
||||||
"object" => %{"content" => "hi"}
|
"object" => %{"content" => "hi"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_config([:mrf_subchain, :match_actor])
|
||||||
|
|
||||||
test "it matches and processes subchains when the actor matches a configured target" do
|
test "it matches and processes subchains when the actor matches a configured target" do
|
||||||
Pleroma.Config.put([:mrf_subchain, :match_actor], %{
|
Pleroma.Config.put([:mrf_subchain, :match_actor], %{
|
||||||
~r/^https:\/\/banned.com/s => [DropPolicy]
|
~r/^https:\/\/banned.com/s => [DropPolicy]
|
||||||
|
|
|
@ -19,6 +19,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "handle_incoming" do
|
describe "handle_incoming" do
|
||||||
|
clear_config([:user, :deny_follow_blocked])
|
||||||
|
|
||||||
test "it works for osada follow request" do
|
test "it works for osada follow request" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
|
|
@ -1893,9 +1893,7 @@ test "returns error when status is not exist", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "when configuration from database is off", %{conn: conn} do
|
test "when configuration from database is off", %{conn: conn} do
|
||||||
initial = Config.get(:configurable_from_database)
|
|
||||||
Config.put(:configurable_from_database, false)
|
Config.put(:configurable_from_database, false)
|
||||||
on_exit(fn -> Config.put(:configurable_from_database, initial) end)
|
|
||||||
conn = get(conn, "/api/pleroma/admin/config")
|
conn = get(conn, "/api/pleroma/admin/config")
|
||||||
|
|
||||||
assert json_response(conn, 400) ==
|
assert json_response(conn, 400) ==
|
||||||
|
|
|
@ -68,6 +68,7 @@ test "with the safe_dm_mention option set, it does not mention people beyond the
|
||||||
har = insert(:user)
|
har = insert(:user)
|
||||||
jafnhar = insert(:user)
|
jafnhar = insert(:user)
|
||||||
tridi = insert(:user)
|
tridi = insert(:user)
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :safe_dm_mentions], true)
|
Pleroma.Config.put([:instance, :safe_dm_mentions], true)
|
||||||
|
|
||||||
{:ok, activity} =
|
{:ok, activity} =
|
||||||
|
|
|
@ -15,6 +15,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
describe "account fetching" do
|
describe "account fetching" do
|
||||||
|
clear_config([:instance, :limit_to_local_content])
|
||||||
|
|
||||||
test "works by id" do
|
test "works by id" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
@ -44,7 +46,6 @@ test "works by nickname" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "works by nickname for remote users" do
|
test "works by nickname for remote users" do
|
||||||
limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], false)
|
Pleroma.Config.put([:instance, :limit_to_local_content], false)
|
||||||
user = insert(:user, nickname: "user@example.com", local: false)
|
user = insert(:user, nickname: "user@example.com", local: false)
|
||||||
|
|
||||||
|
@ -52,13 +53,11 @@ test "works by nickname for remote users" do
|
||||||
build_conn()
|
build_conn()
|
||||||
|> get("/api/v1/accounts/#{user.nickname}")
|
|> get("/api/v1/accounts/#{user.nickname}")
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
|
|
||||||
assert %{"id" => id} = json_response(conn, 200)
|
assert %{"id" => id} = json_response(conn, 200)
|
||||||
assert id == user.id
|
assert id == user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
test "respects limit_to_local_content == :all for remote user nicknames" do
|
test "respects limit_to_local_content == :all for remote user nicknames" do
|
||||||
limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], :all)
|
Pleroma.Config.put([:instance, :limit_to_local_content], :all)
|
||||||
|
|
||||||
user = insert(:user, nickname: "user@example.com", local: false)
|
user = insert(:user, nickname: "user@example.com", local: false)
|
||||||
|
@ -67,12 +66,10 @@ test "respects limit_to_local_content == :all for remote user nicknames" do
|
||||||
build_conn()
|
build_conn()
|
||||||
|> get("/api/v1/accounts/#{user.nickname}")
|
|> get("/api/v1/accounts/#{user.nickname}")
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
|
|
||||||
assert json_response(conn, 404)
|
assert json_response(conn, 404)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
|
test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
|
||||||
limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
|
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
|
||||||
|
|
||||||
user = insert(:user, nickname: "user@example.com", local: false)
|
user = insert(:user, nickname: "user@example.com", local: false)
|
||||||
|
@ -90,7 +87,6 @@ test "respects limit_to_local_content == :unauthenticated for remote user nickna
|
||||||
|> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
|
|> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
|
||||||
|> get("/api/v1/accounts/#{user.nickname}")
|
|> get("/api/v1/accounts/#{user.nickname}")
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
|
|
||||||
assert %{"id" => id} = json_response(conn, 200)
|
assert %{"id" => id} = json_response(conn, 200)
|
||||||
assert id == user.id
|
assert id == user.id
|
||||||
end
|
end
|
||||||
|
@ -677,6 +673,8 @@ test "returns error when user already registred", %{conn: conn, valid_params: va
|
||||||
assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
|
assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
clear_config([Pleroma.Plugs.RemoteIp, :enabled])
|
||||||
|
|
||||||
test "rate limit", %{conn: conn} do
|
test "rate limit", %{conn: conn} do
|
||||||
Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
|
Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
|
||||||
app_token = insert(:oauth_token, user: nil)
|
app_token = insert(:oauth_token, user: nil)
|
||||||
|
|
|
@ -21,6 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
|
|
||||||
clear_config([:instance, :federating])
|
clear_config([:instance, :federating])
|
||||||
clear_config([:instance, :allow_relay])
|
clear_config([:instance, :allow_relay])
|
||||||
|
clear_config([:rich_media, :enabled])
|
||||||
|
|
||||||
describe "posting statuses" do
|
describe "posting statuses" do
|
||||||
setup do: oauth_access(["write:statuses"])
|
setup do: oauth_access(["write:statuses"])
|
||||||
|
|
|
@ -7,11 +7,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
|
||||||
import Mock
|
import Mock
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
|
|
||||||
setup do
|
clear_config(:media_proxy)
|
||||||
media_proxy_config = Config.get([:media_proxy]) || []
|
clear_config([Pleroma.Web.Endpoint, :secret_key_base])
|
||||||
on_exit(fn -> Config.put([:media_proxy], media_proxy_config) end)
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it returns 404 when MediaProxy disabled", %{conn: conn} do
|
test "it returns 404 when MediaProxy disabled", %{conn: conn} do
|
||||||
Config.put([:media_proxy, :enabled], false)
|
Config.put([:media_proxy, :enabled], false)
|
||||||
|
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.MediaProxyTest do
|
||||||
alias Pleroma.Web.MediaProxy.MediaProxyController
|
alias Pleroma.Web.MediaProxy.MediaProxyController
|
||||||
|
|
||||||
clear_config([:media_proxy, :enabled])
|
clear_config([:media_proxy, :enabled])
|
||||||
|
clear_config(Pleroma.Upload)
|
||||||
|
|
||||||
describe "when enabled" do
|
describe "when enabled" do
|
||||||
setup do
|
setup do
|
||||||
|
@ -224,7 +225,6 @@ test "does not change whitelisted urls" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "ensure Pleroma.Upload base_url is always whitelisted" do
|
test "ensure Pleroma.Upload base_url is always whitelisted" do
|
||||||
upload_config = Pleroma.Config.get([Pleroma.Upload])
|
|
||||||
media_url = "https://media.pleroma.social"
|
media_url = "https://media.pleroma.social"
|
||||||
Pleroma.Config.put([Pleroma.Upload, :base_url], media_url)
|
Pleroma.Config.put([Pleroma.Upload, :base_url], media_url)
|
||||||
|
|
||||||
|
@ -232,8 +232,6 @@ test "ensure Pleroma.Upload base_url is always whitelisted" do
|
||||||
encoded = url(url)
|
encoded = url(url)
|
||||||
|
|
||||||
assert String.starts_with?(encoded, media_url)
|
assert String.starts_with?(encoded, media_url)
|
||||||
|
|
||||||
Pleroma.Config.put([Pleroma.Upload], upload_config)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,8 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
alias Pleroma.Web.Metadata.Providers.OpenGraph
|
alias Pleroma.Web.Metadata.Providers.OpenGraph
|
||||||
|
|
||||||
|
clear_config([Pleroma.Web.Metadata, :unfurl_nsfw])
|
||||||
|
|
||||||
test "it renders all supported types of attachments and skips unknown types" do
|
test "it renders all supported types of attachments and skips unknown types" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
|
||||||
alias Pleroma.Web.Metadata.Utils
|
alias Pleroma.Web.Metadata.Utils
|
||||||
alias Pleroma.Web.Router
|
alias Pleroma.Web.Router
|
||||||
|
|
||||||
|
clear_config([Pleroma.Web.Metadata, :unfurl_nsfw])
|
||||||
|
|
||||||
test "it renders twitter card for user info" do
|
test "it renders twitter card for user info" do
|
||||||
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
|
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
|
||||||
avatar_url = Utils.attachment_url(User.avatar_url(user))
|
avatar_url = Utils.attachment_url(User.avatar_url(user))
|
||||||
|
|
|
@ -6,7 +6,9 @@ defmodule Pleroma.Web.NodeInfoTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
clear_config([:mrf_simple])
|
clear_config([:mrf_simple])
|
||||||
|
clear_config(:instance)
|
||||||
|
|
||||||
test "GET /.well-known/nodeinfo", %{conn: conn} do
|
test "GET /.well-known/nodeinfo", %{conn: conn} do
|
||||||
links =
|
links =
|
||||||
|
@ -63,11 +65,6 @@ test "returns software.repository field in nodeinfo 2.1", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns fieldsLimits field", %{conn: conn} do
|
test "returns fieldsLimits field", %{conn: conn} do
|
||||||
max_account_fields = Pleroma.Config.get([:instance, :max_account_fields])
|
|
||||||
max_remote_account_fields = Pleroma.Config.get([:instance, :max_remote_account_fields])
|
|
||||||
account_field_name_length = Pleroma.Config.get([:instance, :account_field_name_length])
|
|
||||||
account_field_value_length = Pleroma.Config.get([:instance, :account_field_value_length])
|
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :max_account_fields], 10)
|
Pleroma.Config.put([:instance, :max_account_fields], 10)
|
||||||
Pleroma.Config.put([:instance, :max_remote_account_fields], 15)
|
Pleroma.Config.put([:instance, :max_remote_account_fields], 15)
|
||||||
Pleroma.Config.put([:instance, :account_field_name_length], 255)
|
Pleroma.Config.put([:instance, :account_field_name_length], 255)
|
||||||
|
@ -82,11 +79,6 @@ test "returns fieldsLimits field", %{conn: conn} do
|
||||||
assert response["metadata"]["fieldsLimits"]["maxRemoteFields"] == 15
|
assert response["metadata"]["fieldsLimits"]["maxRemoteFields"] == 15
|
||||||
assert response["metadata"]["fieldsLimits"]["nameLength"] == 255
|
assert response["metadata"]["fieldsLimits"]["nameLength"] == 255
|
||||||
assert response["metadata"]["fieldsLimits"]["valueLength"] == 2048
|
assert response["metadata"]["fieldsLimits"]["valueLength"] == 2048
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :max_account_fields], max_account_fields)
|
|
||||||
Pleroma.Config.put([:instance, :max_remote_account_fields], max_remote_account_fields)
|
|
||||||
Pleroma.Config.put([:instance, :account_field_name_length], account_field_name_length)
|
|
||||||
Pleroma.Config.put([:instance, :account_field_value_length], account_field_value_length)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
|
test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
|
||||||
|
@ -112,9 +104,10 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
|
||||||
Pleroma.Config.put([:instance, :safe_dm_mentions], option)
|
Pleroma.Config.put([:instance, :safe_dm_mentions], option)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it shows if federation is enabled/disabled", %{conn: conn} do
|
describe "`metadata/federation/enabled`" do
|
||||||
original = Pleroma.Config.get([:instance, :federating])
|
clear_config([:instance, :federating])
|
||||||
|
|
||||||
|
test "it shows if federation is enabled/disabled", %{conn: conn} do
|
||||||
Pleroma.Config.put([:instance, :federating], true)
|
Pleroma.Config.put([:instance, :federating], true)
|
||||||
|
|
||||||
response =
|
response =
|
||||||
|
@ -132,8 +125,7 @@ test "it shows if federation is enabled/disabled", %{conn: conn} do
|
||||||
|> json_response(:ok)
|
|> json_response(:ok)
|
||||||
|
|
||||||
assert response["metadata"]["federation"]["enabled"] == false
|
assert response["metadata"]["federation"]["enabled"] == false
|
||||||
|
end
|
||||||
Pleroma.Config.put([:instance, :federating], original)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it shows MRF transparency data if enabled", %{conn: conn} do
|
test "it shows MRF transparency data if enabled", %{conn: conn} do
|
||||||
|
|
|
@ -17,7 +17,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|
||||||
key: "_test",
|
key: "_test",
|
||||||
signing_salt: "cooldude"
|
signing_salt: "cooldude"
|
||||||
]
|
]
|
||||||
clear_config_all([:instance, :account_activation_required])
|
|
||||||
|
clear_config([:instance, :account_activation_required])
|
||||||
|
|
||||||
describe "in OAuth consumer mode, " do
|
describe "in OAuth consumer mode, " do
|
||||||
setup do
|
setup do
|
||||||
|
|
|
@ -96,6 +96,32 @@ test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "GET /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"})
|
||||||
|
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert result == []
|
||||||
|
|
||||||
|
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
|
||||||
|
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
|
||||||
|
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
[%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result
|
||||||
|
|
||||||
|
assert represented_user["id"] == other_user.id
|
||||||
|
end
|
||||||
|
|
||||||
test "/api/v1/pleroma/conversations/:id" do
|
test "/api/v1/pleroma/conversations/:id" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
%{user: other_user, conn: conn} = oauth_access(["read:statuses"])
|
%{user: other_user, conn: conn} = oauth_access(["read:statuses"])
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.FederatingPlugTest do
|
defmodule Pleroma.Web.FederatingPlugTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
clear_config_all([:instance, :federating])
|
|
||||||
|
clear_config([:instance, :federating])
|
||||||
|
|
||||||
test "returns and halt the conn when federating is disabled" do
|
test "returns and halt the conn when federating is disabled" do
|
||||||
Pleroma.Config.put([:instance, :federating], false)
|
Pleroma.Config.put([:instance, :federating], false)
|
||||||
|
|
|
@ -20,7 +20,7 @@ defmodule Pleroma.Web.StreamerTest do
|
||||||
@streamer_timeout 150
|
@streamer_timeout 150
|
||||||
@streamer_start_wait 10
|
@streamer_start_wait 10
|
||||||
|
|
||||||
clear_config_all([:instance, :skip_thread_containment])
|
clear_config([:instance, :skip_thread_containment])
|
||||||
|
|
||||||
describe "user streams" do
|
describe "user streams" do
|
||||||
setup do
|
setup do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
|
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
|
||||||
|
@ -92,15 +92,13 @@ test "follows user", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
user2 = insert(:user)
|
user2 = insert(:user)
|
||||||
|
|
||||||
response =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|
||||||
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Account followed!"
|
assert redirected_to(conn) == "/users/#{user2.id}"
|
||||||
assert user2.follower_address in User.following(user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns error when user is deactivated", %{conn: conn} do
|
test "returns error when user is deactivated", %{conn: conn} do
|
||||||
|
@ -149,14 +147,13 @@ test "returns success result when user already in followers", %{conn: conn} do
|
||||||
user2 = insert(:user)
|
user2 = insert(:user)
|
||||||
{:ok, _, _, _} = CommonAPI.follow(user, user2)
|
{:ok, _, _, _} = CommonAPI.follow(user, user2)
|
||||||
|
|
||||||
response =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, refresh_record(user))
|
|> assign(:user, refresh_record(user))
|
||||||
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|
||||||
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Account followed!"
|
assert redirected_to(conn) == "/users/#{user2.id}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -165,14 +162,13 @@ test "follows", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
user2 = insert(:user)
|
user2 = insert(:user)
|
||||||
|
|
||||||
response =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> post(remote_follow_path(conn, :do_follow), %{
|
|> post(remote_follow_path(conn, :do_follow), %{
|
||||||
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
|
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
|
||||||
})
|
})
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Account followed!"
|
assert redirected_to(conn) == "/users/#{user2.id}"
|
||||||
assert user2.follower_address in User.following(user)
|
assert user2.follower_address in User.following(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -117,15 +117,8 @@ test "it registers a new user and parses mentions in the bio" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "register with one time token" do
|
describe "register with one time token" do
|
||||||
setup do
|
clear_config([:instance, :registrations_open]) do
|
||||||
setting = Pleroma.Config.get([:instance, :registrations_open])
|
|
||||||
|
|
||||||
if setting do
|
|
||||||
Pleroma.Config.put([:instance, :registrations_open], false)
|
Pleroma.Config.put([:instance, :registrations_open], false)
|
||||||
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
:ok
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns user on success" do
|
test "returns user on success" do
|
||||||
|
@ -191,14 +184,11 @@ test "returns error on expired token" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "registers with date limited token" do
|
describe "registers with date limited token" do
|
||||||
setup do
|
clear_config([:instance, :registrations_open]) do
|
||||||
setting = Pleroma.Config.get([:instance, :registrations_open])
|
|
||||||
|
|
||||||
if setting do
|
|
||||||
Pleroma.Config.put([:instance, :registrations_open], false)
|
Pleroma.Config.put([:instance, :registrations_open], false)
|
||||||
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
setup do
|
||||||
data = %{
|
data = %{
|
||||||
"nickname" => "vinny",
|
"nickname" => "vinny",
|
||||||
"email" => "pasta@pizza.vs",
|
"email" => "pasta@pizza.vs",
|
||||||
|
@ -256,15 +246,8 @@ test "returns an error on overdue date", %{data: data} do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "registers with reusable token" do
|
describe "registers with reusable token" do
|
||||||
setup do
|
clear_config([:instance, :registrations_open]) do
|
||||||
setting = Pleroma.Config.get([:instance, :registrations_open])
|
|
||||||
|
|
||||||
if setting do
|
|
||||||
Pleroma.Config.put([:instance, :registrations_open], false)
|
Pleroma.Config.put([:instance, :registrations_open], false)
|
||||||
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
:ok
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns user on success, after him registration fails" do
|
test "returns user on success, after him registration fails" do
|
||||||
|
@ -309,15 +292,8 @@ test "returns user on success, after him registration fails" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "registers with reusable date limited token" do
|
describe "registers with reusable date limited token" do
|
||||||
setup do
|
clear_config([:instance, :registrations_open]) do
|
||||||
setting = Pleroma.Config.get([:instance, :registrations_open])
|
|
||||||
|
|
||||||
if setting do
|
|
||||||
Pleroma.Config.put([:instance, :registrations_open], false)
|
Pleroma.Config.put([:instance, :registrations_open], false)
|
||||||
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
:ok
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns user on success" do
|
test "returns user on success" do
|
||||||
|
|
|
@ -19,7 +19,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
||||||
|
|
||||||
clear_config([:instance])
|
clear_config([:instance])
|
||||||
clear_config([:frontend_configurations, :pleroma_fe])
|
clear_config([:frontend_configurations, :pleroma_fe])
|
||||||
clear_config([:user, :deny_follow_blocked])
|
|
||||||
|
|
||||||
describe "POST /api/pleroma/follow_import" do
|
describe "POST /api/pleroma/follow_import" do
|
||||||
setup do: oauth_access(["follow"])
|
setup do: oauth_access(["follow"])
|
||||||
|
|
32
test/workers/cron/new_users_digest_worker_test.exs
Normal file
32
test/workers/cron/new_users_digest_worker_test.exs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
alias Pleroma.Tests.ObanHelpers
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Workers.Cron.NewUsersDigestWorker
|
||||||
|
|
||||||
|
test "it sends new users digest emails" do
|
||||||
|
yesterday = NaiveDateTime.utc_now() |> Timex.shift(days: -1)
|
||||||
|
admin = insert(:user, %{is_admin: true})
|
||||||
|
user = insert(:user, %{inserted_at: yesterday})
|
||||||
|
user2 = insert(:user, %{inserted_at: yesterday})
|
||||||
|
CommonAPI.post(user, %{"status" => "cofe"})
|
||||||
|
|
||||||
|
NewUsersDigestWorker.perform(nil, nil)
|
||||||
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
|
assert_received {:email, email}
|
||||||
|
assert email.to == [{admin.name, admin.email}]
|
||||||
|
assert email.subject == "#{Pleroma.Config.get([:instance, :name])} New Users"
|
||||||
|
|
||||||
|
refute email.html_body =~ admin.nickname
|
||||||
|
assert email.html_body =~ user.nickname
|
||||||
|
assert email.html_body =~ user2.nickname
|
||||||
|
assert email.html_body =~ "cofe"
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue