Merge branch 'develop' into gun

This commit is contained in:
Alexander Strizhakov 2020-02-21 10:02:37 +03:00
commit 13918cb545
No known key found for this signature in database
GPG key ID: 022896A53AEF1381
56 changed files with 860 additions and 223 deletions

View file

@ -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.
- Support for custom Elixir modules (such as MRF policies)
- 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]`).
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma wont start. For hackney OTP update is not required.
- Add an option `authorized_fetch_mode` to require HTTP signatures for AP fetches.
<details>
<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.
- Tag feed: `/tags/:tag.rss` - list public statuses by hashtag.
- Mastodon API: Add `reacted` property to `emoji_reactions`
- Pleroma API: Add reactions for a single emoji.
</details>
### Fixed

View file

@ -49,7 +49,8 @@
config :pleroma, Pleroma.Repo,
types: Pleroma.PostgresTypes,
telemetry_event: [Pleroma.Repo.Instrumenter],
migration_lock: nil
migration_lock: nil,
parameters: [gin_fuzzy_search_limit: "500"]
config :pleroma, Pleroma.Captcha,
enabled: true,
@ -304,7 +305,8 @@
unfollow_blocked: true,
outgoing_blocks: true,
follow_handshake_timeout: 500,
sign_object_fetches: true
sign_object_fetches: true,
authorized_fetch_mode: false
config :pleroma, :streamer,
workers: 3,
@ -458,13 +460,15 @@
transmogrifier: 20,
scheduled_activities: 10,
background: 5,
attachments_cleanup: 5
attachments_cleanup: 5,
new_users_digest: 1
],
crontab: [
{"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
{"0 * * * *", Pleroma.Workers.Cron.StatsWorker},
{"* * * * *", 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,
@ -538,6 +542,8 @@
text_muted_color: "#b9b9ba"
}
config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: false
config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics"
config :pleroma, Pleroma.ScheduledActivity,

View file

@ -101,7 +101,7 @@
%{
key: :versions,
type: {:list, :atom},
description: "List of TLS version to use",
description: "List of TLS versions to use",
suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"]
}
]
@ -534,7 +534,8 @@
%{
key: :description,
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: [
"Very cool instance"
]
@ -770,7 +771,7 @@
key: :cleanup_attachments,
type: :boolean,
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.
Enabling this will increase load to database when deleting statuses on larger instances.
"""
@ -838,7 +839,7 @@
%{
key: :healthcheck,
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,
@ -1296,14 +1297,14 @@
%{
key: :media_removal,
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"]
},
%{
key: :media_nsfw,
label: "Media NSFW",
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"]
},
%{
@ -1422,21 +1423,21 @@
key: :reject,
type: [:string, :regex],
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]
},
%{
key: :federated_timeline_removal,
type: [:string, :regex],
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]
},
%{
key: :replace,
type: [{:tuple, :string, :string}, {:tuple, :regex, :string}],
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"}]
}
]
@ -1451,7 +1452,7 @@
%{
key: :actors,
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"]
}
]
@ -1855,9 +1856,8 @@
type: :string,
description:
"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," <>
" is unavailable for an extended period, or otherwise can't respond, someone else on the list can.",
suggestions: ["Subject"]
" It's best if this email is not a personal email address, but rather a group email to the instance moderation team.",
suggestions: ["mailto:moderators@pleroma.com"]
},
%{
key: :public_key,
@ -1924,7 +1924,7 @@
key: :admin_token,
type: :string,
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)",
suggestions: [
activity_expiration: 10,
attachments_cleanup: 5,
background: 5,
federator_incoming: 50,
federator_outgoing: 50,
@ -2001,6 +2002,12 @@
description: "Activity expiration queue",
suggestions: [10]
},
%{
key: :attachments_cleanup,
type: :integer,
description: "Attachment deletion queue",
suggestions: [5]
},
%{
key: :background,
type: :integer,
@ -2099,7 +2106,7 @@
%{
key: :enabled,
type: :boolean,
description: "Enables/disables RichMedia."
description: "Enables RichMedia parsing of URLs."
},
%{
key: :ignore_hosts,
@ -2145,8 +2152,7 @@
%{
key: :enabled,
type: :boolean,
description:
"If enabled, when a new user is federated with, fetch some of their latest posts"
description: "Fetch posts when a new user is federated with"
},
%{
key: :pages,
@ -2165,13 +2171,13 @@
%{
key: :class,
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]
},
%{
key: :rel,
type: [:string, false],
description: "Override the rel attribute. `False` to clear",
description: "Override the rel attribute. Disable to clear",
suggestions: ["ugc", "noopener noreferrer", false]
},
%{
@ -2281,7 +2287,7 @@
key: :ssl,
label: "SSL",
type: :boolean,
description: "`True` to use SSL, usually implies the port 636"
description: "Enable to use SSL, usually implies the port 636"
},
%{
key: :sslopts,
@ -2308,7 +2314,7 @@
key: :tls,
label: "TLS",
type: :boolean,
description: "`True` to start TLS, usually implies the port 389"
description: "Enable to use STARTTLS, usually implies the port 389"
},
%{
key: :tlsopts,
@ -2358,7 +2364,7 @@
description:
"OAuth admin scope requirement toggle. " <>
"If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token " <>
"(client app must support admin scopes). If `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."
},
%{
@ -2380,7 +2386,7 @@
key: :oauth_consumer_strategies,
type: {:list, :string},
description:
"The list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
"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\"" <>
" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_<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,
key: :oauth2,
@ -2517,7 +2537,7 @@
%{
key: :clean_expired_tokens,
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,
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,
type: :boolean,
description: "Enable/disable the plug. Default: `false`."
description: "Enable/disable the plug. Default: disabled."
},
%{
key: :headers,
@ -3017,7 +3037,7 @@
%{
key: :enabled,
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,
type: :boolean,
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"
}
]
}

