forked from AkkomaGang/akkoma
Merge remote-tracking branch 'remotes/upstream/develop' into 1149-oban-job-queue
This commit is contained in:
commit
8778c16dac
79 changed files with 1138 additions and 242 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -23,9 +23,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Not being able to pin unlisted posts
|
- Not being able to pin unlisted posts
|
||||||
- Objects being re-embedded to activities after being updated (e.g faved/reposted). Running 'mix pleroma.database prune_objects' again is advised.
|
- Objects being re-embedded to activities after being updated (e.g faved/reposted). Running 'mix pleroma.database prune_objects' again is advised.
|
||||||
- Metadata rendering errors resulting in the entire page being inaccessible
|
- Metadata rendering errors resulting in the entire page being inaccessible
|
||||||
|
- `federation_incoming_replies_max_depth` option being ignored in certain cases
|
||||||
- Federation/MediaProxy not working with instances that have wrong certificate order
|
- Federation/MediaProxy not working with instances that have wrong certificate order
|
||||||
- Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`)
|
- Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`)
|
||||||
- Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity
|
- Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity
|
||||||
|
- Mastodon API: follower/following counters not being nullified, when `hide_follows`/`hide_followers` is set
|
||||||
|
- Mastodon API: `muted` in the Status entity, using author's account to determine if the tread was muted
|
||||||
- Mastodon API: Add `account_id`, `type`, `offset`, and `limit` to search API (`/api/v1/search` and `/api/v2/search`)
|
- Mastodon API: Add `account_id`, `type`, `offset`, and `limit` to search API (`/api/v1/search` and `/api/v2/search`)
|
||||||
- Mastodon API, streaming: Fix filtering of notifications based on blocks/mutes/thread mutes
|
- Mastodon API, streaming: Fix filtering of notifications based on blocks/mutes/thread mutes
|
||||||
- ActivityPub C2S: follower/following collection pages being inaccessible even when authentifucated if `hide_followers`/ `hide_follows` was set
|
- ActivityPub C2S: follower/following collection pages being inaccessible even when authentifucated if `hide_followers`/ `hide_follows` was set
|
||||||
|
@ -38,11 +41,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag
|
- Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag
|
||||||
- Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected.
|
- Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected.
|
||||||
- Report email not being sent to admins when the reporter is a remote user
|
- Report email not being sent to admins when the reporter is a remote user
|
||||||
|
- MRF: ensure that subdomain_match calls are case-insensitive
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- **Breaking:** MRF describe API, which adds support for exposing configuration information about MRF policies to NodeInfo.
|
||||||
|
Custom modules will need to be updated by adding, at the very least, `def describe, do: {:ok, %{}}` to the MRF policy modules.
|
||||||
- MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`)
|
- MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`)
|
||||||
- MRF: Support for excluding specific domains from Transparency.
|
- MRF: Support for excluding specific domains from Transparency.
|
||||||
- MRF: Support for filtering posts based on who they mention (`Pleroma.Web.ActivityPub.MRF.MentionPolicy`)
|
- MRF: Support for filtering posts based on who they mention (`Pleroma.Web.ActivityPub.MRF.MentionPolicy`)
|
||||||
|
- MRF: Support for filtering posts based on ActivityStreams vocabulary (`Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`)
|
||||||
- MRF (Simple Policy): Support for wildcard domains.
|
- MRF (Simple Policy): Support for wildcard domains.
|
||||||
- Support for wildcard domains in user domain blocks setting.
|
- Support for wildcard domains in user domain blocks setting.
|
||||||
- Configuration: `quarantined_instances` support wildcard domains.
|
- Configuration: `quarantined_instances` support wildcard domains.
|
||||||
|
@ -65,6 +72,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Added synchronization of following/followers counters for external users
|
- Added synchronization of following/followers counters for external users
|
||||||
- Configuration: `enabled` option for `Pleroma.Emails.Mailer`, defaulting to `false`.
|
- Configuration: `enabled` option for `Pleroma.Emails.Mailer`, defaulting to `false`.
|
||||||
- Configuration: Pleroma.Plugs.RateLimiter `bucket_name`, `params` options.
|
- Configuration: Pleroma.Plugs.RateLimiter `bucket_name`, `params` options.
|
||||||
|
- Configuration: `user_bio_length` and `user_name_length` options.
|
||||||
- Addressable lists
|
- Addressable lists
|
||||||
- Twitter API: added rate limit for `/api/account/password_reset` endpoint.
|
- Twitter API: added rate limit for `/api/account/password_reset` endpoint.
|
||||||
- ActivityPub: Add an internal service actor for fetching ActivityPub objects.
|
- ActivityPub: Add an internal service actor for fetching ActivityPub objects.
|
||||||
|
@ -72,6 +80,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Admin API: Endpoint for fetching latest user's statuses
|
- Admin API: Endpoint for fetching latest user's statuses
|
||||||
- Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=<email>` for resending account confirmation.
|
- Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=<email>` for resending account confirmation.
|
||||||
- Relays: Added a task to list relay subscriptions.
|
- Relays: Added a task to list relay subscriptions.
|
||||||
|
- Mix Tasks: `mix pleroma.database fix_likes_collections`
|
||||||
|
- Federation: Remove `likes` from objects.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
||||||
|
@ -82,6 +92,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Removed
|
### Removed
|
||||||
- Emoji: Remove longfox emojis.
|
- Emoji: Remove longfox emojis.
|
||||||
- Remove `Reply-To` header from report emails for admins.
|
- Remove `Reply-To` header from report emails for admins.
|
||||||
|
- ActivityPub: The `accept_blocks` configuration setting.
|
||||||
|
|
||||||
## [1.0.1] - 2019-07-14
|
## [1.0.1] - 2019-07-14
|
||||||
### Security
|
### Security
|
||||||
|
|
|
@ -253,6 +253,8 @@
|
||||||
skip_thread_containment: true,
|
skip_thread_containment: true,
|
||||||
limit_to_local_content: :unauthenticated,
|
limit_to_local_content: :unauthenticated,
|
||||||
dynamic_configuration: false,
|
dynamic_configuration: false,
|
||||||
|
user_bio_length: 5000,
|
||||||
|
user_name_length: 100,
|
||||||
external_user_synchronization: true
|
external_user_synchronization: true
|
||||||
|
|
||||||
config :pleroma, :markup,
|
config :pleroma, :markup,
|
||||||
|
@ -302,7 +304,6 @@
|
||||||
default_mascot: :pleroma_fox_tan
|
default_mascot: :pleroma_fox_tan
|
||||||
|
|
||||||
config :pleroma, :activitypub,
|
config :pleroma, :activitypub,
|
||||||
accept_blocks: true,
|
|
||||||
unfollow_blocked: true,
|
unfollow_blocked: true,
|
||||||
outgoing_blocks: true,
|
outgoing_blocks: true,
|
||||||
follow_handshake_timeout: 500,
|
follow_handshake_timeout: 500,
|
||||||
|
@ -337,6 +338,10 @@
|
||||||
|
|
||||||
config :pleroma, :mrf_subchain, match_actor: %{}
|
config :pleroma, :mrf_subchain, match_actor: %{}
|
||||||
|
|
||||||
|
config :pleroma, :mrf_vocabulary,
|
||||||
|
accept: [],
|
||||||
|
reject: []
|
||||||
|
|
||||||
config :pleroma, :rich_media,
|
config :pleroma, :rich_media,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
ignore_hosts: [],
|
ignore_hosts: [],
|
||||||
|
|
|
@ -18,6 +18,7 @@ Note: `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`.
|
||||||
|
|
||||||
## Pleroma.Uploaders.S3
|
## Pleroma.Uploaders.S3
|
||||||
* `bucket`: S3 bucket name
|
* `bucket`: S3 bucket name
|
||||||
|
* `bucket_namespace`: S3 bucket namespace
|
||||||
* `public_endpoint`: S3 endpoint that the user finally accesses(ex. "https://s3.dualstack.ap-northeast-1.amazonaws.com")
|
* `public_endpoint`: S3 endpoint that the user finally accesses(ex. "https://s3.dualstack.ap-northeast-1.amazonaws.com")
|
||||||
* `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc.
|
* `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc.
|
||||||
For example, when using CDN to S3 virtual host format, set "".
|
For example, when using CDN to S3 virtual host format, set "".
|
||||||
|
@ -102,6 +103,7 @@ config :pleroma, Pleroma.Emails.Mailer,
|
||||||
* `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links.
|
* `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links.
|
||||||
* `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed.
|
* `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed.
|
||||||
* `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (see `:mrf_mention` section)
|
* `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (see `:mrf_mention` section)
|
||||||
|
* `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (see `:mrf_vocabulary` section)
|
||||||
* `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network.
|
* `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network.
|
||||||
* `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send.
|
* `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send.
|
||||||
* `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json``
|
* `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json``
|
||||||
|
@ -125,6 +127,8 @@ config :pleroma, Pleroma.Emails.Mailer,
|
||||||
* `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). Default: `false`.
|
* `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). Default: `false`.
|
||||||
* `healthcheck`: If set to true, system data will be shown on ``/api/pleroma/healthcheck``.
|
* `healthcheck`: If set to true, system data will be shown on ``/api/pleroma/healthcheck``.
|
||||||
* `remote_post_retention_days`: The default amount of days to retain remote posts when pruning the database.
|
* `remote_post_retention_days`: The default amount of days to retain remote posts when pruning the database.
|
||||||
|
* `user_bio_length`: A user bio maximum length (default: `5000`)
|
||||||
|
* `user_name_length`: A user name maximum length (default: `100`)
|
||||||
* `skip_thread_containment`: Skip filter out broken threads. The default is `false`.
|
* `skip_thread_containment`: Skip filter out broken threads. The default is `false`.
|
||||||
* `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`.
|
* `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`.
|
||||||
* `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api.
|
* `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api.
|
||||||
|
@ -275,6 +279,10 @@ config :pleroma, :mrf_subchain,
|
||||||
## :mrf_mention
|
## :mrf_mention
|
||||||
* `actors`: A list of actors, for which to drop any posts mentioning.
|
* `actors`: A list of actors, for which to drop any posts mentioning.
|
||||||
|
|
||||||
|
## :mrf_vocabulary
|
||||||
|
* `accept`: A list of ActivityStreams terms to accept. If empty, all supported messages are accepted.
|
||||||
|
* `reject`: A list of ActivityStreams terms to reject. If empty, no messages are rejected.
|
||||||
|
|
||||||
## :media_proxy
|
## :media_proxy
|
||||||
* `enabled`: Enables proxying of remote media to the instance’s proxy
|
* `enabled`: Enables proxying of remote media to the instance’s proxy
|
||||||
* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.
|
* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.
|
||||||
|
@ -328,7 +336,6 @@ config :pleroma, Pleroma.Web.Endpoint,
|
||||||
This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020`
|
This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020`
|
||||||
|
|
||||||
## :activitypub
|
## :activitypub
|
||||||
* ``accept_blocks``: Whether to accept incoming block activities from other instances
|
|
||||||
* ``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
|
||||||
|
|
|
@ -36,6 +36,10 @@ defmodule Mix.Tasks.Pleroma.Database do
|
||||||
## Remove duplicated items from following and update followers count for all users
|
## Remove duplicated items from following and update followers count for all users
|
||||||
|
|
||||||
mix pleroma.database update_users_following_followers_counts
|
mix pleroma.database update_users_following_followers_counts
|
||||||
|
|
||||||
|
## Fix the pre-existing "likes" collections for all objects
|
||||||
|
|
||||||
|
mix pleroma.database fix_likes_collections
|
||||||
"""
|
"""
|
||||||
def run(["remove_embedded_objects" | args]) do
|
def run(["remove_embedded_objects" | args]) do
|
||||||
{options, [], []} =
|
{options, [], []} =
|
||||||
|
@ -125,4 +129,36 @@ def run(["prune_objects" | args]) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run(["fix_likes_collections"]) do
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
start_pleroma()
|
||||||
|
|
||||||
|
from(object in Object,
|
||||||
|
where: fragment("(?)->>'likes' is not null", object.data),
|
||||||
|
select: %{id: object.id, likes: fragment("(?)->>'likes'", object.data)}
|
||||||
|
)
|
||||||
|
|> Pleroma.RepoStreamer.chunk_stream(100)
|
||||||
|
|> Stream.each(fn objects ->
|
||||||
|
ids =
|
||||||
|
objects
|
||||||
|
|> Enum.filter(fn object -> object.likes |> Jason.decode!() |> is_map() end)
|
||||||
|
|> Enum.map(& &1.id)
|
||||||
|
|
||||||
|
Object
|
||||||
|
|> where([object], object.id in ^ids)
|
||||||
|
|> update([object],
|
||||||
|
set: [
|
||||||
|
data:
|
||||||
|
fragment(
|
||||||
|
"jsonb_set(?, '{likes}', '[]'::jsonb, true)",
|
||||||
|
object.data
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|> Repo.update_all([], timeout: :infinity)
|
||||||
|
end)
|
||||||
|
|> Stream.run()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -224,6 +224,29 @@ def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do
|
||||||
|
|
||||||
def get_create_by_object_ap_id(_), do: nil
|
def get_create_by_object_ap_id(_), do: nil
|
||||||
|
|
||||||
|
def create_by_object_ap_id_with_object(ap_ids) when is_list(ap_ids) do
|
||||||
|
from(
|
||||||
|
activity in Activity,
|
||||||
|
where:
|
||||||
|
fragment(
|
||||||
|
"coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)",
|
||||||
|
activity.data,
|
||||||
|
activity.data,
|
||||||
|
^ap_ids
|
||||||
|
),
|
||||||
|
where: fragment("(?)->>'type' = 'Create'", activity.data),
|
||||||
|
inner_join: o in Object,
|
||||||
|
on:
|
||||||
|
fragment(
|
||||||
|
"(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
|
||||||
|
o.data,
|
||||||
|
activity.data,
|
||||||
|
activity.data
|
||||||
|
),
|
||||||
|
preload: [object: o]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do
|
def create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do
|
||||||
from(
|
from(
|
||||||
activity in Activity,
|
activity in Activity,
|
||||||
|
@ -263,8 +286,8 @@ defp get_in_reply_to_activity_from_object(%Object{data: %{"inReplyTo" => ap_id}}
|
||||||
|
|
||||||
defp get_in_reply_to_activity_from_object(_), do: nil
|
defp get_in_reply_to_activity_from_object(_), do: nil
|
||||||
|
|
||||||
def get_in_reply_to_activity(%Activity{data: %{"object" => object}}) do
|
def get_in_reply_to_activity(%Activity{} = activity) do
|
||||||
get_in_reply_to_activity_from_object(Object.normalize(object))
|
get_in_reply_to_activity_from_object(Object.normalize(activity))
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalize(obj) when is_map(obj), do: get_by_ap_id_with_object(obj["id"])
|
def normalize(obj) when is_map(obj), do: get_by_ap_id_with_object(obj["id"])
|
||||||
|
|
|
@ -11,7 +11,7 @@ def get_file(_) do
|
||||||
|
|
||||||
def put_file(upload) do
|
def put_file(upload) do
|
||||||
{local_path, file} =
|
{local_path, file} =
|
||||||
case Enum.reverse(String.split(upload.path, "/", trim: true)) do
|
case Enum.reverse(Path.split(upload.path)) do
|
||||||
[file] ->
|
[file] ->
|
||||||
{upload_path(), file}
|
{upload_path(), file}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ def put_file(upload) do
|
||||||
|
|
||||||
result_file = Path.join(local_path, file)
|
result_file = Path.join(local_path, file)
|
||||||
|
|
||||||
unless File.exists?(result_file) do
|
if not File.exists?(result_file) do
|
||||||
File.cp!(upload.tempfile, result_file)
|
File.cp!(upload.tempfile, result_file)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Uploaders.MDII do
|
defmodule Pleroma.Uploaders.MDII do
|
||||||
|
@moduledoc "Represents uploader for https://github.com/hakaba-hitoyo/minimal-digital-image-infrastructure"
|
||||||
|
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.HTTP
|
alias Pleroma.HTTP
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,12 @@ defmodule Pleroma.Uploaders.S3 do
|
||||||
@behaviour Pleroma.Uploaders.Uploader
|
@behaviour Pleroma.Uploaders.Uploader
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
alias Pleroma.Config
|
||||||
|
|
||||||
# The file name is re-encoded with S3's constraints here to comply with previous
|
# The file name is re-encoded with S3's constraints here to comply with previous
|
||||||
# links with less strict filenames
|
# links with less strict filenames
|
||||||
def get_file(file) do
|
def get_file(file) do
|
||||||
config = Pleroma.Config.get([__MODULE__])
|
config = Config.get([__MODULE__])
|
||||||
bucket = Keyword.fetch!(config, :bucket)
|
bucket = Keyword.fetch!(config, :bucket)
|
||||||
|
|
||||||
bucket_with_namespace =
|
bucket_with_namespace =
|
||||||
|
@ -34,15 +36,15 @@ def get_file(file) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def put_file(%Pleroma.Upload{} = upload) do
|
def put_file(%Pleroma.Upload{} = upload) do
|
||||||
config = Pleroma.Config.get([__MODULE__])
|
config = Config.get([__MODULE__])
|
||||||
bucket = Keyword.get(config, :bucket)
|
bucket = Keyword.get(config, :bucket)
|
||||||
|
|
||||||
{:ok, file_data} = File.read(upload.tempfile)
|
|
||||||
|
|
||||||
s3_name = strict_encode(upload.path)
|
s3_name = strict_encode(upload.path)
|
||||||
|
|
||||||
op =
|
op =
|
||||||
ExAws.S3.put_object(bucket, s3_name, file_data, [
|
upload.tempfile
|
||||||
|
|> ExAws.S3.Upload.stream_file()
|
||||||
|
|> ExAws.S3.upload(bucket, s3_name, [
|
||||||
{:acl, :public_read},
|
{:acl, :public_read},
|
||||||
{:content_type, upload.content_type}
|
{:content_type, upload.content_type}
|
||||||
])
|
])
|
||||||
|
|
|
@ -155,10 +155,10 @@ def following_count(%User{} = user) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def remote_user_creation(params) do
|
def remote_user_creation(params) do
|
||||||
params =
|
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
||||||
params
|
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
||||||
|> Map.put(:info, params[:info] || %{})
|
|
||||||
|
|
||||||
|
params = Map.put(params, :info, params[:info] || %{})
|
||||||
info_cng = User.Info.remote_user_creation(%User.Info{}, params[:info])
|
info_cng = User.Info.remote_user_creation(%User.Info{}, params[:info])
|
||||||
|
|
||||||
changes =
|
changes =
|
||||||
|
@ -167,8 +167,8 @@ def remote_user_creation(params) do
|
||||||
|> validate_required([:name, :ap_id])
|
|> validate_required([:name, :ap_id])
|
||||||
|> unique_constraint(:nickname)
|
|> unique_constraint(:nickname)
|
||||||
|> validate_format(:nickname, @email_regex)
|
|> validate_format(:nickname, @email_regex)
|
||||||
|> validate_length(:bio, max: 5000)
|
|> validate_length(:bio, max: bio_limit)
|
||||||
|> validate_length(:name, max: 100)
|
|> validate_length(:name, max: name_limit)
|
||||||
|> put_change(:local, false)
|
|> put_change(:local, false)
|
||||||
|> put_embed(:info, info_cng)
|
|> put_embed(:info, info_cng)
|
||||||
|
|
||||||
|
@ -191,22 +191,23 @@ def remote_user_creation(params) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_changeset(struct, params \\ %{}) do
|
def update_changeset(struct, params \\ %{}) do
|
||||||
|
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
||||||
|
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|> cast(params, [:bio, :name, :avatar, :following])
|
|> cast(params, [:bio, :name, :avatar, :following])
|
||||||
|> unique_constraint(:nickname)
|
|> unique_constraint(:nickname)
|
||||||
|> validate_format(:nickname, local_nickname_regex())
|
|> validate_format(:nickname, local_nickname_regex())
|
||||||
|> validate_length(:bio, max: 5000)
|
|> validate_length(:bio, max: bio_limit)
|
||||||
|> validate_length(:name, min: 1, max: 100)
|
|> validate_length(:name, min: 1, max: name_limit)
|
||||||
end
|
end
|
||||||
|
|
||||||
def upgrade_changeset(struct, params \\ %{}) do
|
def upgrade_changeset(struct, params \\ %{}) do
|
||||||
params =
|
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
||||||
params
|
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
||||||
|> Map.put(:last_refreshed_at, NaiveDateTime.utc_now())
|
|
||||||
|
|
||||||
info_cng =
|
params = Map.put(params, :last_refreshed_at, NaiveDateTime.utc_now())
|
||||||
struct.info
|
info_cng = User.Info.user_upgrade(struct.info, params[:info])
|
||||||
|> User.Info.user_upgrade(params[:info])
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|> cast(params, [
|
|> cast(params, [
|
||||||
|
@ -219,8 +220,8 @@ def upgrade_changeset(struct, params \\ %{}) do
|
||||||
])
|
])
|
||||||
|> unique_constraint(:nickname)
|
|> unique_constraint(:nickname)
|
||||||
|> validate_format(:nickname, local_nickname_regex())
|
|> validate_format(:nickname, local_nickname_regex())
|
||||||
|> validate_length(:bio, max: 5000)
|
|> validate_length(:bio, max: bio_limit)
|
||||||
|> validate_length(:name, max: 100)
|
|> validate_length(:name, max: name_limit)
|
||||||
|> put_embed(:info, info_cng)
|
|> put_embed(:info, info_cng)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -247,6 +248,9 @@ def reset_password(%User{id: user_id} = user, data) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def register_changeset(struct, params \\ %{}, opts \\ []) do
|
def register_changeset(struct, params \\ %{}, opts \\ []) do
|
||||||
|
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
||||||
|
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
||||||
|
|
||||||
need_confirmation? =
|
need_confirmation? =
|
||||||
if is_nil(opts[:need_confirmation]) do
|
if is_nil(opts[:need_confirmation]) do
|
||||||
Pleroma.Config.get([:instance, :account_activation_required])
|
Pleroma.Config.get([:instance, :account_activation_required])
|
||||||
|
@ -267,8 +271,8 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do
|
||||||
|> validate_exclusion(:nickname, Pleroma.Config.get([User, :restricted_nicknames]))
|
|> validate_exclusion(:nickname, Pleroma.Config.get([User, :restricted_nicknames]))
|
||||||
|> validate_format(:nickname, local_nickname_regex())
|
|> validate_format(:nickname, local_nickname_regex())
|
||||||
|> validate_format(:email, @email_regex)
|
|> validate_format(:email, @email_regex)
|
||||||
|> validate_length(:bio, max: 1000)
|
|> validate_length(:bio, max: bio_limit)
|
||||||
|> validate_length(:name, min: 1, max: 100)
|
|> validate_length(:name, min: 1, max: name_limit)
|
||||||
|> put_change(:info, info_change)
|
|> put_change(:info, info_change)
|
||||||
|
|
||||||
changeset =
|
changeset =
|
||||||
|
|
|
@ -523,6 +523,8 @@ defp fetch_activities_for_context_query(context, opts) do
|
||||||
|
|
||||||
from(activity in Activity)
|
from(activity in Activity)
|
||||||
|> maybe_preload_objects(opts)
|
|> maybe_preload_objects(opts)
|
||||||
|
|> maybe_preload_bookmarks(opts)
|
||||||
|
|> maybe_set_thread_muted_field(opts)
|
||||||
|> restrict_blocked(opts)
|
|> restrict_blocked(opts)
|
||||||
|> restrict_recipients(recipients, opts["user"])
|
|> restrict_recipients(recipients, opts["user"])
|
||||||
|> where(
|
|> where(
|
||||||
|
@ -536,6 +538,7 @@ defp fetch_activities_for_context_query(context, opts) do
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|> exclude_poll_votes(opts)
|
|> exclude_poll_votes(opts)
|
||||||
|
|> exclude_id(opts)
|
||||||
|> order_by([activity], desc: activity.id)
|
|> order_by([activity], desc: activity.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -628,6 +631,7 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do
|
||||||
params =
|
params =
|
||||||
params
|
params
|
||||||
|> Map.put("type", ["Create", "Announce"])
|
|> Map.put("type", ["Create", "Announce"])
|
||||||
|
|> Map.put("user", reading_user)
|
||||||
|> Map.put("actor_id", user.ap_id)
|
|> Map.put("actor_id", user.ap_id)
|
||||||
|> Map.put("whole_db", true)
|
|> Map.put("whole_db", true)
|
||||||
|> Map.put("pinned_activity_ids", user.info.pinned_activities)
|
|> Map.put("pinned_activity_ids", user.info.pinned_activities)
|
||||||
|
@ -875,6 +879,12 @@ defp exclude_poll_votes(query, _) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp exclude_id(query, %{"exclude_id" => id}) when is_binary(id) do
|
||||||
|
from(activity in query, where: activity.id != ^id)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp exclude_id(query, _), do: query
|
||||||
|
|
||||||
defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query
|
defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query
|
||||||
|
|
||||||
defp maybe_preload_objects(query, _) do
|
defp maybe_preload_objects(query, _) do
|
||||||
|
|
|
@ -28,11 +28,43 @@ defp get_policies(_), do: []
|
||||||
|
|
||||||
@spec subdomains_regex([String.t()]) :: [Regex.t()]
|
@spec subdomains_regex([String.t()]) :: [Regex.t()]
|
||||||
def subdomains_regex(domains) when is_list(domains) do
|
def subdomains_regex(domains) when is_list(domains) do
|
||||||
for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$)
|
for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$)i
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec subdomain_match?([Regex.t()], String.t()) :: boolean()
|
@spec subdomain_match?([Regex.t()], String.t()) :: boolean()
|
||||||
def subdomain_match?(domains, host) do
|
def subdomain_match?(domains, host) do
|
||||||
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
|
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@callback describe() :: {:ok | :error, Map.t()}
|
||||||
|
|
||||||
|
def describe(policies) do
|
||||||
|
{:ok, policy_configs} =
|
||||||
|
policies
|
||||||
|
|> Enum.reduce({:ok, %{}}, fn
|
||||||
|
policy, {:ok, data} ->
|
||||||
|
{:ok, policy_data} = policy.describe()
|
||||||
|
{:ok, Map.merge(data, policy_data)}
|
||||||
|
|
||||||
|
_, error ->
|
||||||
|
error
|
||||||
|
end)
|
||||||
|
|
||||||
|
mrf_policies =
|
||||||
|
get_policies()
|
||||||
|
|> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end)
|
||||||
|
|
||||||
|
exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions])
|
||||||
|
|
||||||
|
base =
|
||||||
|
%{
|
||||||
|
mrf_policies: mrf_policies,
|
||||||
|
exclusions: length(exclusions) > 0
|
||||||
|
}
|
||||||
|
|> Map.merge(policy_configs)
|
||||||
|
|
||||||
|
{:ok, base}
|
||||||
|
end
|
||||||
|
|
||||||
|
def describe, do: get_policies() |> describe()
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,4 +62,7 @@ def filter(%{"type" => "Follow", "actor" => actor_id} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
# has the user successfully posted before?
|
# has the user successfully posted before?
|
||||||
|
@ -22,6 +24,7 @@ defp contains_links?(%{"content" => content} = _object) do
|
||||||
|
|
||||||
defp contains_links?(_), do: false
|
defp contains_links?(_), do: false
|
||||||
|
|
||||||
|
@impl true
|
||||||
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do
|
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do
|
||||||
with {:ok, %User{} = u} <- User.get_or_fetch_by_ap_id(actor),
|
with {:ok, %User{} = u} <- User.get_or_fetch_by_ap_id(actor),
|
||||||
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
||||||
|
@ -45,4 +48,7 @@ def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message
|
||||||
|
|
||||||
# in all other cases, pass through
|
# in all other cases, pass through
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,4 +12,7 @@ def filter(object) do
|
||||||
Logger.info("REJECTING #{inspect(object)}")
|
Logger.info("REJECTING #{inspect(object)}")
|
||||||
{:reject, object}
|
{:reject, object}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,4 +39,6 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -90,4 +90,7 @@ def filter(%{"type" => "Create"} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{mrf_hellthread: Pleroma.Config.get([:mrf_hellthread])}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -96,4 +96,36 @@ def filter(%{"type" => "Create", "object" => %{"content" => _content}} = message
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe do
|
||||||
|
# This horror is needed to convert regex sigils to strings
|
||||||
|
mrf_keyword =
|
||||||
|
Pleroma.Config.get(:mrf_keyword, [])
|
||||||
|
|> Enum.map(fn {key, value} ->
|
||||||
|
{key,
|
||||||
|
Enum.map(value, fn
|
||||||
|
{pattern, replacement} ->
|
||||||
|
%{
|
||||||
|
"pattern" =>
|
||||||
|
if not is_binary(pattern) do
|
||||||
|
inspect(pattern)
|
||||||
|
else
|
||||||
|
pattern
|
||||||
|
end,
|
||||||
|
"replacement" => replacement
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern ->
|
||||||
|
if not is_binary(pattern) do
|
||||||
|
inspect(pattern)
|
||||||
|
else
|
||||||
|
pattern
|
||||||
|
end
|
||||||
|
end)}
|
||||||
|
end)
|
||||||
|
|> Enum.into(%{})
|
||||||
|
|
||||||
|
{:ok, %{mrf_keyword: mrf_keyword}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,4 +61,7 @@ def filter(
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,4 +21,7 @@ def filter(%{"type" => "Create"} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,4 +19,7 @@ def filter(
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,4 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
||||||
def filter(object) do
|
def filter(object) do
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,4 +21,6 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,4 +44,7 @@ def filter(%{"type" => "Create"} = object) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get([:mrf_rejectnonpublic])}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -177,4 +177,16 @@ def filter(%{"id" => actor, "type" => obj_type} = object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe do
|
||||||
|
exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions])
|
||||||
|
|
||||||
|
mrf_simple =
|
||||||
|
Pleroma.Config.get(:mrf_simple)
|
||||||
|
|> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end)
|
||||||
|
|> Enum.into(%{})
|
||||||
|
|
||||||
|
{:ok, %{mrf_simple: mrf_simple}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,4 +37,7 @@ def filter(%{"actor" => actor} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -165,4 +165,7 @@ def filter(%{"actor" => actor, "type" => "Create"} = message),
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,4 +32,13 @@ def filter(%{"actor" => actor} = object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe do
|
||||||
|
mrf_user_allowlist =
|
||||||
|
Config.get([:mrf_user_allowlist], [])
|
||||||
|
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
|
||||||
|
|
||||||
|
{:ok, %{mrf_user_allowlist: mrf_user_allowlist}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
36
lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
Normal file
36
lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
|
||||||
|
@moduledoc "Filter messages which belong to certain activity vocabularies"
|
||||||
|
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
|
def filter(%{"type" => "Undo", "object" => child_message} = message) do
|
||||||
|
with {:ok, _} <- filter(child_message) do
|
||||||
|
{:ok, message}
|
||||||
|
else
|
||||||
|
{:reject, nil} ->
|
||||||
|
{:reject, nil}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter(%{"type" => message_type} = message) do
|
||||||
|
with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]),
|
||||||
|
rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]),
|
||||||
|
true <-
|
||||||
|
length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type),
|
||||||
|
false <-
|
||||||
|
length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type),
|
||||||
|
{:ok, _} <- filter(message["object"]) do
|
||||||
|
{:ok, message}
|
||||||
|
else
|
||||||
|
_ -> {:reject, nil}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
def describe, do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary)}}
|
||||||
|
end
|
|
@ -14,6 +14,7 @@ def get_actor do
|
||||||
|> User.get_or_create_service_actor_by_ap_id()
|
|> User.get_or_create_service_actor_by_ap_id()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()}
|
||||||
def follow(target_instance) do
|
def follow(target_instance) do
|
||||||
with %User{} = local_user <- get_actor(),
|
with %User{} = local_user <- get_actor(),
|
||||||
{:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance),
|
{:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance),
|
||||||
|
@ -21,12 +22,17 @@ def follow(target_instance) do
|
||||||
Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}")
|
Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}")
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
|
{:error, _} = error ->
|
||||||
|
Logger.error("error: #{inspect(error)}")
|
||||||
|
error
|
||||||
|
|
||||||
e ->
|
e ->
|
||||||
Logger.error("error: #{inspect(e)}")
|
Logger.error("error: #{inspect(e)}")
|
||||||
{:error, e}
|
{:error, e}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec unfollow(String.t()) :: {:ok, Activity.t()} | {:error, any()}
|
||||||
def unfollow(target_instance) do
|
def unfollow(target_instance) do
|
||||||
with %User{} = local_user <- get_actor(),
|
with %User{} = local_user <- get_actor(),
|
||||||
{:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance),
|
{:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance),
|
||||||
|
@ -34,20 +40,27 @@ def unfollow(target_instance) do
|
||||||
Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}")
|
Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}")
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
|
{:error, _} = error ->
|
||||||
|
Logger.error("error: #{inspect(error)}")
|
||||||
|
error
|
||||||
|
|
||||||
e ->
|
e ->
|
||||||
Logger.error("error: #{inspect(e)}")
|
Logger.error("error: #{inspect(e)}")
|
||||||
{:error, e}
|
{:error, e}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec publish(any()) :: {:ok, Activity.t(), Object.t()} | {:error, any()}
|
||||||
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
|
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
|
||||||
with %User{} = user <- get_actor(),
|
with %User{} = user <- get_actor(),
|
||||||
%Object{} = object <- Object.normalize(activity) do
|
%Object{} = object <- Object.normalize(activity) do
|
||||||
ActivityPub.announce(user, object, nil, true, false)
|
ActivityPub.announce(user, object, nil, true, false)
|
||||||
else
|
else
|
||||||
e -> Logger.error("error: #{inspect(e)}")
|
e ->
|
||||||
|
Logger.error("error: #{inspect(e)}")
|
||||||
|
{:error, inspect(e)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def publish(_), do: nil
|
def publish(_), do: {:error, "Not implemented"}
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,6 +29,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
"""
|
"""
|
||||||
def fix_object(object, options \\ []) do
|
def fix_object(object, options \\ []) do
|
||||||
object
|
object
|
||||||
|
|> strip_internal_fields
|
||||||
|> fix_actor
|
|> fix_actor
|
||||||
|> fix_url
|
|> fix_url
|
||||||
|> fix_attachments
|
|> fix_attachments
|
||||||
|
@ -37,7 +38,6 @@ def fix_object(object, options \\ []) do
|
||||||
|> fix_emoji
|
|> fix_emoji
|
||||||
|> fix_tag
|
|> fix_tag
|
||||||
|> fix_content_map
|
|> fix_content_map
|
||||||
|> fix_likes
|
|
||||||
|> fix_addressing
|
|> fix_addressing
|
||||||
|> fix_summary
|
|> fix_summary
|
||||||
|> fix_type(options)
|
|> fix_type(options)
|
||||||
|
@ -154,20 +154,6 @@ def fix_actor(%{"attributedTo" => actor} = object) do
|
||||||
|> Map.put("actor", Containment.get_actor(%{"actor" => actor}))
|
|> Map.put("actor", Containment.get_actor(%{"actor" => actor}))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check for standardisation
|
|
||||||
# This is what Peertube does
|
|
||||||
# curl -H 'Accept: application/activity+json' $likes | jq .totalItems
|
|
||||||
# Prismo returns only an integer (count) as "likes"
|
|
||||||
def fix_likes(%{"likes" => likes} = object) when not is_map(likes) do
|
|
||||||
object
|
|
||||||
|> Map.put("likes", [])
|
|
||||||
|> Map.put("like_count", 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fix_likes(object) do
|
|
||||||
object
|
|
||||||
end
|
|
||||||
|
|
||||||
def fix_in_reply_to(object, options \\ [])
|
def fix_in_reply_to(object, options \\ [])
|
||||||
|
|
||||||
def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options)
|
def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options)
|
||||||
|
@ -350,13 +336,15 @@ def fix_content_map(object), do: object
|
||||||
|
|
||||||
def fix_type(object, options \\ [])
|
def fix_type(object, options \\ [])
|
||||||
|
|
||||||
def fix_type(%{"inReplyTo" => reply_id} = object, options) when is_binary(reply_id) do
|
def fix_type(%{"inReplyTo" => reply_id, "name" => _} = object, options)
|
||||||
|
when is_binary(reply_id) do
|
||||||
reply =
|
reply =
|
||||||
if Federator.allowed_incoming_reply_depth?(options[:depth]) do
|
with true <- Federator.allowed_incoming_reply_depth?(options[:depth]),
|
||||||
Object.normalize(reply_id, true)
|
{:ok, object} <- get_obj_helper(reply_id, options) do
|
||||||
|
object
|
||||||
end
|
end
|
||||||
|
|
||||||
if reply && (reply.data["type"] == "Question" and object["name"]) do
|
if reply && reply.data["type"] == "Question" do
|
||||||
Map.put(object, "type", "Answer")
|
Map.put(object, "type", "Answer")
|
||||||
else
|
else
|
||||||
object
|
object
|
||||||
|
@ -716,8 +704,7 @@ def handle_incoming(
|
||||||
} = _data,
|
} = _data,
|
||||||
_options
|
_options
|
||||||
) do
|
) do
|
||||||
with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
|
with %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked),
|
||||||
%User{local: true} = blocked <- User.get_cached_by_ap_id(blocked),
|
|
||||||
{:ok, %User{} = blocker} <- User.get_or_fetch_by_ap_id(blocker),
|
{:ok, %User{} = blocker} <- User.get_or_fetch_by_ap_id(blocker),
|
||||||
{:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do
|
{:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do
|
||||||
User.unblock(blocker, blocked)
|
User.unblock(blocker, blocked)
|
||||||
|
@ -731,8 +718,7 @@ def handle_incoming(
|
||||||
%{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = _data,
|
%{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = _data,
|
||||||
_options
|
_options
|
||||||
) do
|
) do
|
||||||
with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
|
with %User{local: true} = blocked = User.get_cached_by_ap_id(blocked),
|
||||||
%User{local: true} = blocked = User.get_cached_by_ap_id(blocked),
|
|
||||||
{:ok, %User{} = blocker} = User.get_or_fetch_by_ap_id(blocker),
|
{:ok, %User{} = blocker} = User.get_or_fetch_by_ap_id(blocker),
|
||||||
{:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do
|
{:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do
|
||||||
User.unfollow(blocker, blocked)
|
User.unfollow(blocker, blocked)
|
||||||
|
@ -787,7 +773,6 @@ def prepare_object(object) do
|
||||||
|> add_mention_tags
|
|> add_mention_tags
|
||||||
|> add_emoji_tags
|
|> add_emoji_tags
|
||||||
|> add_attributed_to
|
|> add_attributed_to
|
||||||
|> add_likes
|
|
||||||
|> prepare_attachments
|
|> prepare_attachments
|
||||||
|> set_conversation
|
|> set_conversation
|
||||||
|> set_reply_to_uri
|
|> set_reply_to_uri
|
||||||
|
@ -974,22 +959,6 @@ def add_attributed_to(object) do
|
||||||
|> Map.put("attributedTo", attributed_to)
|
|> Map.put("attributedTo", attributed_to)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_likes(%{"id" => id, "like_count" => likes} = object) do
|
|
||||||
likes = %{
|
|
||||||
"id" => "#{id}/likes",
|
|
||||||
"first" => "#{id}/likes?page=1",
|
|
||||||
"type" => "OrderedCollection",
|
|
||||||
"totalItems" => likes
|
|
||||||
}
|
|
||||||
|
|
||||||
object
|
|
||||||
|> Map.put("likes", likes)
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_likes(object) do
|
|
||||||
object
|
|
||||||
end
|
|
||||||
|
|
||||||
def prepare_attachments(object) do
|
def prepare_attachments(object) do
|
||||||
attachments =
|
attachments =
|
||||||
(object["attachment"] || [])
|
(object["attachment"] || [])
|
||||||
|
@ -1005,6 +974,7 @@ def prepare_attachments(object) do
|
||||||
defp strip_internal_fields(object) do
|
defp strip_internal_fields(object) do
|
||||||
object
|
object
|
||||||
|> Map.drop([
|
|> Map.drop([
|
||||||
|
"likes",
|
||||||
"like_count",
|
"like_count",
|
||||||
"announcements",
|
"announcements",
|
||||||
"announcement_count",
|
"announcement_count",
|
||||||
|
|
|
@ -13,10 +13,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
|
@spec follow(User.t(), User.t(), map) :: {:ok, User.t()} | {:error, String.t()}
|
||||||
def follow(follower, followed, params \\ %{}) do
|
def follow(follower, followed, params \\ %{}) do
|
||||||
options = cast_params(params)
|
|
||||||
reblogs = options[:reblogs]
|
|
||||||
|
|
||||||
result =
|
result =
|
||||||
if not User.following?(follower, followed) do
|
if not User.following?(follower, followed) do
|
||||||
CommonAPI.follow(follower, followed)
|
CommonAPI.follow(follower, followed)
|
||||||
|
@ -24,19 +22,25 @@ def follow(follower, followed, params \\ %{}) do
|
||||||
{:ok, follower, followed, nil}
|
{:ok, follower, followed, nil}
|
||||||
end
|
end
|
||||||
|
|
||||||
with {:ok, follower, followed, _} <- result do
|
with {:ok, follower, _followed, _} <- result do
|
||||||
reblogs
|
options = cast_params(params)
|
||||||
|> case do
|
|
||||||
false -> CommonAPI.hide_reblogs(follower, followed)
|
case reblogs_visibility(options[:reblogs], result) do
|
||||||
_ -> CommonAPI.show_reblogs(follower, followed)
|
|
||||||
end
|
|
||||||
|> case do
|
|
||||||
{:ok, follower} -> {:ok, follower}
|
{:ok, follower} -> {:ok, follower}
|
||||||
_ -> {:ok, follower}
|
_ -> {:ok, follower}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp reblogs_visibility(false, {:ok, follower, followed, _}) do
|
||||||
|
CommonAPI.hide_reblogs(follower, followed)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp reblogs_visibility(_, {:ok, follower, followed, _}) do
|
||||||
|
CommonAPI.show_reblogs(follower, followed)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_followers(User.t(), map()) :: list(User.t())
|
||||||
def get_followers(user, params \\ %{}) do
|
def get_followers(user, params \\ %{}) do
|
||||||
user
|
user
|
||||||
|> User.get_followers_query()
|
|> User.get_followers_query()
|
||||||
|
|
|
@ -435,6 +435,7 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put("local_only", local_only)
|
|> Map.put("local_only", local_only)
|
||||||
|> Map.put("blocking_user", user)
|
|> Map.put("blocking_user", user)
|
||||||
|> Map.put("muting_user", user)
|
|> Map.put("muting_user", user)
|
||||||
|
|> Map.put("user", user)
|
||||||
|> ActivityPub.fetch_public_activities()
|
|> ActivityPub.fetch_public_activities()
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
|
||||||
|
@ -496,12 +497,9 @@ def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
activities <-
|
activities <-
|
||||||
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
|
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
|
||||||
"blocking_user" => user,
|
"blocking_user" => user,
|
||||||
"user" => user
|
"user" => user,
|
||||||
|
"exclude_id" => activity.id
|
||||||
}),
|
}),
|
||||||
activities <-
|
|
||||||
activities |> Enum.filter(fn %{id: aid} -> to_string(aid) != to_string(id) end),
|
|
||||||
activities <-
|
|
||||||
activities |> Enum.filter(fn %{data: %{"type" => type}} -> type == "Create" end),
|
|
||||||
grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do
|
grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do
|
||||||
result = %{
|
result = %{
|
||||||
ancestors:
|
ancestors:
|
||||||
|
@ -536,8 +534,8 @@ def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
|> put_view(StatusView)
|
|> put_view(StatusView)
|
||||||
|> try_render("poll.json", %{object: object, for: user})
|
|> try_render("poll.json", %{object: object, for: user})
|
||||||
else
|
else
|
||||||
nil -> render_error(conn, :not_found, "Record not found")
|
error when is_nil(error) or error == false ->
|
||||||
false -> render_error(conn, :not_found, "Record not found")
|
render_error(conn, :not_found, "Record not found")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -885,8 +883,8 @@ def get_mascot(%{assigns: %{user: user}} = conn, _params) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
with %Activity{data: %{"object" => object}} <- Activity.get_by_id(id),
|
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||||
%Object{data: %{"likes" => likes}} <- Object.normalize(object) do
|
%Object{data: %{"likes" => likes}} <- Object.normalize(activity) do
|
||||||
q = from(u in User, where: u.ap_id in ^likes)
|
q = from(u in User, where: u.ap_id in ^likes)
|
||||||
|
|
||||||
users =
|
users =
|
||||||
|
@ -902,8 +900,8 @@ def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
with %Activity{data: %{"object" => object}} <- Activity.get_by_id(id),
|
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||||
%Object{data: %{"announcements" => announces}} <- Object.normalize(object) do
|
%Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do
|
||||||
q = from(u in User, where: u.ap_id in ^announces)
|
q = from(u in User, where: u.ap_id in ^announces)
|
||||||
|
|
||||||
users =
|
users =
|
||||||
|
@ -944,6 +942,7 @@ def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put("local_only", local_only)
|
|> Map.put("local_only", local_only)
|
||||||
|> Map.put("blocking_user", user)
|
|> Map.put("blocking_user", user)
|
||||||
|> Map.put("muting_user", user)
|
|> Map.put("muting_user", user)
|
||||||
|
|> Map.put("user", user)
|
||||||
|> Map.put("tag", tags)
|
|> Map.put("tag", tags)
|
||||||
|> Map.put("tag_all", tag_all)
|
|> Map.put("tag_all", tag_all)
|
||||||
|> Map.put("tag_reject", tag_reject)
|
|> Map.put("tag_reject", tag_reject)
|
||||||
|
@ -1350,6 +1349,7 @@ def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params)
|
||||||
params
|
params
|
||||||
|> Map.put("type", "Create")
|
|> Map.put("type", "Create")
|
||||||
|> Map.put("blocking_user", user)
|
|> Map.put("blocking_user", user)
|
||||||
|
|> Map.put("user", user)
|
||||||
|> Map.put("muting_user", user)
|
|> Map.put("muting_user", user)
|
||||||
|
|
||||||
# we must filter the following list for the user to avoid leaking statuses the user
|
# we must filter the following list for the user to avoid leaking statuses the user
|
||||||
|
@ -1690,45 +1690,35 @@ def suggestions(%{assigns: %{user: user}} = conn, _) do
|
||||||
|> String.replace("{{user}}", user)
|
|> String.replace("{{user}}", user)
|
||||||
|
|
||||||
with {:ok, %{status: 200, body: body}} <-
|
with {:ok, %{status: 200, body: body}} <-
|
||||||
HTTP.get(
|
HTTP.get(url, [], adapter: [recv_timeout: timeout, pool: :default]),
|
||||||
url,
|
|
||||||
[],
|
|
||||||
adapter: [
|
|
||||||
recv_timeout: timeout,
|
|
||||||
pool: :default
|
|
||||||
]
|
|
||||||
),
|
|
||||||
{:ok, data} <- Jason.decode(body) do
|
{:ok, data} <- Jason.decode(body) do
|
||||||
data =
|
data =
|
||||||
data
|
data
|
||||||
|> Enum.slice(0, limit)
|
|> Enum.slice(0, limit)
|
||||||
|> Enum.map(fn x ->
|
|> Enum.map(fn x ->
|
||||||
Map.put(
|
x
|
||||||
x,
|
|> Map.put("id", fetch_suggestion_id(x))
|
||||||
"id",
|
|> Map.put("avatar", MediaProxy.url(x["avatar"]))
|
||||||
case User.get_or_fetch(x["acct"]) do
|
|> Map.put("avatar_static", MediaProxy.url(x["avatar_static"]))
|
||||||
{:ok, %User{id: id}} -> id
|
|
||||||
_ -> 0
|
|
||||||
end
|
|
||||||
)
|
|
||||||
end)
|
|
||||||
|> Enum.map(fn x ->
|
|
||||||
Map.put(x, "avatar", MediaProxy.url(x["avatar"]))
|
|
||||||
end)
|
|
||||||
|> Enum.map(fn x ->
|
|
||||||
Map.put(x, "avatar_static", MediaProxy.url(x["avatar_static"]))
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
conn
|
json(conn, data)
|
||||||
|> json(data)
|
|
||||||
else
|
else
|
||||||
e -> Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}")
|
e ->
|
||||||
|
Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
json(conn, [])
|
json(conn, [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp fetch_suggestion_id(attrs) do
|
||||||
|
case User.get_or_fetch(attrs["acct"]) do
|
||||||
|
{:ok, %User{id: id}} -> id
|
||||||
|
_ -> 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
|
def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
|
||||||
with %Activity{} = activity <- Activity.get_by_id(status_id),
|
with %Activity{} = activity <- Activity.get_by_id(status_id),
|
||||||
true <- Visibility.visible_for_user?(activity, user) do
|
true <- Visibility.visible_for_user?(activity, user) do
|
||||||
|
|
|
@ -72,6 +72,13 @@ defp do_render("account.json", %{user: user} = opts) do
|
||||||
image = User.avatar_url(user) |> MediaProxy.url()
|
image = User.avatar_url(user) |> MediaProxy.url()
|
||||||
header = User.banner_url(user) |> MediaProxy.url()
|
header = User.banner_url(user) |> MediaProxy.url()
|
||||||
user_info = User.get_cached_user_info(user)
|
user_info = User.get_cached_user_info(user)
|
||||||
|
|
||||||
|
following_count =
|
||||||
|
((!user.info.hide_follows or opts[:for] == user) && user_info.following_count) || 0
|
||||||
|
|
||||||
|
followers_count =
|
||||||
|
((!user.info.hide_followers or opts[:for] == user) && user_info.follower_count) || 0
|
||||||
|
|
||||||
bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"]
|
bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"]
|
||||||
|
|
||||||
emojis =
|
emojis =
|
||||||
|
@ -102,8 +109,8 @@ defp do_render("account.json", %{user: user} = opts) do
|
||||||
display_name: display_name,
|
display_name: display_name,
|
||||||
locked: user_info.locked,
|
locked: user_info.locked,
|
||||||
created_at: Utils.to_masto_date(user.inserted_at),
|
created_at: Utils.to_masto_date(user.inserted_at),
|
||||||
followers_count: user_info.follower_count,
|
followers_count: followers_count,
|
||||||
following_count: user_info.following_count,
|
following_count: following_count,
|
||||||
statuses_count: user_info.note_count,
|
statuses_count: user_info.note_count,
|
||||||
note: bio || "",
|
note: bio || "",
|
||||||
url: User.profile_url(user),
|
url: User.profile_url(user),
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.StatusView do
|
defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
use Pleroma.Web, :view
|
use Pleroma.Web, :view
|
||||||
|
|
||||||
|
require Pleroma.Constants
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
@ -24,19 +26,19 @@ defp get_replied_to_activities([]), do: %{}
|
||||||
defp get_replied_to_activities(activities) do
|
defp get_replied_to_activities(activities) do
|
||||||
activities
|
activities
|
||||||
|> Enum.map(fn
|
|> Enum.map(fn
|
||||||
%{data: %{"type" => "Create", "object" => object}} ->
|
%{data: %{"type" => "Create"}} = activity ->
|
||||||
object = Object.normalize(object)
|
object = Object.normalize(activity)
|
||||||
object.data["inReplyTo"] != "" && object.data["inReplyTo"]
|
object && object.data["inReplyTo"] != "" && object.data["inReplyTo"]
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
nil
|
nil
|
||||||
end)
|
end)
|
||||||
|> Enum.filter(& &1)
|
|> Enum.filter(& &1)
|
||||||
|> Activity.create_by_object_ap_id()
|
|> Activity.create_by_object_ap_id_with_object()
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|> Enum.reduce(%{}, fn activity, acc ->
|
|> Enum.reduce(%{}, fn activity, acc ->
|
||||||
object = Object.normalize(activity)
|
object = Object.normalize(activity)
|
||||||
Map.put(acc, object.data["id"], activity)
|
if object, do: Map.put(acc, object.data["id"], activity), else: acc
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -88,6 +90,7 @@ def render(
|
||||||
reblogged_activity =
|
reblogged_activity =
|
||||||
Activity.create_by_object_ap_id(activity_object.data["id"])
|
Activity.create_by_object_ap_id(activity_object.data["id"])
|
||||||
|> Activity.with_preloaded_bookmark(opts[:for])
|
|> Activity.with_preloaded_bookmark(opts[:for])
|
||||||
|
|> Activity.with_set_thread_muted_field(opts[:for])
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
|
|
||||||
reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity))
|
reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity))
|
||||||
|
@ -142,6 +145,7 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity
|
||||||
object = Object.normalize(activity)
|
object = Object.normalize(activity)
|
||||||
|
|
||||||
user = get_user(activity.data["actor"])
|
user = get_user(activity.data["actor"])
|
||||||
|
user_follower_address = user.follower_address
|
||||||
|
|
||||||
like_count = object.data["like_count"] || 0
|
like_count = object.data["like_count"] || 0
|
||||||
announcement_count = object.data["announcement_count"] || 0
|
announcement_count = object.data["announcement_count"] || 0
|
||||||
|
@ -157,7 +161,11 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity
|
||||||
mentions =
|
mentions =
|
||||||
(object.data["to"] ++ tag_mentions)
|
(object.data["to"] ++ tag_mentions)
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
|> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
|
|> Enum.map(fn
|
||||||
|
Pleroma.Constants.as_public() -> nil
|
||||||
|
^user_follower_address -> nil
|
||||||
|
ap_id -> User.get_cached_by_ap_id(ap_id)
|
||||||
|
end)
|
||||||
|> Enum.filter(& &1)
|
|> Enum.filter(& &1)
|
||||||
|> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end)
|
|> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end)
|
||||||
|
|
||||||
|
@ -168,7 +176,7 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity
|
||||||
thread_muted? =
|
thread_muted? =
|
||||||
case activity.thread_muted? do
|
case activity.thread_muted? do
|
||||||
thread_muted? when is_boolean(thread_muted?) -> thread_muted?
|
thread_muted? when is_boolean(thread_muted?) -> thread_muted?
|
||||||
nil -> CommonAPI.thread_muted?(user, activity)
|
nil -> (opts[:for] && CommonAPI.thread_muted?(opts[:for], activity)) || false
|
||||||
end
|
end
|
||||||
|
|
||||||
attachment_data = object.data["attachment"] || []
|
attachment_data = object.data["attachment"] || []
|
||||||
|
|
|
@ -34,64 +34,18 @@ def schemas(conn, _params) do
|
||||||
def raw_nodeinfo do
|
def raw_nodeinfo do
|
||||||
stats = Stats.get_stats()
|
stats = Stats.get_stats()
|
||||||
|
|
||||||
exclusions = Config.get([:instance, :mrf_transparency_exclusions])
|
|
||||||
|
|
||||||
mrf_simple =
|
|
||||||
Config.get(:mrf_simple)
|
|
||||||
|> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end)
|
|
||||||
|> Enum.into(%{})
|
|
||||||
|
|
||||||
# This horror is needed to convert regex sigils to strings
|
|
||||||
mrf_keyword =
|
|
||||||
Config.get(:mrf_keyword, [])
|
|
||||||
|> Enum.map(fn {key, value} ->
|
|
||||||
{key,
|
|
||||||
Enum.map(value, fn
|
|
||||||
{pattern, replacement} ->
|
|
||||||
%{
|
|
||||||
"pattern" =>
|
|
||||||
if not is_binary(pattern) do
|
|
||||||
inspect(pattern)
|
|
||||||
else
|
|
||||||
pattern
|
|
||||||
end,
|
|
||||||
"replacement" => replacement
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern ->
|
|
||||||
if not is_binary(pattern) do
|
|
||||||
inspect(pattern)
|
|
||||||
else
|
|
||||||
pattern
|
|
||||||
end
|
|
||||||
end)}
|
|
||||||
end)
|
|
||||||
|> Enum.into(%{})
|
|
||||||
|
|
||||||
mrf_policies =
|
|
||||||
MRF.get_policies()
|
|
||||||
|> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end)
|
|
||||||
|
|
||||||
quarantined = Config.get([:instance, :quarantined_instances], [])
|
quarantined = Config.get([:instance, :quarantined_instances], [])
|
||||||
|
|
||||||
staff_accounts =
|
staff_accounts =
|
||||||
User.all_superusers()
|
User.all_superusers()
|
||||||
|> Enum.map(fn u -> u.ap_id end)
|
|> Enum.map(fn u -> u.ap_id end)
|
||||||
|
|
||||||
mrf_user_allowlist =
|
|
||||||
Config.get([:mrf_user_allowlist], [])
|
|
||||||
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
|
|
||||||
|
|
||||||
federation_response =
|
federation_response =
|
||||||
if Config.get([:instance, :mrf_transparency]) do
|
if Config.get([:instance, :mrf_transparency]) do
|
||||||
%{
|
{:ok, data} = MRF.describe()
|
||||||
mrf_policies: mrf_policies,
|
|
||||||
mrf_simple: mrf_simple,
|
data
|
||||||
mrf_keyword: mrf_keyword,
|
|> Map.merge(%{quarantined_instances: quarantined})
|
||||||
mrf_user_allowlist: mrf_user_allowlist,
|
|
||||||
quarantined_instances: quarantined,
|
|
||||||
exclusions: length(exclusions) > 0
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
%{}
|
%{}
|
||||||
end
|
end
|
||||||
|
|
|
@ -58,10 +58,10 @@ def safe_render(view, template, assigns \\ %{}) do
|
||||||
rescue
|
rescue
|
||||||
error ->
|
error ->
|
||||||
Logger.error(
|
Logger.error(
|
||||||
"#{__MODULE__} failed to render #{inspect({view, template})}: #{inspect(error)}"
|
"#{__MODULE__} failed to render #{inspect({view, template})}\n" <>
|
||||||
|
Exception.format(:error, error, __STACKTRACE__)
|
||||||
)
|
)
|
||||||
|
|
||||||
Logger.error(inspect(__STACKTRACE__))
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
5
mix.exs
5
mix.exs
|
@ -95,7 +95,7 @@ defp oauth_deps do
|
||||||
defp deps do
|
defp deps do
|
||||||
[
|
[
|
||||||
{:phoenix, "~> 1.4.8"},
|
{:phoenix, "~> 1.4.8"},
|
||||||
{:tzdata, "~> 1.0"},
|
{:tzdata, "~> 0.5.21"},
|
||||||
{:plug_cowboy, "~> 2.0"},
|
{:plug_cowboy, "~> 2.0"},
|
||||||
{:phoenix_pubsub, "~> 1.1"},
|
{:phoenix_pubsub, "~> 1.1"},
|
||||||
{:phoenix_ecto, "~> 4.0"},
|
{:phoenix_ecto, "~> 4.0"},
|
||||||
|
@ -115,8 +115,9 @@ defp deps do
|
||||||
{:tesla, "~> 1.2"},
|
{:tesla, "~> 1.2"},
|
||||||
{:jason, "~> 1.0"},
|
{:jason, "~> 1.0"},
|
||||||
{:mogrify, "~> 0.6.1"},
|
{:mogrify, "~> 0.6.1"},
|
||||||
{:ex_aws, "~> 2.0"},
|
{:ex_aws, "~> 2.1"},
|
||||||
{:ex_aws_s3, "~> 2.0"},
|
{:ex_aws_s3, "~> 2.0"},
|
||||||
|
{:sweet_xml, "~> 0.6.6"},
|
||||||
{:earmark, "~> 1.3"},
|
{:earmark, "~> 1.3"},
|
||||||
{:bbcode, "~> 0.1.1"},
|
{:bbcode, "~> 0.1.1"},
|
||||||
{:ex_machina, "~> 2.3", only: :test},
|
{:ex_machina, "~> 2.3", only: :test},
|
||||||
|
|
3
mix.lock
3
mix.lock
|
@ -81,13 +81,14 @@
|
||||||
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
|
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
|
||||||
"recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]},
|
"recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]},
|
||||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},
|
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},
|
||||||
|
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"},
|
||||||
"swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
|
"swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
|
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
|
||||||
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
|
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
|
||||||
"tesla": {:hex, :tesla, "1.2.1", "864783cc27f71dd8c8969163704752476cec0f3a51eb3b06393b3971dc9733ff", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
|
"tesla": {:hex, :tesla, "1.2.1", "864783cc27f71dd8c8969163704752476cec0f3a51eb3b06393b3971dc9733ff", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
|
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"tzdata": {:hex, :tzdata, "1.0.1", "f6027a331af7d837471248e62733c6ebee86a72e57c613aa071ebb1f750fc71a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
|
"tzdata": {:hex, :tzdata, "0.5.21", "8cbf3607fcce69636c672d5be2bbb08687fe26639a62bdcc283d267277db7cf0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"ueberauth": {:hex, :ueberauth, "0.6.1", "9e90d3337dddf38b1ca2753aca9b1e53d8a52b890191cdc55240247c89230412", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
"ueberauth": {:hex, :ueberauth, "0.6.1", "9e90d3337dddf38b1ca2753aca9b1e53d8a52b890191cdc55240247c89230412", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
|
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
|
||||||
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"},
|
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"},
|
||||||
|
|
1
priv/static/adminfe/chunk-0e18.e12401fb.css
Normal file
1
priv/static/adminfe/chunk-0e18.e12401fb.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
header[data-v-71c7ded0]{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;margin:22px 0;padding-left:15px}header h1[data-v-71c7ded0]{margin:0 0 0 10px}table[data-v-71c7ded0]{margin:10px 0 0 15px}table .name-col[data-v-71c7ded0]{width:150px}.el-table--border[data-v-71c7ded0]:after,.el-table--group[data-v-71c7ded0]:after,.el-table[data-v-71c7ded0]:before{background-color:transparent}.poll ul[data-v-71c7ded0]{list-style-type:none;padding:0;width:30%}.image[data-v-71c7ded0]{width:20%}.image img[data-v-71c7ded0]{width:100%}.statuses[data-v-71c7ded0]{padding-right:20px}.show-private[data-v-71c7ded0]{text-align:right;line-height:67px;padding-right:20px}
|
|
@ -1 +1 @@
|
||||||
.status-account{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-avatar-img{width:15px;height:15px;margin-right:5px}.status-account-name{margin:0;height:22px}.status-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.status-content{font-size:15px}.status-card{margin-bottom:15px}.status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.el-message{min-width:80%}.el-message-box{width:80%}.status-card .el-card__header{padding:10px 17px}.status-card .el-tag{margin:3px 4px 3px 0}.status-card .status-account-container{margin-bottom:5px}.status-card .status-actions-button{margin:3px 0}.status-card .status-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.account{text-decoration:underline}.avatar-img{vertical-align:bottom;width:15px;height:15px;margin-left:5px}.el-card__body{padding:17px}.el-card__header{background-color:#fafafa;padding:10px 20px}.el-collapse{border-bottom:none}.el-collapse-item__header{height:46px;font-size:14px}.el-collapse-item__content{padding-bottom:7px}.el-icon-arrow-right{margin-right:6px}.el-icon-close{padding:10px 5px 10px 10px;cursor:pointer}h4{margin:0;height:17px}.header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;height:40px}.id{color:grey;margin-top:6px}.line{width:100%;height:0;border:.5px solid #ebeef5;margin:15px 0}.new-note p{font-size:14px;font-weight:500;height:17px;margin:13px 0 7px}.note{-webkit-box-shadow:0 2px 5px 0 rgba(0,0,0,.1);box-shadow:0 2px 5px 0 rgba(0,0,0,.1);margin-bottom:10px}.no-notes{font-style:italic;color:grey}.report-row-key{font-weight:500;font-size:14px}.report-title{margin:0}.statuses{margin-top:15px}.submit-button{display:block;margin:7px 0 17px auto}.timestamp{margin:0;font-style:italic;color:grey}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.timeline-item-container .header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:80px}.timeline-item-container .id{margin:6px 0 0}}.select-field[data-v-bb4390da]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-bb4390da]{width:100%;margin-bottom:5px}}.reports-container .el-timeline[data-v-e32c7dc6]{margin:45px 45px 45px 19px;padding:0}.reports-container .filter-container[data-v-e32c7dc6]{margin:22px 15px;padding-bottom:0}.reports-container h1[data-v-e32c7dc6]{margin:22px 0 0 15px}.reports-container .no-reports-message[data-v-e32c7dc6]{color:grey;margin-left:19px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.reports-container h1[data-v-e32c7dc6]{margin:7px 10px 15px}.reports-container .filter-container[data-v-e32c7dc6]{margin:0 10px}.reports-container .timeline[data-v-e32c7dc6]{margin:20px 20px 20px 18px}}
|
.status-account{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-avatar-img{width:15px;height:15px;margin-right:5px}.status-account-name{margin:0;height:22px}.status-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.status-content{font-size:15px}.status-card{margin-bottom:15px}.status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.el-message{min-width:80%}.el-message-box{width:80%}.status-card .el-card__header{padding:10px 17px}.status-card .el-tag{margin:3px 4px 3px 0}.status-card .status-account-container{margin-bottom:5px}.status-card .status-actions-button{margin:3px 0}.status-card .status-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.account{text-decoration:underline}.avatar-img{vertical-align:bottom;width:15px;height:15px;margin-left:5px}.el-card__body{padding:17px}.el-card__header{background-color:#fafafa;padding:10px 20px}.el-collapse{border-bottom:none}.el-collapse-item__header{height:46px;font-size:14px}.el-collapse-item__content{padding-bottom:7px}.el-icon-arrow-right{margin-right:6px}.el-icon-close{padding:10px 5px 10px 10px;cursor:pointer}h4{margin:0;height:17px}.header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;height:40px}.id{color:grey;margin-top:6px}.line{width:100%;height:0;border:.5px solid #ebeef5;margin:15px 0}.new-note p{font-size:14px;font-weight:500;height:17px;margin:13px 0 7px}.note{-webkit-box-shadow:0 2px 5px 0 rgba(0,0,0,.1);box-shadow:0 2px 5px 0 rgba(0,0,0,.1);margin-bottom:10px}.no-notes{font-style:italic;color:grey}.report-row-key{font-weight:500;font-size:14px}.report-title{margin:0}.statuses{margin-top:15px}.submit-button{display:block;margin:7px 0 17px auto}.timestamp{margin:0;font-style:italic;color:grey}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.timeline-item-container .header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:80px}.timeline-item-container .id{margin:6px 0 0}}.select-field[data-v-07695bc4]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-07695bc4]{width:100%;margin-bottom:5px}}.reports-container .el-timeline[data-v-e32c7dc6]{margin:45px 45px 45px 19px;padding:0}.reports-container .filter-container[data-v-e32c7dc6]{margin:22px 15px;padding-bottom:0}.reports-container h1[data-v-e32c7dc6]{margin:22px 0 0 15px}.reports-container .no-reports-message[data-v-e32c7dc6]{color:grey;margin-left:19px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.reports-container h1[data-v-e32c7dc6]{margin:7px 10px 15px}.reports-container .filter-container[data-v-e32c7dc6]{margin:0 10px}.reports-container .timeline[data-v-e32c7dc6]{margin:20px 20px 20px 18px}}
|
1
priv/static/adminfe/chunk-5e57.ac97b15a.css
Normal file
1
priv/static/adminfe/chunk-5e57.ac97b15a.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
a{text-decoration:underline}.code{background-color:rgba(173,190,214,.48);border-radius:3px;font-family:monospace;padding:0 3px}.el-form-item{margin-right:30px}.el-select{width:100%}.esshd-list{margin:0}.expl{color:#666;font-size:13px;line-height:22px;margin:5px 0 0;overflow-wrap:break-word}.highlight{background-color:#e6e6e6}.limit-button-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.limit-expl{margin-left:10px}.limit-input{width:48%;margin:0 0 5px 8px}.line{width:100%;height:0;border:1px solid #eee;margin-bottom:22px}.mascot-container{margin-bottom:15px}.mascot-input{margin-bottom:7px}.mascot-name-container{display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:7px}.mascot-name-input{margin-right:10px}.name-input{width:30%;margin-right:8px}.options-paragraph{font-size:14px;color:#606266;font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei;font-weight:700;line-height:20px;margin:0 0 14px}.options-paragraph-container{overflow-wrap:break-word;margin-bottom:0}.pattern-input{width:20%;margin-right:8px}.setting-input{display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:10px}.single-input{margin-right:10px}.scale-input{width:48%;margin:0 8px 5px 0}.replacement-input{width:80%;margin-left:8px;margin-right:10px}.text{line-height:20px;margin-right:15px}.upload-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.value-input{width:70%;margin-left:8px;margin-right:10px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.el-form-item{margin-right:15px}.el-input__inner{padding:0 5px}.el-form-item__label:not(.no-top-margin){padding-left:3px;padding-right:10px;line-height:22px;margin-top:7px}.el-message{min-width:80%}.el-select__tags{overflow:hidden}.name-input{width:40%;margin-right:5px}p.expl{line-height:20px}.pattern-input{width:40%;margin-right:4px}.replacement-input{width:60%;margin-left:4px;margin-right:5px}.top-margin{position:absolute;top:25%}.value-input{width:60%;margin-left:5px;margin-right:8px}}.settings-container .el-tabs[data-v-729534ce]{margin-top:20px}.settings-container h1[data-v-729534ce]{margin:22px 0 0 15px}
|
|
@ -1 +1 @@
|
||||||
.select-field[data-v-71bc6b38]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-71bc6b38]{width:100%;margin-bottom:5px}}.actions-button[data-v-94227b1e]{text-align:left;width:350px;padding:10px}.actions-button-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-dropdown[data-v-94227b1e]{float:right}.el-icon-edit[data-v-94227b1e]{margin-right:5px}.tag-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.tag-text[data-v-94227b1e]{padding-right:20px}.no-hover[data-v-94227b1e]:hover{color:#606266;background-color:#fff;cursor:auto}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.create-user-dialog{width:80%}.create-account-form-item{margin-bottom:30px}.el-dialog__body{padding:20px 20px 0}}.actions-button[data-v-3ffddd00]{text-align:left;width:350px;padding:10px}.actions-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:0 15px 10px}.active-tag[data-v-3ffddd00]{color:#409eff;font-weight:700}.active-tag .el-icon-check[data-v-3ffddd00]{color:#409eff;float:right;margin:7px 0 0 15px}.el-dropdown-link[data-v-3ffddd00]:hover{cursor:pointer;color:#409eff}.el-icon-plus[data-v-3ffddd00]{margin-right:5px}.users-container h1[data-v-3ffddd00]{margin:22px 0 0 15px}.users-container .pagination[data-v-3ffddd00]{margin:25px 0;text-align:center}.users-container .search[data-v-3ffddd00]{width:350px;float:right}.users-container .filter-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:22px 15px 15px}.users-container .user-count[data-v-3ffddd00]{color:grey;font-size:28px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.users-container h1[data-v-3ffddd00]{margin:7px 10px 15px}.users-container .actions-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px 7px}.users-container .create-account[data-v-3ffddd00]{width:100%}.users-container .el-icon-arrow-down[data-v-3ffddd00]{font-size:12px}.users-container .search[data-v-3ffddd00]{width:100%}.users-container .filter-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;height:82px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px}.users-container .el-tag[data-v-3ffddd00]{width:30px;display:inline-block;margin-bottom:4px;font-weight:700}.users-container .el-tag.el-tag--danger[data-v-3ffddd00],.users-container .el-tag.el-tag--success[data-v-3ffddd00]{padding-left:8px}}
|
.select-field[data-v-71bc6b38]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-71bc6b38]{width:100%;margin-bottom:5px}}.actions-button[data-v-94227b1e]{text-align:left;width:350px;padding:10px}.actions-button-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-dropdown[data-v-94227b1e]{float:right}.el-icon-edit[data-v-94227b1e]{margin-right:5px}.tag-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.tag-text[data-v-94227b1e]{padding-right:20px}.no-hover[data-v-94227b1e]:hover{color:#606266;background-color:#fff;cursor:auto}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.create-user-dialog{width:80%}.create-account-form-item{margin-bottom:30px}.el-dialog__body{padding:20px 20px 0}}.actions-button[data-v-c51cd8ee]{text-align:left;width:350px;padding:10px}.actions-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:0 15px 10px}.active-tag[data-v-c51cd8ee]{color:#409eff;font-weight:700}.active-tag .el-icon-check[data-v-c51cd8ee]{color:#409eff;float:right;margin:7px 0 0 15px}.el-dropdown-link[data-v-c51cd8ee]:hover{cursor:pointer;color:#409eff}.el-icon-plus[data-v-c51cd8ee]{margin-right:5px}.users-container h1[data-v-c51cd8ee]{margin:22px 0 0 15px}.users-container .pagination[data-v-c51cd8ee]{margin:25px 0;text-align:center}.users-container .search[data-v-c51cd8ee]{width:350px;float:right}.users-container .filter-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:22px 15px 15px}.users-container .user-count[data-v-c51cd8ee]{color:grey;font-size:28px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.users-container h1[data-v-c51cd8ee]{margin:7px 10px 15px}.users-container .actions-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px 7px}.users-container .create-account[data-v-c51cd8ee]{width:100%}.users-container .el-icon-arrow-down[data-v-c51cd8ee]{font-size:12px}.users-container .search[data-v-c51cd8ee]{width:100%}.users-container .filter-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;height:82px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px}.users-container .el-tag[data-v-c51cd8ee]{width:30px;display:inline-block;margin-bottom:4px;font-weight:700}.users-container .el-tag.el-tag--danger[data-v-c51cd8ee],.users-container .el-tag.el-tag--success[data-v-c51cd8ee]{padding-left:8px}}
|
1
priv/static/adminfe/chunk-elementUI.e5cd8da6.css
Normal file
1
priv/static/adminfe/chunk-elementUI.e5cd8da6.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
||||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Admin FE</title><link rel="shortcut icon" href=favicon.ico><link href=chunk-elementUI.f74c256b.css rel=stylesheet><link href=chunk-libs.4e8c4664.css rel=stylesheet><link href=app.34fc670f.css rel=stylesheet></head><body><script src=/pleroma/admin/static/tinymce4.7.5/tinymce.min.js></script><div id=app></div><script type=text/javascript src=static/js/runtime.d8d12c12.js></script><script type=text/javascript src=static/js/chunk-elementUI.1fa5434b.js></script><script type=text/javascript src=static/js/chunk-libs.d5609760.js></script><script type=text/javascript src=static/js/app.4137ad8f.js></script></body></html>
|
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=renderer content=webkit><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Admin FE</title><link rel="shortcut icon" href=favicon.ico><link href=chunk-elementUI.e5cd8da6.css rel=stylesheet><link href=chunk-libs.4e8c4664.css rel=stylesheet><link href=app.34fc670f.css rel=stylesheet></head><body><script src=/pleroma/admin/static/tinymce4.7.5/tinymce.min.js></script><div id=app></div><script type=text/javascript src=static/js/runtime.f40c8ec4.js></script><script type=text/javascript src=static/js/chunk-elementUI.1911151b.js></script><script type=text/javascript src=static/js/chunk-libs.fb0b7f4a.js></script><script type=text/javascript src=static/js/app.8e186193.js></script></body></html>
|
Binary file not shown.
BIN
priv/static/adminfe/static/fonts/element-icons.535877f.woff
Normal file
BIN
priv/static/adminfe/static/fonts/element-icons.535877f.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
priv/static/adminfe/static/fonts/element-icons.732389d.ttf
Normal file
BIN
priv/static/adminfe/static/fonts/element-icons.732389d.ttf
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
1
priv/static/adminfe/static/js/app.8e186193.js
Normal file
1
priv/static/adminfe/static/js/app.8e186193.js
Normal file
File diff suppressed because one or more lines are too long
1
priv/static/adminfe/static/js/chunk-0e18.208cd826.js
Normal file
1
priv/static/adminfe/static/js/chunk-0e18.208cd826.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(window.webpackJsonp=window.webpackJsonp||[]).push([["chunk-0e18"],{"4bFr":function(t,e,s){"use strict";s.r(e);var a={name:"UsersShow",data:function(){return{showPrivate:!1}},computed:{loading:function(){return this.$store.state.userProfile.loading},user:function(){return this.$store.state.userProfile.user},statuses:function(){return this.$store.state.userProfile.statuses}},mounted:function(){this.$store.dispatch("FetchData",{id:this.$route.params.id,godmode:!1})},methods:{optionPercent:function(t,e){var s=t.options.reduce(function(t,e){return t+e.votes_count},0);return 0===s?0:+(e.votes_count/s*100).toFixed(1)},createdAtLocaleString:function(t){var e=new Date(t);return"".concat(e.toLocaleDateString()," ").concat(e.toLocaleTimeString())},onTogglePrivate:function(){console.log(this.showPrivate),this.$store.dispatch("FetchData",{id:this.$route.params.id,godmode:this.showPrivate})}}},r=(s("QG2t"),s("KHd+")),l=Object(r.a)(a,function(){var t=this,e=t.$createElement,s=t._self._c||e;return t.loading?t._e():s("main",[s("header",[s("el-avatar",{attrs:{src:t.user.avatar,size:"large"}}),t._v(" "),s("h1",[t._v(t._s(t.user.display_name))])],1),t._v(" "),s("el-row",[s("el-col",{attrs:{span:6}},[s("div",{staticClass:"el-table el-table--fit el-table--enable-row-hover el-table--enable-row-transition el-table--medium"},[s("table",{staticClass:"el-table__body"},[s("tbody",[s("tr",{staticClass:"el-table__row"},[s("td",{staticClass:"name-col"},[t._v("ID")]),t._v(" "),s("td",{staticClass:"value-col"},[t._v("\n "+t._s(t.user.id)+"\n ")])]),t._v(" "),s("tr",{staticClass:"el-table__row"},[s("td",[t._v(t._s(t.$t("userProfile.tags")))]),t._v(" "),s("td",[t._l(t.user.tags,function(e){return s("el-tag",{key:e},[t._v(t._s(e))])}),t._v(" "),0===t.user.tags.length?s("span",[t._v("None")]):t._e()],2)]),t._v(" "),s("tr",{staticClass:"el-table__row"},[s("td",[t._v(t._s(t.$t("userProfile.moderator")))]),t._v(" "),s("td",[t.user.roles.moderator?s("el-tag",{attrs:{type:"success"}},[s("i",{staticClass:"el-icon-check"})]):t._e(),t._v(" "),t.user.roles.moderator?t._e():s("el-tag",{attrs:{type:"danger"}},[s("i",{staticClass:"el-icon-error"})])],1)]),t._v(" "),s("tr",{staticClass:"el-table__row"},[s("td",[t._v(t._s(t.$t("userProfile.admin")))]),t._v(" "),s("td",[t.user.roles.admin?s("el-tag",{attrs:{type:"success"}},[s("i",{staticClass:"el-icon-check"})]):t._e(),t._v(" "),t.user.roles.admin?t._e():s("el-tag",{attrs:{type:"danger"}},[s("i",{staticClass:"el-icon-error"})])],1)]),t._v(" "),s("tr",{staticClass:"el-table__row"},[s("td",[t._v(t._s(t.$t("userProfile.local")))]),t._v(" "),s("td",[t.user.local?s("el-tag",{attrs:{type:"success"}},[s("i",{staticClass:"el-icon-check"})]):t._e(),t._v(" "),t.user.local?t._e():s("el-tag",{attrs:{type:"danger"}},[s("i",{staticClass:"el-icon-error"})])],1)]),t._v(" "),s("tr",{staticClass:"el-table__row"},[s("td",[t._v(t._s(t.$t("userProfile.deactivated")))]),t._v(" "),s("td",[t.user.deactivated?s("el-tag",{attrs:{type:"success"}},[s("i",{staticClass:"el-icon-check"})]):t._e(),t._v(" "),t.user.deactivated?t._e():s("el-tag",{attrs:{type:"danger"}},[s("i",{staticClass:"el-icon-error"})])],1)]),t._v(" "),s("tr",{staticClass:"el-table__row"},[s("td",[t._v(t._s(t.$t("userProfile.nickname")))]),t._v(" "),s("td",[t._v("\n "+t._s(t.user.nickname)+"\n ")])])])])])]),t._v(" "),s("el-row",{staticClass:"row-bg",attrs:{type:"flex",justify:"space-between"}},[s("el-col",{attrs:{span:18}},[s("h2",[t._v(t._s(t.$t("userProfile.recentStatuses")))])]),t._v(" "),s("el-col",{staticClass:"show-private",attrs:{span:6}},[s("el-checkbox",{on:{change:t.onTogglePrivate},model:{value:t.showPrivate,callback:function(e){t.showPrivate=e},expression:"showPrivate"}},[t._v("\n "+t._s(t.$t("userProfile.showPrivateStatuses"))+"\n ")])],1)],1),t._v(" "),s("el-col",{attrs:{span:18}},[s("el-timeline",{staticClass:"statuses"},t._l(t.statuses,function(e){return s("el-timeline-item",{key:e.id,attrs:{timestamp:t.createdAtLocaleString(e.created_at)}},[s("el-card",[e.spoiler_text?s("strong",[t._v(t._s(e.spoiler_text))]):t._e(),t._v(" "),e.content?s("p",{domProps:{innerHTML:t._s(e.content)}}):t._e(),t._v(" "),e.poll?s("div",{staticClass:"poll"},[s("ul",t._l(e.poll.options,function(a,r){return s("li",{key:r},[t._v("\n "+t._s(a.title)+"\n "),s("el-progress",{attrs:{percentage:t.optionPercent(e.poll,a)}})],1)}),0)]):t._e(),t._v(" "),t._l(e.media_attachments,function(t,e){return s("div",{key:e,staticClass:"image"},[s("img",{attrs:{src:t.preview_url}})])})],2)],1)}),1)],1)],1)],1)},[],!1,null,"71c7ded0",null);l.options.__file="show.vue";e.default=l.exports},QG2t:function(t,e,s){"use strict";var a=s("R7Mx");s.n(a).a},R7Mx:function(t,e,s){}}]);
|
1
priv/static/adminfe/static/js/chunk-1fbf.616fb309.js
Normal file
1
priv/static/adminfe/static/js/chunk-1fbf.616fb309.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
priv/static/adminfe/static/js/chunk-5e57.7313703a.js
Normal file
1
priv/static/adminfe/static/js/chunk-5e57.7313703a.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js
Normal file
1
priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js
Normal file
File diff suppressed because one or more lines are too long
1
priv/static/adminfe/static/js/chunk-e547.d57d1b91.js
Normal file
1
priv/static/adminfe/static/js/chunk-e547.d57d1b91.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
||||||
!function(e){function t(t){for(var r,o,a=t[0],i=t[1],f=t[2],l=0,h=[];l<a.length;l++)o=a[l],u[o]&&h.push(u[o][0]),u[o]=0;for(r in i)Object.prototype.hasOwnProperty.call(i,r)&&(e[r]=i[r]);for(s&&s(t);h.length;)h.shift()();return c.push.apply(c,f||[]),n()}function n(){for(var e,t=0;t<c.length;t++){for(var n=c[t],r=!0,o=1;o<n.length;o++){var i=n[o];0!==u[i]&&(r=!1)}r&&(c.splice(t--,1),e=a(a.s=n[0]))}return e}var r={},o={runtime:0},u={runtime:0},c=[];function a(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,a),n.l=!0,n.exports}a.e=function(e){var t=[];o[e]?t.push(o[e]):0!==o[e]&&{"chunk-56c9":1,"chunk-5eaf":1,"chunk-18e1":1,"chunk-8b70":1,"chunk-f018":1}[e]&&t.push(o[e]=new Promise(function(t,n){for(var r=({}[e]||e)+"."+{"7zzA":"31d6cfe0",JEtC:"31d6cfe0","chunk-02a0":"31d6cfe0","chunk-56c9":"c27dac5e","chunk-0620":"31d6cfe0","chunk-5eaf":"1a04e979","chunk-18e1":"6aaab273","chunk-8b70":"9ba0945c","chunk-f018":"0d22684d"}[e]+".css",o=a.p+r,u=document.getElementsByTagName("link"),c=0;c<u.length;c++){var i=(l=u[c]).getAttribute("data-href")||l.getAttribute("href");if("stylesheet"===l.rel&&(i===r||i===o))return t()}var f=document.getElementsByTagName("style");for(c=0;c<f.length;c++){var l;if((i=(l=f[c]).getAttribute("data-href"))===r||i===o)return t()}var s=document.createElement("link");s.rel="stylesheet",s.type="text/css",s.onload=t,s.onerror=function(t){var r=t&&t.target&&t.target.src||o,u=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");u.request=r,n(u)},s.href=o,document.getElementsByTagName("head")[0].appendChild(s)}).then(function(){o[e]=0}));var n=u[e];if(0!==n)if(n)t.push(n[2]);else{var r=new Promise(function(t,r){n=u[e]=[t,r]});t.push(n[2]=r);var c,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{"7zzA":"e1ae1c94",JEtC:"f9ba4594","chunk-02a0":"db6ec114","chunk-56c9":"28e35fc3","chunk-0620":"c765c190","chunk-5eaf":"5b76e416","chunk-18e1":"7f9c377c","chunk-8b70":"46525646","chunk-f018":"e1a7a454"}[e]+".js"}(e),c=function(t){i.onerror=i.onload=null,clearTimeout(f);var n=u[e];if(0!==n){if(n){var r=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src,c=new Error("Loading chunk "+e+" failed.\n("+r+": "+o+")");c.type=r,c.request=o,n[1](c)}u[e]=void 0}};var f=setTimeout(function(){c({type:"timeout",target:i})},12e4);i.onerror=i.onload=c,document.head.appendChild(i)}return Promise.all(t)},a.m=e,a.c=r,a.d=function(e,t,n){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(a.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)a.d(n,r,function(t){return e[t]}.bind(null,r));return n},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],f=i.push.bind(i);i.push=t,i=i.slice();for(var l=0;l<i.length;l++)t(i[l]);var s=f;n()}([]);
|
|
1
priv/static/adminfe/static/js/runtime.f40c8ec4.js
Normal file
1
priv/static/adminfe/static/js/runtime.f40c8ec4.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
!function(e){function n(n){for(var r,u,a=n[0],f=n[1],i=n[2],l=0,s=[];l<a.length;l++)u=a[l],c[u]&&s.push(c[u][0]),c[u]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);for(h&&h(n);s.length;)s.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,u=1;u<t.length;u++){var f=t[u];0!==c[f]&&(r=!1)}r&&(o.splice(n--,1),e=a(a.s=t[0]))}return e}var r={},u={runtime:0},c={runtime:0},o=[];function a(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=[];u[e]?n.push(u[e]):0!==u[e]&&{"chunk-1fbf":1,"chunk-e547":1,"chunk-0e18":1,"chunk-18e1":1,"chunk-2325":1,"chunk-5e57":1,"chunk-8b70":1}[e]&&n.push(u[e]=new Promise(function(n,t){for(var r=({}[e]||e)+"."+{"7zzA":"31d6cfe0",JEtC:"31d6cfe0","chunk-02a0":"31d6cfe0","chunk-1fbf":"d7a1893c","chunk-0620":"31d6cfe0","chunk-e547":"e4b6230b","chunk-0e18":"e12401fb","chunk-18e1":"6aaab273","chunk-2325":"0d22684d","chunk-7fe2":"31d6cfe0","chunk-5e57":"ac97b15a","chunk-8b70":"9ba0945c"}[e]+".css",u=a.p+r,c=document.getElementsByTagName("link"),o=0;o<c.length;o++){var f=(l=c[o]).getAttribute("data-href")||l.getAttribute("href");if("stylesheet"===l.rel&&(f===r||f===u))return n()}var i=document.getElementsByTagName("style");for(o=0;o<i.length;o++){var l;if((f=(l=i[o]).getAttribute("data-href"))===r||f===u)return n()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=n,h.onerror=function(n){var r=n&&n.target&&n.target.src||u,c=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");c.request=r,t(c)},h.href=u,document.getElementsByTagName("head")[0].appendChild(h)}).then(function(){u[e]=0}));var t=c[e];if(0!==t)if(t)n.push(t[2]);else{var r=new Promise(function(n,r){t=c[e]=[n,r]});n.push(t[2]=r);var o,f=document.createElement("script");f.charset="utf-8",f.timeout=120,a.nc&&f.setAttribute("nonce",a.nc),f.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{"7zzA":"e1ae1c94",JEtC:"f9ba4594","chunk-02a0":"db6ec114","chunk-1fbf":"616fb309","chunk-0620":"c765c190","chunk-e547":"d57d1b91","chunk-0e18":"208cd826","chunk-18e1":"7f9c377c","chunk-2325":"154a537b","chunk-7fe2":"458f9da5","chunk-5e57":"7313703a","chunk-8b70":"46525646"}[e]+".js"}(e),o=function(n){f.onerror=f.onload=null,clearTimeout(i);var t=c[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),u=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+u+")");o.type=r,o.request=u,t[1](o)}c[e]=void 0}};var i=setTimeout(function(){o({type:"timeout",target:f})},12e4);f.onerror=f.onload=o,document.head.appendChild(f)}return Promise.all(n)},a.m=e,a.c=r,a.d=function(e,n,t){a.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,n){if(1&n&&(e=a(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)a.d(t,r,function(n){return e[n]}.bind(null,r));return t},a.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="",a.oe=function(e){throw console.error(e),e};var f=window.webpackJsonp=window.webpackJsonp||[],i=f.push.bind(f);f.push=n,f=f.slice();for(var l=0;l<f.length;l++)n(f[l]);var h=i;t()}([]);
|
13
test/support/mrf_module_mock.ex
Normal file
13
test/support/mrf_module_mock.ex
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule MRFModuleMock do
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{mrf_module_mock: "some config data"}}
|
||||||
|
end
|
|
@ -3,8 +3,11 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.DatabaseTest do
|
defmodule Mix.Tasks.Pleroma.DatabaseTest do
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
@ -46,4 +49,37 @@ test "following and followers count are updated" do
|
||||||
assert user.info.follower_count == 0
|
assert user.info.follower_count == 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "running fix_likes_collections" do
|
||||||
|
test "it turns OrderedCollection likes into empty arrays" do
|
||||||
|
[user, user2] = insert_pair(:user)
|
||||||
|
|
||||||
|
{:ok, %{id: id, object: object}} = CommonAPI.post(user, %{"status" => "test"})
|
||||||
|
{:ok, %{object: object2}} = CommonAPI.post(user, %{"status" => "test test"})
|
||||||
|
|
||||||
|
CommonAPI.favorite(id, user2)
|
||||||
|
|
||||||
|
likes = %{
|
||||||
|
"first" =>
|
||||||
|
"http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1",
|
||||||
|
"id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes",
|
||||||
|
"totalItems" => 3,
|
||||||
|
"type" => "OrderedCollection"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_data = Map.put(object2.data, "likes", likes)
|
||||||
|
|
||||||
|
object2
|
||||||
|
|> Ecto.Changeset.change(%{data: new_data})
|
||||||
|
|> Repo.update()
|
||||||
|
|
||||||
|
assert length(Object.get_by_id(object.id).data["likes"]) == 1
|
||||||
|
assert is_map(Object.get_by_id(object2.id).data["likes"])
|
||||||
|
|
||||||
|
assert :ok == Mix.Tasks.Pleroma.Database.run(["fix_likes_collections"])
|
||||||
|
|
||||||
|
assert length(Object.get_by_id(object.id).data["likes"]) == 1
|
||||||
|
assert Enum.empty?(Object.get_by_id(object2.id).data["likes"])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
32
test/uploaders/local_test.exs
Normal file
32
test/uploaders/local_test.exs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Uploaders.LocalTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
alias Pleroma.Uploaders.Local
|
||||||
|
|
||||||
|
describe "get_file/1" do
|
||||||
|
test "it returns path to local folder for files" do
|
||||||
|
assert Local.get_file("") == {:ok, {:static_dir, "test/uploads"}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "put_file/1" do
|
||||||
|
test "put file to local folder" do
|
||||||
|
file_path = "local_upload/files/image.jpg"
|
||||||
|
|
||||||
|
file = %Pleroma.Upload{
|
||||||
|
name: "image.jpg",
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: file_path,
|
||||||
|
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Local.put_file(file) == :ok
|
||||||
|
|
||||||
|
assert Path.join([Local.upload_path(), file_path])
|
||||||
|
|> File.exists?()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
50
test/uploaders/mdii_test.exs
Normal file
50
test/uploaders/mdii_test.exs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Uploaders.MDIITest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
alias Pleroma.Uploaders.MDII
|
||||||
|
import Tesla.Mock
|
||||||
|
|
||||||
|
describe "get_file/1" do
|
||||||
|
test "it returns path to local folder for files" do
|
||||||
|
assert MDII.get_file("") == {:ok, {:static_dir, "test/uploads"}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "put_file/1" do
|
||||||
|
setup do
|
||||||
|
file_upload = %Pleroma.Upload{
|
||||||
|
name: "mdii-image.jpg",
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: "test_folder/mdii-image.jpg",
|
||||||
|
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
[file_upload: file_upload]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "save file", %{file_upload: file_upload} do
|
||||||
|
mock(fn
|
||||||
|
%{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} ->
|
||||||
|
%Tesla.Env{status: 200, body: "mdii-image"}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert MDII.put_file(file_upload) ==
|
||||||
|
{:ok, {:url, "https://mdii.sakura.ne.jp/mdii-image.jpg"}}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "save file to local if MDII isn`t available", %{file_upload: file_upload} do
|
||||||
|
mock(fn
|
||||||
|
%{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} ->
|
||||||
|
%Tesla.Env{status: 500}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert MDII.put_file(file_upload) == :ok
|
||||||
|
|
||||||
|
assert Path.join([Pleroma.Uploaders.Local.upload_path(), file_upload.path])
|
||||||
|
|> File.exists?()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
90
test/uploaders/s3_test.exs
Normal file
90
test/uploaders/s3_test.exs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Uploaders.S3Test do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Config
|
||||||
|
alias Pleroma.Uploaders.S3
|
||||||
|
|
||||||
|
import Mock
|
||||||
|
import ExUnit.CaptureLog
|
||||||
|
|
||||||
|
setup do
|
||||||
|
config = Config.get([Pleroma.Uploaders.S3])
|
||||||
|
|
||||||
|
Config.put([Pleroma.Uploaders.S3],
|
||||||
|
bucket: "test_bucket",
|
||||||
|
public_endpoint: "https://s3.amazonaws.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
on_exit(fn ->
|
||||||
|
Config.put([Pleroma.Uploaders.S3], config)
|
||||||
|
end)
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "get_file/1" do
|
||||||
|
test "it returns path to local folder for files" do
|
||||||
|
assert S3.get_file("test_image.jpg") == {
|
||||||
|
:ok,
|
||||||
|
{:url, "https://s3.amazonaws.com/test_bucket/test_image.jpg"}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it returns path without bucket when truncated_namespace set to ''" do
|
||||||
|
Config.put([Pleroma.Uploaders.S3],
|
||||||
|
bucket: "test_bucket",
|
||||||
|
public_endpoint: "https://s3.amazonaws.com",
|
||||||
|
truncated_namespace: ""
|
||||||
|
)
|
||||||
|
|
||||||
|
assert S3.get_file("test_image.jpg") == {
|
||||||
|
:ok,
|
||||||
|
{:url, "https://s3.amazonaws.com/test_image.jpg"}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it returns path with bucket namespace when namespace is set" do
|
||||||
|
Config.put([Pleroma.Uploaders.S3],
|
||||||
|
bucket: "test_bucket",
|
||||||
|
public_endpoint: "https://s3.amazonaws.com",
|
||||||
|
bucket_namespace: "family"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert S3.get_file("test_image.jpg") == {
|
||||||
|
:ok,
|
||||||
|
{:url, "https://s3.amazonaws.com/family:test_bucket/test_image.jpg"}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "put_file/1" do
|
||||||
|
setup do
|
||||||
|
file_upload = %Pleroma.Upload{
|
||||||
|
name: "image-tet.jpg",
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: "test_folder/image-tet.jpg",
|
||||||
|
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
[file_upload: file_upload]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "save file", %{file_upload: file_upload} do
|
||||||
|
with_mock ExAws, request: fn _ -> {:ok, :ok} end do
|
||||||
|
assert S3.put_file(file_upload) == {:ok, {:file, "test_folder/image-tet.jpg"}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error", %{file_upload: file_upload} do
|
||||||
|
with_mock ExAws, request: fn _ -> {:error, "S3 Upload failed"} end do
|
||||||
|
assert capture_log(fn ->
|
||||||
|
assert S3.put_file(file_upload) == {:error, "S3 Upload failed"}
|
||||||
|
end) =~ "Elixir.Pleroma.Uploaders.S3: {:error, \"S3 Upload failed\"}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -526,7 +526,10 @@ test "it has required fields" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it restricts some sizes" do
|
test "it restricts some sizes" do
|
||||||
[bio: 5000, name: 100]
|
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
||||||
|
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
||||||
|
|
||||||
|
[bio: bio_limit, name: name_limit]
|
||||||
|> Enum.each(fn {field, size} ->
|
|> Enum.each(fn {field, size} ->
|
||||||
string = String.pad_leading(".", size)
|
string = String.pad_leading(".", size)
|
||||||
cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
|
cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
|
||||||
|
|
|
@ -4,8 +4,8 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
|
||||||
|
|
||||||
test "subdomains_regex/1" do
|
test "subdomains_regex/1" do
|
||||||
assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [
|
assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [
|
||||||
~r/^unsafe.tld$/,
|
~r/^unsafe.tld$/i,
|
||||||
~r/^(.*\.)*unsafe.tld$/
|
~r/^(.*\.)*unsafe.tld$/i
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ test "subdomains_regex/1" do
|
||||||
test "common domains" do
|
test "common domains" do
|
||||||
regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"])
|
regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"])
|
||||||
|
|
||||||
assert regexes == [~r/^unsafe.tld$/, ~r/^unsafe2.tld$/]
|
assert regexes == [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i]
|
||||||
|
|
||||||
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||||
assert MRF.subdomain_match?(regexes, "unsafe2.tld")
|
assert MRF.subdomain_match?(regexes, "unsafe2.tld")
|
||||||
|
@ -24,7 +24,7 @@ test "common domains" do
|
||||||
test "wildcard domains with one subdomain" do
|
test "wildcard domains with one subdomain" do
|
||||||
regexes = MRF.subdomains_regex(["*.unsafe.tld"])
|
regexes = MRF.subdomains_regex(["*.unsafe.tld"])
|
||||||
|
|
||||||
assert regexes == [~r/^(.*\.)*unsafe.tld$/]
|
assert regexes == [~r/^(.*\.)*unsafe.tld$/i]
|
||||||
|
|
||||||
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||||
assert MRF.subdomain_match?(regexes, "sub.unsafe.tld")
|
assert MRF.subdomain_match?(regexes, "sub.unsafe.tld")
|
||||||
|
@ -35,12 +35,52 @@ test "wildcard domains with one subdomain" do
|
||||||
test "wildcard domains with two subdomains" do
|
test "wildcard domains with two subdomains" do
|
||||||
regexes = MRF.subdomains_regex(["*.unsafe.tld"])
|
regexes = MRF.subdomains_regex(["*.unsafe.tld"])
|
||||||
|
|
||||||
assert regexes == [~r/^(.*\.)*unsafe.tld$/]
|
assert regexes == [~r/^(.*\.)*unsafe.tld$/i]
|
||||||
|
|
||||||
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||||
assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld")
|
assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld")
|
||||||
refute MRF.subdomain_match?(regexes, "sub.anotherunsafe.tld")
|
refute MRF.subdomain_match?(regexes, "sub.anotherunsafe.tld")
|
||||||
refute MRF.subdomain_match?(regexes, "sub.unsafe.tldanother")
|
refute MRF.subdomain_match?(regexes, "sub.unsafe.tldanother")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "matches are case-insensitive" do
|
||||||
|
regexes = MRF.subdomains_regex(["UnSafe.TLD", "UnSAFE2.Tld"])
|
||||||
|
|
||||||
|
assert regexes == [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i]
|
||||||
|
|
||||||
|
assert MRF.subdomain_match?(regexes, "UNSAFE.TLD")
|
||||||
|
assert MRF.subdomain_match?(regexes, "UNSAFE2.TLD")
|
||||||
|
assert MRF.subdomain_match?(regexes, "unsafe.tld")
|
||||||
|
assert MRF.subdomain_match?(regexes, "unsafe2.tld")
|
||||||
|
|
||||||
|
refute MRF.subdomain_match?(regexes, "EXAMPLE.COM")
|
||||||
|
refute MRF.subdomain_match?(regexes, "example.com")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "describe/0" do
|
||||||
|
test "it works as expected with noop policy" do
|
||||||
|
expected = %{
|
||||||
|
mrf_policies: ["NoOpPolicy"],
|
||||||
|
exclusions: false
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, ^expected} = MRF.describe()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works as expected with mock policy" do
|
||||||
|
config = Pleroma.Config.get([:instance, :rewrite_policy])
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], [MRFModuleMock])
|
||||||
|
|
||||||
|
expected = %{
|
||||||
|
mrf_policies: ["MRFModuleMock"],
|
||||||
|
mrf_module_mock: "some config data",
|
||||||
|
exclusions: false
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, ^expected} = MRF.describe()
|
||||||
|
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], config)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
123
test/web/activity_pub/mrf/vocabulary_policy_test.exs
Normal file
123
test/web/activity_pub/mrf/vocabulary_policy_test.exs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Web.ActivityPub.MRF.VocabularyPolicy
|
||||||
|
|
||||||
|
describe "accept" do
|
||||||
|
test "it accepts based on parent activity type" do
|
||||||
|
config = Pleroma.Config.get([:mrf_vocabulary, :accept])
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Like"])
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"type" => "Like",
|
||||||
|
"object" => "whatever"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, ^message} = VocabularyPolicy.filter(message)
|
||||||
|
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], config)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it accepts based on child object type" do
|
||||||
|
config = Pleroma.Config.get([:mrf_vocabulary, :accept])
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"])
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"content" => "whatever"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, ^message} = VocabularyPolicy.filter(message)
|
||||||
|
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], config)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it does not accept disallowed child objects" do
|
||||||
|
config = Pleroma.Config.get([:mrf_vocabulary, :accept])
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"])
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Article",
|
||||||
|
"content" => "whatever"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{:reject, nil} = VocabularyPolicy.filter(message)
|
||||||
|
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], config)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it does not accept disallowed parent types" do
|
||||||
|
config = Pleroma.Config.get([:mrf_vocabulary, :accept])
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], ["Announce", "Note"])
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"content" => "whatever"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{:reject, nil} = VocabularyPolicy.filter(message)
|
||||||
|
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :accept], config)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "reject" do
|
||||||
|
test "it rejects based on parent activity type" do
|
||||||
|
config = Pleroma.Config.get([:mrf_vocabulary, :reject])
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"])
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"type" => "Like",
|
||||||
|
"object" => "whatever"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:reject, nil} = VocabularyPolicy.filter(message)
|
||||||
|
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :reject], config)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it rejects based on child object type" do
|
||||||
|
config = Pleroma.Config.get([:mrf_vocabulary, :reject])
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :reject], ["Note"])
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"content" => "whatever"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{:reject, nil} = VocabularyPolicy.filter(message)
|
||||||
|
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :reject], config)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it passes through objects that aren't disallowed" do
|
||||||
|
config = Pleroma.Config.get([:mrf_vocabulary, :reject])
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"])
|
||||||
|
|
||||||
|
message = %{
|
||||||
|
"type" => "Announce",
|
||||||
|
"object" => "whatever"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, ^message} = VocabularyPolicy.filter(message)
|
||||||
|
|
||||||
|
Pleroma.Config.put([:mrf_vocabulary, :reject], config)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,11 +5,71 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.RelayTest do
|
defmodule Pleroma.Web.ActivityPub.RelayTest do
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
test "gets an actor for the relay" do
|
test "gets an actor for the relay" do
|
||||||
user = Relay.get_actor()
|
user = Relay.get_actor()
|
||||||
|
assert user.ap_id == "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||||
|
end
|
||||||
|
|
||||||
assert user.ap_id =~ "/relay"
|
describe "follow/1" do
|
||||||
|
test "returns errors when user not found" do
|
||||||
|
assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns activity" do
|
||||||
|
user = insert(:user)
|
||||||
|
service_actor = Relay.get_actor()
|
||||||
|
assert {:ok, %Activity{} = activity} = Relay.follow(user.ap_id)
|
||||||
|
assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||||
|
assert user.ap_id in activity.recipients
|
||||||
|
assert activity.data["type"] == "Follow"
|
||||||
|
assert activity.data["actor"] == service_actor.ap_id
|
||||||
|
assert activity.data["object"] == user.ap_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "unfollow/1" do
|
||||||
|
test "returns errors when user not found" do
|
||||||
|
assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns activity" do
|
||||||
|
user = insert(:user)
|
||||||
|
service_actor = Relay.get_actor()
|
||||||
|
ActivityPub.follow(service_actor, user)
|
||||||
|
assert {:ok, %Activity{} = activity} = Relay.unfollow(user.ap_id)
|
||||||
|
assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||||
|
assert user.ap_id in activity.recipients
|
||||||
|
assert activity.data["type"] == "Undo"
|
||||||
|
assert activity.data["actor"] == service_actor.ap_id
|
||||||
|
assert activity.data["to"] == [user.ap_id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "publish/1" do
|
||||||
|
test "returns error when activity not `Create` type" do
|
||||||
|
activity = insert(:like_activity)
|
||||||
|
assert Relay.publish(activity) == {:error, "Not implemented"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when activity not public" do
|
||||||
|
activity = insert(:direct_note_activity)
|
||||||
|
assert Relay.publish(activity) == {:error, false}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns announce activity" do
|
||||||
|
service_actor = Relay.get_actor()
|
||||||
|
note = insert(:note_activity)
|
||||||
|
assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note)
|
||||||
|
assert activity.data["type"] == "Announce"
|
||||||
|
assert activity.data["actor"] == service_actor.ap_id
|
||||||
|
assert activity.data["object"] == obj.data["id"]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -451,6 +451,27 @@ test "it ensures that address fields become lists" do
|
||||||
assert !is_nil(data["cc"])
|
assert !is_nil(data["cc"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it strips internal likes" do
|
||||||
|
data =
|
||||||
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||||
|
|> Poison.decode!()
|
||||||
|
|
||||||
|
likes = %{
|
||||||
|
"first" =>
|
||||||
|
"http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1",
|
||||||
|
"id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes",
|
||||||
|
"totalItems" => 3,
|
||||||
|
"type" => "OrderedCollection"
|
||||||
|
}
|
||||||
|
|
||||||
|
object = Map.put(data["object"], "likes", likes)
|
||||||
|
data = Map.put(data, "object", object)
|
||||||
|
|
||||||
|
{:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
|
refute Map.has_key?(object.data, "likes")
|
||||||
|
end
|
||||||
|
|
||||||
test "it works for incoming update activities" do
|
test "it works for incoming update activities" do
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
|
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
|
||||||
|
|
||||||
|
@ -1063,14 +1084,7 @@ test "it strips internal fields of article" do
|
||||||
assert is_nil(modified["object"]["announcements"])
|
assert is_nil(modified["object"]["announcements"])
|
||||||
assert is_nil(modified["object"]["announcement_count"])
|
assert is_nil(modified["object"]["announcement_count"])
|
||||||
assert is_nil(modified["object"]["context_id"])
|
assert is_nil(modified["object"]["context_id"])
|
||||||
end
|
assert is_nil(modified["object"]["likes"])
|
||||||
|
|
||||||
test "it adds like collection to object" do
|
|
||||||
activity = insert(:note_activity)
|
|
||||||
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
|
|
||||||
|
|
||||||
assert modified["object"]["likes"]["type"] == "OrderedCollection"
|
|
||||||
assert modified["object"]["likes"]["totalItems"] == 0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "the directMessage flag is present" do
|
test "the directMessage flag is present" do
|
||||||
|
|
|
@ -356,4 +356,31 @@ test "sanitizes display names" do
|
||||||
result = AccountView.render("account.json", %{user: user})
|
result = AccountView.render("account.json", %{user: user})
|
||||||
refute result.display_name == "<marquee> username </marquee>"
|
refute result.display_name == "<marquee> username </marquee>"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "hiding follows/following" do
|
||||||
|
test "shows when follows/following are hidden and sets follower/following count to 0" do
|
||||||
|
user = insert(:user, info: %{hide_followers: true, hide_follows: true})
|
||||||
|
other_user = insert(:user)
|
||||||
|
{:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user)
|
||||||
|
{:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
|
||||||
|
|
||||||
|
assert %{
|
||||||
|
followers_count: 0,
|
||||||
|
following_count: 0,
|
||||||
|
pleroma: %{hide_follows: true, hide_followers: true}
|
||||||
|
} = AccountView.render("account.json", %{user: user})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows actual follower/following count to the account owner" do
|
||||||
|
user = insert(:user, info: %{hide_followers: true, hide_follows: true})
|
||||||
|
other_user = insert(:user)
|
||||||
|
{:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user)
|
||||||
|
{:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
|
||||||
|
|
||||||
|
assert %{
|
||||||
|
followers_count: 1,
|
||||||
|
following_count: 1
|
||||||
|
} = AccountView.render("account.json", %{user: user, for: user})
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|
||||||
|
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Config
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
@ -86,11 +87,11 @@ test "the public timeline", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "the public timeline when public is set to false", %{conn: conn} do
|
test "the public timeline when public is set to false", %{conn: conn} do
|
||||||
public = Pleroma.Config.get([:instance, :public])
|
public = Config.get([:instance, :public])
|
||||||
Pleroma.Config.put([:instance, :public], false)
|
Config.put([:instance, :public], false)
|
||||||
|
|
||||||
on_exit(fn ->
|
on_exit(fn ->
|
||||||
Pleroma.Config.put([:instance, :public], public)
|
Config.put([:instance, :public], public)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert conn
|
assert conn
|
||||||
|
@ -251,7 +252,7 @@ test "posting a fake status", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "posting a status with OGP link preview", %{conn: conn} do
|
test "posting a status with OGP link preview", %{conn: conn} do
|
||||||
Pleroma.Config.put([:rich_media, :enabled], true)
|
Config.put([:rich_media, :enabled], true)
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
@ -261,7 +262,7 @@ test "posting a status with OGP link preview", %{conn: conn} do
|
||||||
|
|
||||||
assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
|
assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
|
||||||
assert Activity.get_by_id(id)
|
assert Activity.get_by_id(id)
|
||||||
Pleroma.Config.put([:rich_media, :enabled], false)
|
Config.put([:rich_media, :enabled], false)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "posting a direct status", %{conn: conn} do
|
test "posting a direct status", %{conn: conn} do
|
||||||
|
@ -305,7 +306,7 @@ test "posting a poll", %{conn: conn} do
|
||||||
|
|
||||||
test "option limit is enforced", %{conn: conn} do
|
test "option limit is enforced", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
limit = Pleroma.Config.get([:instance, :poll_limits, :max_options])
|
limit = Config.get([:instance, :poll_limits, :max_options])
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
@ -321,7 +322,7 @@ test "option limit is enforced", %{conn: conn} do
|
||||||
|
|
||||||
test "option character limit is enforced", %{conn: conn} do
|
test "option character limit is enforced", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
limit = Pleroma.Config.get([:instance, :poll_limits, :max_option_chars])
|
limit = Config.get([:instance, :poll_limits, :max_option_chars])
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
@ -340,7 +341,7 @@ test "option character limit is enforced", %{conn: conn} do
|
||||||
|
|
||||||
test "minimal date limit is enforced", %{conn: conn} do
|
test "minimal date limit is enforced", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
limit = Pleroma.Config.get([:instance, :poll_limits, :min_expiration])
|
limit = Config.get([:instance, :poll_limits, :min_expiration])
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
@ -359,7 +360,7 @@ test "minimal date limit is enforced", %{conn: conn} do
|
||||||
|
|
||||||
test "maximum date limit is enforced", %{conn: conn} do
|
test "maximum date limit is enforced", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
limit = Pleroma.Config.get([:instance, :poll_limits, :max_expiration])
|
limit = Config.get([:instance, :poll_limits, :max_expiration])
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|
@ -1634,12 +1635,12 @@ test "returns the relationships for the current user", %{conn: conn} do
|
||||||
|
|
||||||
describe "media upload" do
|
describe "media upload" do
|
||||||
setup do
|
setup do
|
||||||
upload_config = Pleroma.Config.get([Pleroma.Upload])
|
upload_config = Config.get([Pleroma.Upload])
|
||||||
proxy_config = Pleroma.Config.get([:media_proxy])
|
proxy_config = Config.get([:media_proxy])
|
||||||
|
|
||||||
on_exit(fn ->
|
on_exit(fn ->
|
||||||
Pleroma.Config.put([Pleroma.Upload], upload_config)
|
Config.put([Pleroma.Upload], upload_config)
|
||||||
Pleroma.Config.put([:media_proxy], proxy_config)
|
Config.put([:media_proxy], proxy_config)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
@ -2582,7 +2583,7 @@ test "get instance information", %{conn: conn} do
|
||||||
conn = get(conn, "/api/v1/instance")
|
conn = get(conn, "/api/v1/instance")
|
||||||
assert result = json_response(conn, 200)
|
assert result = json_response(conn, 200)
|
||||||
|
|
||||||
email = Pleroma.Config.get([:instance, :email])
|
email = Config.get([:instance, :email])
|
||||||
# Note: not checking for "max_toot_chars" since it's optional
|
# Note: not checking for "max_toot_chars" since it's optional
|
||||||
assert %{
|
assert %{
|
||||||
"uri" => _,
|
"uri" => _,
|
||||||
|
@ -2667,7 +2668,7 @@ test "put settings", %{conn: conn} do
|
||||||
|
|
||||||
describe "pinned statuses" do
|
describe "pinned statuses" do
|
||||||
setup do
|
setup do
|
||||||
Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
|
Config.put([:instance, :max_pinned_statuses], 1)
|
||||||
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
{:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
|
||||||
|
@ -2767,10 +2768,10 @@ test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
|
||||||
|
|
||||||
describe "cards" do
|
describe "cards" do
|
||||||
setup do
|
setup do
|
||||||
Pleroma.Config.put([:rich_media, :enabled], true)
|
Config.put([:rich_media, :enabled], true)
|
||||||
|
|
||||||
on_exit(fn ->
|
on_exit(fn ->
|
||||||
Pleroma.Config.put([:rich_media, :enabled], false)
|
Config.put([:rich_media, :enabled], false)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
@ -2902,8 +2903,10 @@ test "bookmarks" do
|
||||||
|
|
||||||
describe "conversation muting" do
|
describe "conversation muting" do
|
||||||
setup do
|
setup do
|
||||||
|
post_user = insert(:user)
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
{:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
|
|
||||||
|
{:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"})
|
||||||
|
|
||||||
[user: user, activity: activity]
|
[user: user, activity: activity]
|
||||||
end
|
end
|
||||||
|
@ -2996,7 +2999,7 @@ test "comment must be up to the size specified in the config", %{
|
||||||
reporter: reporter,
|
reporter: reporter,
|
||||||
target_user: target_user
|
target_user: target_user
|
||||||
} do
|
} do
|
||||||
max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
|
max_size = Config.get([:instance, :max_report_comment_size], 1000)
|
||||||
comment = String.pad_trailing("a", max_size + 1, "a")
|
comment = String.pad_trailing("a", max_size + 1, "a")
|
||||||
|
|
||||||
error = %{"error" => "Comment must be up to #{max_size} characters"}
|
error = %{"error" => "Comment must be up to #{max_size} characters"}
|
||||||
|
@ -3125,15 +3128,15 @@ test "redirects not logged-in users to the login page on private instances", %{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
path: path
|
path: path
|
||||||
} do
|
} do
|
||||||
is_public = Pleroma.Config.get([:instance, :public])
|
is_public = Config.get([:instance, :public])
|
||||||
Pleroma.Config.put([:instance, :public], false)
|
Config.put([:instance, :public], false)
|
||||||
|
|
||||||
conn = get(conn, path)
|
conn = get(conn, path)
|
||||||
|
|
||||||
assert conn.status == 302
|
assert conn.status == 302
|
||||||
assert redirected_to(conn) == "/web/login"
|
assert redirected_to(conn) == "/web/login"
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :public], is_public)
|
Config.put([:instance, :public], is_public)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
|
test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
|
||||||
|
@ -3876,8 +3879,8 @@ test "it sends an email to user", %{user: user} do
|
||||||
token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
|
token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
|
||||||
|
|
||||||
email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
|
email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
|
||||||
notify_email = Pleroma.Config.get([:instance, :notify_email])
|
notify_email = Config.get([:instance, :notify_email])
|
||||||
instance_name = Pleroma.Config.get([:instance, :name])
|
instance_name = Config.get([:instance, :name])
|
||||||
|
|
||||||
assert_email_sent(
|
assert_email_sent(
|
||||||
from: {instance_name, notify_email},
|
from: {instance_name, notify_email},
|
||||||
|
@ -3909,11 +3912,11 @@ test "it returns 400 when user is not local", %{conn: conn, user: user} do
|
||||||
|
|
||||||
describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
|
describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
|
||||||
setup do
|
setup do
|
||||||
setting = Pleroma.Config.get([:instance, :account_activation_required])
|
setting = Config.get([:instance, :account_activation_required])
|
||||||
|
|
||||||
unless setting do
|
unless setting do
|
||||||
Pleroma.Config.put([:instance, :account_activation_required], true)
|
Config.put([:instance, :account_activation_required], true)
|
||||||
on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
|
on_exit(fn -> Config.put([:instance, :account_activation_required], setting) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
@ -3939,8 +3942,8 @@ test "resend account confirmation email", %{conn: conn, user: user} do
|
||||||
ObanHelpers.perform_all()
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
|
email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
|
||||||
notify_email = Pleroma.Config.get([:instance, :notify_email])
|
notify_email = Config.get([:instance, :notify_email])
|
||||||
instance_name = Pleroma.Config.get([:instance, :name])
|
instance_name = Config.get([:instance, :name])
|
||||||
|
|
||||||
assert_email_sent(
|
assert_email_sent(
|
||||||
from: {instance_name, notify_email},
|
from: {instance_name, notify_email},
|
||||||
|
@ -3949,4 +3952,84 @@ test "resend account confirmation email", %{conn: conn, user: user} do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "GET /api/v1/suggestions" do
|
||||||
|
setup do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
config = Config.get(:suggestions)
|
||||||
|
on_exit(fn -> Config.put(:suggestions, config) end)
|
||||||
|
|
||||||
|
host = Config.get([Pleroma.Web.Endpoint, :url, :host])
|
||||||
|
url500 = "http://test500?#{host}&#{user.nickname}"
|
||||||
|
url200 = "http://test200?#{host}&#{user.nickname}"
|
||||||
|
|
||||||
|
mock(fn
|
||||||
|
%{method: :get, url: ^url500} ->
|
||||||
|
%Tesla.Env{status: 500, body: "bad request"}
|
||||||
|
|
||||||
|
%{method: :get, url: ^url200} ->
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
|
||||||
|
other_user.ap_id
|
||||||
|
}","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
[user: user, other_user: other_user]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns empty result when suggestions disabled", %{conn: conn, user: user} do
|
||||||
|
Config.put([:suggestions, :enabled], false)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/suggestions")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert res == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error", %{conn: conn, user: user} do
|
||||||
|
Config.put([:suggestions, :enabled], true)
|
||||||
|
Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/suggestions")
|
||||||
|
|> json_response(500)
|
||||||
|
|
||||||
|
assert res == "Something went wrong"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do
|
||||||
|
Config.put([:suggestions, :enabled], true)
|
||||||
|
Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/suggestions")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert res == [
|
||||||
|
%{
|
||||||
|
"acct" => "yj455",
|
||||||
|
"avatar" => "https://social.heldscal.la/avatar/201.jpeg",
|
||||||
|
"avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
|
||||||
|
"id" => 0
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"acct" => other_user.ap_id,
|
||||||
|
"avatar" => "https://social.heldscal.la/avatar/202.jpeg",
|
||||||
|
"avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
|
||||||
|
"id" => other_user.id
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
103
test/web/mastodon_api/mastodon_api_test.exs
Normal file
103
test/web/mastodon_api/mastodon_api_test.exs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do
|
||||||
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.ScheduledActivity
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||||
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
describe "follow/3" do
|
||||||
|
test "returns error when user deactivated" do
|
||||||
|
follower = insert(:user)
|
||||||
|
user = insert(:user, local: true, info: %{deactivated: true})
|
||||||
|
{:error, error} = MastodonAPI.follow(follower, user)
|
||||||
|
assert error == "Could not follow user: You are deactivated."
|
||||||
|
end
|
||||||
|
|
||||||
|
test "following for user" do
|
||||||
|
follower = insert(:user)
|
||||||
|
user = insert(:user)
|
||||||
|
{:ok, follower} = MastodonAPI.follow(follower, user)
|
||||||
|
assert User.following?(follower, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns ok if user already followed" do
|
||||||
|
follower = insert(:user)
|
||||||
|
user = insert(:user)
|
||||||
|
{:ok, follower} = User.follow(follower, user)
|
||||||
|
{:ok, follower} = MastodonAPI.follow(follower, refresh_record(user))
|
||||||
|
assert User.following?(follower, user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "get_followers/2" do
|
||||||
|
test "returns user followers" do
|
||||||
|
follower1_user = insert(:user)
|
||||||
|
follower2_user = insert(:user)
|
||||||
|
user = insert(:user)
|
||||||
|
{:ok, _follower1_user} = User.follow(follower1_user, user)
|
||||||
|
{:ok, follower2_user} = User.follow(follower2_user, user)
|
||||||
|
|
||||||
|
assert MastodonAPI.get_followers(user, %{"limit" => 1}) == [follower2_user]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "get_friends/2" do
|
||||||
|
test "returns user friends" do
|
||||||
|
user = insert(:user)
|
||||||
|
followed_one = insert(:user)
|
||||||
|
followed_two = insert(:user)
|
||||||
|
followed_three = insert(:user)
|
||||||
|
|
||||||
|
{:ok, user} = User.follow(user, followed_one)
|
||||||
|
{:ok, user} = User.follow(user, followed_two)
|
||||||
|
{:ok, user} = User.follow(user, followed_three)
|
||||||
|
res = MastodonAPI.get_friends(user)
|
||||||
|
|
||||||
|
assert length(res) == 3
|
||||||
|
assert Enum.member?(res, refresh_record(followed_three))
|
||||||
|
assert Enum.member?(res, refresh_record(followed_two))
|
||||||
|
assert Enum.member?(res, refresh_record(followed_one))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "get_notifications/2" do
|
||||||
|
test "returns notifications for user" do
|
||||||
|
user = insert(:user)
|
||||||
|
subscriber = insert(:user)
|
||||||
|
|
||||||
|
User.subscribe(subscriber, user)
|
||||||
|
|
||||||
|
{:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"})
|
||||||
|
{:ok, status1} = TwitterAPI.create_status(user, %{"status" => "Magi"})
|
||||||
|
{:ok, [notification]} = Notification.create_notifications(status)
|
||||||
|
{:ok, [notification1]} = Notification.create_notifications(status1)
|
||||||
|
res = MastodonAPI.get_notifications(subscriber)
|
||||||
|
|
||||||
|
assert Enum.member?(Enum.map(res, & &1.id), notification.id)
|
||||||
|
assert Enum.member?(Enum.map(res, & &1.id), notification1.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "get_scheduled_activities/2" do
|
||||||
|
test "returns user scheduled activities" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
today =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> NaiveDateTime.add(:timer.minutes(6), :millisecond)
|
||||||
|
|> NaiveDateTime.to_iso8601()
|
||||||
|
|
||||||
|
attrs = %{params: %{}, scheduled_at: today}
|
||||||
|
{:ok, schedule} = ScheduledActivity.create(user, attrs)
|
||||||
|
assert MastodonAPI.get_scheduled_activities(user) == [schedule]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -85,6 +85,9 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it shows MRF transparency data if enabled", %{conn: conn} do
|
test "it shows MRF transparency data if enabled", %{conn: conn} do
|
||||||
|
config = Pleroma.Config.get([:instance, :rewrite_policy])
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||||
|
|
||||||
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
||||||
|
|
||||||
|
@ -98,11 +101,15 @@ test "it shows MRF transparency data if enabled", %{conn: conn} do
|
||||||
|
|
||||||
assert response["metadata"]["federation"]["mrf_simple"] == simple_config
|
assert response["metadata"]["federation"]["mrf_simple"] == simple_config
|
||||||
|
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], config)
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
||||||
Pleroma.Config.put(:mrf_simple, %{})
|
Pleroma.Config.put(:mrf_simple, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
|
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
|
||||||
|
config = Pleroma.Config.get([:instance, :rewrite_policy])
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||||
|
|
||||||
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
||||||
|
|
||||||
|
@ -122,6 +129,7 @@ test "it performs exclusions from MRF transparency data if configured", %{conn:
|
||||||
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
|
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
|
||||||
assert response["metadata"]["federation"]["exclusions"] == true
|
assert response["metadata"]["federation"]["exclusions"] == true
|
||||||
|
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], config)
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency_exclusions], exclusions)
|
Pleroma.Config.put([:instance, :mrf_transparency_exclusions], exclusions)
|
||||||
Pleroma.Config.put(:mrf_simple, %{})
|
Pleroma.Config.put(:mrf_simple, %{})
|
||||||
|
|
Loading…
Reference in a new issue