View file

@ -96,6 +96,8 @@
config :pleroma, Pleroma.Gun.API, Pleroma.Gun.API.Mock
config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true
if File.exists?("./config/test.secret.exs") do
import_config "test.secret.exs"
else

View file

@ -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..."}]}
]
```
## `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..."}]}
]
```

View file

@ -1,4 +1,21 @@
# 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`)
2. Run `git pull`. This pulls the latest changes from upstream.
3. Run `mix deps.get`. This pulls in any new dependencies.

View file

@ -143,10 +143,11 @@ config :pleroma, :mrf_user_allowlist,
* `:reject` rejects the message entirely
### :activitypub
* ``unfollow_blocked``: Whether blocks result in people getting unfollowed
* ``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
* ``sign_object_fetches``: Sign object fetches with HTTP signatures
* `unfollow_blocked`: Whether blocks result in people getting unfollowed
* `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
* `sign_object_fetches`: Sign object fetches with HTTP signatures
* `authorized_fetch_mode`: Require HTTP signatures for AP fetches
### :fetch_initial_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.
- `: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
### Oban

View file

@ -1,4 +1,5 @@
# 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.
Possible uses include:
@ -10,7 +11,8 @@ Possible uses include:
* removing media from messages
* 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.
## 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.
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,
[...]
quarantined_instances: ["instance.example", "other.example"]
@ -28,15 +31,15 @@ config :pleroma, :instance,
`SimplePolicy` is capable of handling most common admin tasks.
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,
[...]
rewrite_policy: Pleroma.Web.ActivityPub.MRF.SimplePolicy
```
Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_simple` config object. These groups are:
Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_simple` config object. These groups are:
* `media_removal`: Servers in this group will have media stripped from incoming messages.
* `media_nsfw`: Servers in this group will have the #nsfw tag and sensitive setting injected into incoming messages which contain media.
@ -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`:
```
```elixir
config :pleroma, :instance,
rewrite_policy: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
@ -60,30 +63,31 @@ config :pleroma, :mrf_simple,
reject: ["spam.com"],
federated_timeline_removal: ["spam.university"],
report_removal: ["whiny.whiner"]
```
### Use with Care
The effects of MRF policies can be very drastic. It is important to use this functionality carefully. Always try to talk to an admin before writing an MRF policy concerning their instance.
The effects of MRF policies can be very drastic. It is important to use this functionality carefully. Always try to talk to an admin before writing an MRF policy concerning their instance.
## Writing your own MRF Policy
As discussed above, the MRF system is a modular system that supports pluggable policies. This means that an admin may write a custom MRF policy in Elixir or any other language that runs on the Erlang VM, by specifying the module name in the `rewrite_policy` config setting.
As discussed above, the MRF system is a modular system that supports pluggable policies. This means that an admin may write a custom MRF policy in Elixir or any other language that runs on the Erlang VM, by specifying the module name in the `rewrite_policy` config setting.
For example, here is a sample policy module which rewrites all messages to "new message content":
```elixir
# This is a sample MRF policy which rewrites all Notes to have "new message
# content."
defmodule Site.RewritePolicy do
@behavior Pleroma.Web.ActivityPub.MRF
defmodule Pleroma.Web.ActivityPub.MRF.RewritePolicy do
@moduledoc "MRF policy which rewrites all Notes to have 'new message content'."
@behaviour Pleroma.Web.ActivityPub.MRF
# Catch messages which contain Note objects with actual data to filter.
# Capture the object as `object`, the message content as `content` and the
# message itself as `message`.
@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
# Subject / CW is stored as summary instead of `name` like other AS2 objects
# because of Mastodon doing it that way.
@ -106,17 +110,22 @@ defmodule Site.RewritePolicy do
# Let all other messages through without modifying them.
@impl true
def filter(message), do: {:ok, message}
@impl true
def describe do
{:ok, %{mrf_sample: %{content: "new message content"}}}`
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,
rewrite_policy: [
Pleroma.Web.ActivityPub.MRF.SimplePolicy,
Site.RewritePolicy
Pleroma.Web.ActivityPub.MRF.RewritePolicy
]
```
Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request.
Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request.

View file

@ -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.
### 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
* [Backup your instance](../administration/backup.md)
* [Hardening your instance](../configuration/hardening.md)
* [How to activate mediaproxy](../configuration/howto_mediaproxy.md)
* [Updating your instance](../administration/updating.md)
## Questions
Questions about the installation or didnt 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**.

View 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

View file

@ -4,6 +4,7 @@
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
import Plug.Conn
import Phoenix.Controller, only: [get_format: 1, text: 2]
require Logger
def init(options) do
@ -15,25 +16,27 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
end
def call(conn, _opts) do
headers = get_req_header(conn, "signature")
signature = Enum.at(headers, 0)
if get_format(conn) == "activity+json" do
conn
|> maybe_assign_valid_signature()
|> maybe_require_signature()
else
conn
end
end
if signature do
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
conn =
conn
|> put_req_header(
"(request-target)",
String.downcase("#{conn.method}") <> " #{conn.request_path}"
)
request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}"
conn =
if conn.assigns[:digest] do
conn
|> put_req_header("digest", conn.assigns[:digest])
else
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))
@ -42,4 +45,21 @@ def call(conn, _opts) do
conn
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

View file

@ -41,24 +41,29 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
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),
%Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
Object.normalize(activity) do
reactions =
emoji_reactions
|> Enum.map(fn [emoji, user_ap_ids] ->
users =
Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
|> Enum.filter(& &1)
if params["emoji"] && params["emoji"] != emoji do
nil
else
users =
Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
|> Enum.filter(& &1)
%{
name: emoji,
count: length(users),
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
me: !!(user && user.ap_id in user_ap_ids)
}
%{
name: emoji,
count: length(users),
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
me: !!(user && user.ap_id in user_ap_ids)
}
end
end)
|> Enum.filter(& &1)
conn
|> json(reactions)

View file

@ -271,6 +271,7 @@ defmodule Pleroma.Web.Router do
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:api)
get("/statuses/:id/reactions/:emoji", PleromaAPIController, :emoji_reactions_by)
get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by)
end

View 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 %>

View 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>

View file

@ -1,5 +1,5 @@
# 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
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
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
render(conn, "followed.html", %{error: false})
redirect(conn, to: "/users/#{followee.id}")
else
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)},
{_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
render(conn, "followed.html", %{error: false})
redirect(conn, to: "/users/#{followee.id}")
else
error ->
handle_follow_error(conn, error)

View file

@ -12,4 +12,8 @@ def format_date(date) when is_binary(date) do
|> Timex.parse!("{ISO:Extended:Z}")
|> Timex.format!("{Mshort} {D}, {YYYY} {h24}:{m}")
end
def admin_user_url(%{id: id}) do
Pleroma.Web.Endpoint.url() <> "/pleroma/admin/#/users/" <> id
end
end

View 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

View file

@ -17,7 +17,11 @@ def up do
Repo.stream(query)
|> Enum.each(fn %{id: user_id, bookmarks: bookmarks} ->
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)
end)
end)

View file

@ -1,7 +1,8 @@
defmodule Pleroma.Repo.Migrations.AddFollowingAddressFromSourceData do
use Ecto.Migration
import Ecto.Query
alias Pleroma.User
import Ecto.Query
require Logger
use Ecto.Migration
def change do
query =
@ -19,6 +20,9 @@ def change do
:following_address
])
|> Pleroma.Repo.update()
user ->
Logger.warn("User #{user.id} / #{user.nickname} does not seem to have source_data")
end)
end
end

View file

@ -2,6 +2,8 @@ defmodule Pleroma.Repo.Migrations.CopyMutedToMutedNotifications do
use Ecto.Migration
def change do
execute("update users set info = '{}' where info is null")
execute(
"update users set info = safe_jsonb_set(info, '{muted_notifications}', info->'mutes', true) where local = true"
)

View file

@ -138,6 +138,8 @@ test "when association is not loaded" do
}
end
clear_config([:instance, :limit_to_local_content])
test "finds utf8 text in statuses", %{
japanese_activity: japanese_activity,
user: user
@ -165,7 +167,6 @@ test "find only local statuses for unauthenticated users when `limit_to_local_c
%{local_activity: local_activity} do
Pleroma.Config.put([:instance, :limit_to_local_content], :all)
assert [^local_activity] = Activity.search(nil, "find me")
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
end
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)
assert [^local_activity, ^remote_activity] = activities
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
end
end

View file

@ -11,6 +11,7 @@ defmodule Pleroma.HTTP.RequestBuilderTest do
describe "headers/2" do
clear_config([:http, :send_user_agent])
clear_config([:http, :user_agent])
test "don't send pleroma user agent" do
assert RequestBuilder.headers(%Request{}, []) == %Request{headers: []}

View file

@ -75,6 +75,7 @@ test "ensures cache is cleared for the object" do
describe "delete attachments" do
clear_config([Pleroma.Upload])
clear_config([:instance, :cleanup_attachments])
test "Disabled via config" do
Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)

View file

@ -23,6 +23,8 @@ test "does nothing if a user is assigned", %{conn: conn} do
end
describe "when secret set it assigns an admin user" do
clear_config([:admin_token])
test "with `admin_token` query parameter", %{conn: conn} do
Pleroma.Config.put(:admin_token, "password123")

View file

@ -9,6 +9,7 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
clear_config([:http_securiy, :enabled])
clear_config([:http_security, :sts])
clear_config([:http_security, :referrer_policy])
describe "http security enabled" do
setup do

View file

@ -7,6 +7,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
alias Pleroma.Web.Plugs.HTTPSignaturePlug
import Plug.Conn
import Phoenix.Controller, only: [put_format: 2]
import Mock
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",
"keyId=\"http://mastodon.example.org/users/admin#main-key"
)
|> put_format("activity+json")
|> HTTPSignaturePlug.call(%{})
assert conn.assigns.valid_signature == true
assert conn.halted == false
assert called(HTTPSignatures.validate_conn(:_))
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

View file

@ -8,6 +8,10 @@ defmodule Pleroma.Plugs.RemoteIpTest do
alias Pleroma.Plugs.RemoteIp
import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2]
clear_config(RemoteIp)
test "disabled" do
Pleroma.Config.put(RemoteIp, enabled: false)

View file

@ -8,6 +8,8 @@ defmodule Pleroma.Plugs.UserEnabledPlugTest do
alias Pleroma.Plugs.UserEnabledPlug
import Pleroma.Factory
clear_config([:instance, :account_activation_required])
test "doesn't do anything if the user isn't set", %{conn: conn} do
ret_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",
%{conn: conn} do
old = Pleroma.Config.get([:instance, :account_activation_required])
Pleroma.Config.put([:instance, :account_activation_required], 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(%{})
assert conn.assigns.user == nil
Pleroma.Config.put([:instance, :account_activation_required], old)
end
test "with a user that is deactivated, it removes that user", %{conn: conn} do

View file

@ -67,6 +67,8 @@ test "return error if has not assoc " do
:ok
end
clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check])
test "raises if it detects unapplied migrations" do
assert_raise Pleroma.Repo.UnappliedMigrationsError, fn ->
capture_log(&Repo.check_migrations_applied!/0)
@ -74,18 +76,8 @@ test "raises if it detects unapplied migrations" do
end
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)
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!()
end
end

View file

@ -26,6 +26,7 @@ defmacro clear_config(config_path, do: yield) do
end
end
@doc "Stores initial config value and restores it after *all* test examples are executed."
defmacro clear_config_all(config_path) do
quote do
clear_config_all(unquote(config_path)) do
@ -33,6 +34,11 @@ defmacro clear_config_all(config_path) do
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
quote do
setup_all do

View file

@ -15,6 +15,8 @@ defmodule Pleroma.UserSearchTest do
end
describe "User.search" do
clear_config([:instance, :limit_to_local_content])
test "excluded invisible users from results" do
user = insert(:user, %{nickname: "john t1000"})
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})
assert [%{id: ^id}] = User.search("lain")
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
end
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()
assert [u1.id, u2.id, u3.id] == results
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
end
test "does not yield false-positive matches" do

View file

@ -297,15 +297,7 @@ test "local users do not automatically follow local locked accounts" do
end
describe "unfollow/2" do
setup do
setting = Pleroma.Config.get([:instance, :external_user_synchronization])
on_exit(fn ->
Pleroma.Config.put([:instance, :external_user_synchronization], setting)
end)
:ok
end
clear_config([:instance, :external_user_synchronization])
test "unfollow with syncronizes external user" do
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",
email: "email@example.com"
}
clear_config([:instance, :autofollowed_nicknames])
clear_config([:instance, :welcome_message])
clear_config([:instance, :welcome_user_nickname])
@ -1754,17 +1747,14 @@ test "changes email", %{user: user} do
describe "get_cached_by_nickname_or_id" do
setup do
limit_to_local_content = Pleroma.Config.get([:instance, :limit_to_local_content])
local_user = insert(:user)
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]
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", %{
remote_user: remote_user
} do

View file

@ -1224,6 +1224,8 @@ test "creates an undo activity for the last block" do
end
describe "deletion" do
clear_config([:instance, :rewrite_policy])
test "it creates a delete activity and deletes the original object" do
note = insert(:note_activity)
object = Object.normalize(note)
@ -1327,11 +1329,8 @@ test "decreases reply count" do
end
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)
on_exit(fn -> Pleroma.Config.put([:instance, :rewrite_policy], rewrite_policy) end)
note = insert(:note_activity)
object = Object.normalize(note)
@ -1396,6 +1395,8 @@ test "it filters broken threads" do
end
describe "update" do
clear_config([:instance, :max_pinned_statuses])
test "it creates an update activity with the new user data" do
user = insert(:user)
{:ok, user} = User.ensure_keys_present(user)

View file

@ -26,6 +26,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
[user: user, message: message]
end
clear_config(:mrf_hellthread)
describe "reject" do
test "rejects the message if the recipient count is above reject_threshold", %{
message: message

View file

@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
alias Pleroma.Web.ActivityPub.MRF.KeywordPolicy
clear_config(:mrf_keyword)
setup do
Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []})
end

View file

@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
alias Pleroma.Web.ActivityPub.MRF.MentionPolicy
clear_config(:mrf_mention)
test "pass filter if allow list is empty" do
Pleroma.Config.delete([:mrf_mention])

View file

@ -14,6 +14,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do
"object" => %{"content" => "hi"}
}
clear_config([:mrf_subchain, :match_actor])
test "it matches and processes subchains when the actor matches a configured target" do
Pleroma.Config.put([:mrf_subchain, :match_actor], %{
~r/^https:\/\/banned.com/s => [DropPolicy]

View file

@ -19,6 +19,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
end
describe "handle_incoming" do
clear_config([:user, :deny_follow_blocked])
test "it works for osada follow request" do
user = insert(:user)

View file

@ -1893,9 +1893,7 @@ test "returns error when status is not exist", %{conn: conn} do
end
test "when configuration from database is off", %{conn: conn} do
initial = Config.get(:configurable_from_database)
Config.put(:configurable_from_database, false)
on_exit(fn -> Config.put(:configurable_from_database, initial) end)
conn = get(conn, "/api/pleroma/admin/config")
assert json_response(conn, 400) ==

View file

@ -68,6 +68,7 @@ test "with the safe_dm_mention option set, it does not mention people beyond the
har = insert(:user)
jafnhar = insert(:user)
tridi = insert(:user)
Pleroma.Config.put([:instance, :safe_dm_mentions], true)
{:ok, activity} =

View file

@ -15,6 +15,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
import Pleroma.Factory
describe "account fetching" do
clear_config([:instance, :limit_to_local_content])
test "works by id" do
user = insert(:user)
@ -44,7 +46,6 @@ test "works by nickname" do
end
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)
user = insert(:user, nickname: "user@example.com", local: false)
@ -52,13 +53,11 @@ test "works by nickname for remote users" do
build_conn()
|> 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 == user.id
end
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)
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()
|> get("/api/v1/accounts/#{user.nickname}")
Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
assert json_response(conn, 404)
end
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)
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"]))
|> 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 == user.id
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\"]}"}
end
clear_config([Pleroma.Plugs.RemoteIp, :enabled])
test "rate limit", %{conn: conn} do
Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
app_token = insert(:oauth_token, user: nil)

View file

@ -21,6 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
clear_config([:instance, :federating])
clear_config([:instance, :allow_relay])
clear_config([:rich_media, :enabled])
describe "posting statuses" do
setup do: oauth_access(["write:statuses"])

View file

@ -7,11 +7,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
import Mock
alias Pleroma.Config
setup do
media_proxy_config = Config.get([:media_proxy]) || []
on_exit(fn -> Config.put([:media_proxy], media_proxy_config) end)
:ok
end
clear_config(:media_proxy)
clear_config([Pleroma.Web.Endpoint, :secret_key_base])
test "it returns 404 when MediaProxy disabled", %{conn: conn} do
Config.put([:media_proxy, :enabled], false)

View file

@ -9,6 +9,7 @@ defmodule Pleroma.Web.MediaProxyTest do
alias Pleroma.Web.MediaProxy.MediaProxyController
clear_config([:media_proxy, :enabled])
clear_config(Pleroma.Upload)
describe "when enabled" do
setup do
@ -224,7 +225,6 @@ test "does not change whitelisted urls" do
end
test "ensure Pleroma.Upload base_url is always whitelisted" do
upload_config = Pleroma.Config.get([Pleroma.Upload])
media_url = "https://media.pleroma.social"
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)
assert String.starts_with?(encoded, media_url)
Pleroma.Config.put([Pleroma.Upload], upload_config)
end
end
end

View file

@ -7,6 +7,8 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do
import Pleroma.Factory
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
user = insert(:user)

View file

@ -13,6 +13,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
alias Pleroma.Web.Metadata.Utils
alias Pleroma.Web.Router
clear_config([Pleroma.Web.Metadata, :unfurl_nsfw])
test "it renders twitter card for user info" do
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
avatar_url = Utils.attachment_url(User.avatar_url(user))

View file

@ -6,7 +6,9 @@ defmodule Pleroma.Web.NodeInfoTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
clear_config([:mrf_simple])
clear_config(:instance)
test "GET /.well-known/nodeinfo", %{conn: conn} do
links =
@ -63,11 +65,6 @@ test "returns software.repository field in nodeinfo 2.1", %{conn: conn} do
end
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_remote_account_fields], 15)
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"]["nameLength"] == 255
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
test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
@ -112,28 +104,28 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
Pleroma.Config.put([:instance, :safe_dm_mentions], option)
end
test "it shows if federation is enabled/disabled", %{conn: conn} do
original = Pleroma.Config.get([:instance, :federating])
describe "`metadata/federation/enabled`" do
clear_config([:instance, :federating])
Pleroma.Config.put([:instance, :federating], true)
test "it shows if federation is enabled/disabled", %{conn: conn} do
Pleroma.Config.put([:instance, :federating], true)
response =
conn
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
response =
conn
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
assert response["metadata"]["federation"]["enabled"] == true
assert response["metadata"]["federation"]["enabled"] == true
Pleroma.Config.put([:instance, :federating], false)
Pleroma.Config.put([:instance, :federating], false)
response =
conn
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
response =
conn
|> get("/nodeinfo/2.1.json")
|> json_response(:ok)
assert response["metadata"]["federation"]["enabled"] == false
Pleroma.Config.put([:instance, :federating], original)
assert response["metadata"]["federation"]["enabled"] == false
end
end
test "it shows MRF transparency data if enabled", %{conn: conn} do

View file

@ -17,7 +17,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
key: "_test",
signing_salt: "cooldude"
]
clear_config_all([:instance, :account_activation_required])
clear_config([:instance, :account_activation_required])
describe "in OAuth consumer mode, " do
setup do

View file

@ -96,6 +96,32 @@ test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do
result
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
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["read:statuses"])

View file

@ -4,7 +4,8 @@
defmodule Pleroma.Web.FederatingPlugTest do
use Pleroma.Web.ConnCase
clear_config_all([:instance, :federating])
clear_config([:instance, :federating])
test "returns and halt the conn when federating is disabled" do
Pleroma.Config.put([:instance, :federating], false)

View file

@ -20,7 +20,7 @@ defmodule Pleroma.Web.StreamerTest do
@streamer_timeout 150
@streamer_start_wait 10
clear_config_all([:instance, :skip_thread_containment])
clear_config([:instance, :skip_thread_containment])
describe "user streams" do
setup do

View file

@ -1,5 +1,5 @@
# 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
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
@ -92,15 +92,13 @@ test "follows user", %{conn: conn} do
user = insert(:user)
user2 = insert(:user)
response =
conn =
conn
|> assign(:user, user)
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|> response(200)
assert response =~ "Account followed!"
assert user2.follower_address in User.following(user)
assert redirected_to(conn) == "/users/#{user2.id}"
end
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)
{:ok, _, _, _} = CommonAPI.follow(user, user2)
response =
conn =
conn
|> assign(:user, refresh_record(user))
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|> 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
@ -165,14 +162,13 @@ test "follows", %{conn: conn} do
user = insert(:user)
user2 = insert(:user)
response =
conn =
conn
|> post(remote_follow_path(conn, :do_follow), %{
"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)
end

View file

@ -117,15 +117,8 @@ test "it registers a new user and parses mentions in the bio" do
end
describe "register with one time token" do
setup do
setting = Pleroma.Config.get([:instance, :registrations_open])
if setting do
Pleroma.Config.put([:instance, :registrations_open], false)
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
end
:ok
clear_config([:instance, :registrations_open]) do
Pleroma.Config.put([:instance, :registrations_open], false)
end
test "returns user on success" do
@ -191,14 +184,11 @@ test "returns error on expired token" do
end
describe "registers with date limited token" do
clear_config([:instance, :registrations_open]) do
Pleroma.Config.put([:instance, :registrations_open], false)
end
setup do
setting = Pleroma.Config.get([:instance, :registrations_open])
if setting do
Pleroma.Config.put([:instance, :registrations_open], false)
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
end
data = %{
"nickname" => "vinny",
"email" => "pasta@pizza.vs",
@ -256,15 +246,8 @@ test "returns an error on overdue date", %{data: data} do
end
describe "registers with reusable token" do
setup do
setting = Pleroma.Config.get([:instance, :registrations_open])
if setting do
Pleroma.Config.put([:instance, :registrations_open], false)
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
end
:ok
clear_config([:instance, :registrations_open]) do
Pleroma.Config.put([:instance, :registrations_open], false)
end
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
describe "registers with reusable date limited token" do
setup do
setting = Pleroma.Config.get([:instance, :registrations_open])
if setting do
Pleroma.Config.put([:instance, :registrations_open], false)
on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end)
end
:ok
clear_config([:instance, :registrations_open]) do
Pleroma.Config.put([:instance, :registrations_open], false)
end
test "returns user on success" do

View file

@ -19,7 +19,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
clear_config([:instance])
clear_config([:frontend_configurations, :pleroma_fe])
clear_config([:user, :deny_follow_blocked])
describe "POST /api/pleroma/follow_import" do
setup do: oauth_access(["follow"])

View 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