Merge remote-tracking branch 'upstream/develop' into restrict-domain
This commit is contained in:
commit
cc196e2cd5
148 changed files with 3519 additions and 636 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -27,6 +27,8 @@ erl_crash.dump
|
|||
# variables.
|
||||
/config/*.secret.exs
|
||||
/config/generated_config.exs
|
||||
/config/*.env
|
||||
|
||||
|
||||
# Database setup file, some may forget to delete it
|
||||
/config/setup_db.psql
|
||||
|
|
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -7,12 +7,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
### Changed
|
||||
- **Breaking:** Elixir >=1.9 is now required (was >= 1.8)
|
||||
- **Breaking:** Configuration: `:auto_linker, :opts` moved to `:pleroma, Pleroma.Formatter`. Old config namespace is deprecated.
|
||||
- In Conversations, return only direct messages as `last_status`
|
||||
- Using the `only_media` filter on timelines will now exclude reblog media
|
||||
- MFR policy to set global expiration for all local Create activities
|
||||
- OGP rich media parser merged with TwitterCard
|
||||
- Configuration: `:instance, rewrite_policy` moved to `:mrf, policies`, `:instance, :mrf_transparency` moved to `:mrf, :transparency`, `:instance, :mrf_transparency_exclusions` moved to `:mrf, :transparency_exclusions`. Old config namespace is deprecated.
|
||||
- Configuration: `:media_proxy, whitelist` format changed to host with scheme (e.g. `http://example.com` instead of `example.com`). Domain format is deprecated.
|
||||
- **Breaking:** Configuration: `:instance, welcome_user_nickname` moved to `:welcome, :direct_message, :sender_nickname`, `:instance, :welcome_message` moved to `:welcome, :direct_message, :message`. Old config namespace is deprecated.
|
||||
|
||||
<details>
|
||||
<summary>API Changes</summary>
|
||||
|
@ -30,6 +32,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- **Breaking:** Notification Settings API option for hiding push notification
|
||||
contents has been renamed to `hide_notification_contents`
|
||||
- Mastodon API: Added `pleroma.metadata.post_formats` to /api/v1/instance
|
||||
- Mastodon API (legacy): Allow query parameters for `/api/v1/domain_blocks`, e.g. `/api/v1/domain_blocks?domain=badposters.zone`
|
||||
- Pleroma API: `/api/pleroma/captcha` responses now include `seconds_valid` with an integer value.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
@ -45,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
### Added
|
||||
|
||||
- Configuration: Added a blacklist for email servers.
|
||||
- Chats: Added `accepts_chat_messages` field to user, exposed in APIs and federation.
|
||||
- Chats: Added support for federated chats. For details, see the docs.
|
||||
- ActivityPub: Added support for existing AP ids for instances migrated from Mastodon.
|
||||
|
@ -64,10 +69,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- Support pagination in emoji packs API (for packs and for files in pack)
|
||||
- Support for viewing instances favicons next to posts and accounts
|
||||
- Added Pleroma.Upload.Filter.Exiftool as an alternate EXIF stripping mechanism targeting GPS/location metadata.
|
||||
- "By approval" registrations mode.
|
||||
- Configuration: Added `:welcome` settings for the welcome message to newly registered users. You can send a welcome message as a direct message, chat or email.
|
||||
- Ability to hide favourites and emoji reactions in the API with `[:instance, :show_reactions]` config.
|
||||
|
||||
<details>
|
||||
<summary>API Changes</summary>
|
||||
- Mastodon API: Add pleroma.parents_visible field to statuses.
|
||||
|
||||
- Mastodon API: Add pleroma.parent_visible field to statuses.
|
||||
- Mastodon API: Extended `/api/v1/instance`.
|
||||
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
|
||||
- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
|
||||
|
@ -92,6 +101,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- Admin API: fix `GET /api/pleroma/admin/users/:nickname/credentials` returning 404 when getting the credentials of a remote user while `:instance, :limit_to_local_content` is set to `:unauthenticated`
|
||||
- Fix CSP policy generation to include remote Captcha services
|
||||
- Fix edge case where MediaProxy truncates media, usually caused when Caddy is serving content for the other Federated instance.
|
||||
- Emoji Packs could not be listed when instance was set to `public: false`
|
||||
|
||||
## [Unreleased (patch)]
|
||||
|
||||
|
@ -121,6 +131,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- Follow request notifications
|
||||
<details>
|
||||
<summary>API Changes</summary>
|
||||
|
||||
- Admin API: `GET /api/pleroma/admin/need_reboot`.
|
||||
</details>
|
||||
|
||||
|
@ -188,6 +199,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- **Breaking**: Using third party engines for user recommendation
|
||||
<details>
|
||||
<summary>API Changes</summary>
|
||||
|
||||
- **Breaking**: AdminAPI: migrate_from_db endpoint
|
||||
</details>
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
"application/ld+json" => ["activity+json"]
|
||||
}
|
||||
|
||||
config :tesla, adapter: Tesla.Adapter.Gun
|
||||
config :tesla, adapter: Tesla.Adapter.Hackney
|
||||
|
||||
# Configures http settings, upstream proxy etc.
|
||||
config :pleroma, :http,
|
||||
|
@ -205,6 +205,7 @@
|
|||
registrations_open: true,
|
||||
invites_enabled: false,
|
||||
account_activation_required: false,
|
||||
account_approval_required: false,
|
||||
federating: true,
|
||||
federation_incoming_replies_max_depth: 100,
|
||||
federation_reachability_timeout_days: 7,
|
||||
|
@ -225,8 +226,6 @@
|
|||
autofollowed_nicknames: [],
|
||||
max_pinned_statuses: 1,
|
||||
attachment_links: false,
|
||||
welcome_user_nickname: nil,
|
||||
welcome_message: nil,
|
||||
max_report_comment_size: 1000,
|
||||
safe_dm_mentions: false,
|
||||
healthcheck: false,
|
||||
|
@ -239,6 +238,7 @@
|
|||
max_remote_account_fields: 20,
|
||||
account_field_name_length: 512,
|
||||
account_field_value_length: 2048,
|
||||
registration_reason_length: 500,
|
||||
external_user_synchronization: true,
|
||||
extended_nickname_format: true,
|
||||
cleanup_attachments: false,
|
||||
|
@ -252,6 +252,26 @@
|
|||
number: 5,
|
||||
length: 16
|
||||
]
|
||||
],
|
||||
show_reactions: true
|
||||
|
||||
config :pleroma, :welcome,
|
||||
direct_message: [
|
||||
enabled: false,
|
||||
sender_nickname: nil,
|
||||
message: nil
|
||||
],
|
||||
chat_message: [
|
||||
enabled: false,
|
||||
sender_nickname: nil,
|
||||
message: nil
|
||||
],
|
||||
email: [
|
||||
enabled: false,
|
||||
sender: nil,
|
||||
subject: "Welcome to <%= instance_name %>",
|
||||
html: "Welcome to <%= instance_name %>",
|
||||
text: "Welcome to <%= instance_name %>"
|
||||
]
|
||||
|
||||
config :pleroma, :feed,
|
||||
|
@ -359,6 +379,7 @@
|
|||
federated_timeline_removal: [],
|
||||
report_removal: [],
|
||||
reject: [],
|
||||
followers_only: [],
|
||||
accept: [],
|
||||
avatar_removal: [],
|
||||
banner_removal: [],
|
||||
|
@ -377,8 +398,9 @@
|
|||
accept: [],
|
||||
reject: []
|
||||
|
||||
# threshold of 7 days
|
||||
config :pleroma, :mrf_object_age,
|
||||
threshold: 172_800,
|
||||
threshold: 604_800,
|
||||
actions: [:delist, :strip_followers]
|
||||
|
||||
config :pleroma, :rich_media,
|
||||
|
@ -494,7 +516,8 @@
|
|||
"user_exists",
|
||||
"users",
|
||||
"web"
|
||||
]
|
||||
],
|
||||
email_blacklist: []
|
||||
|
||||
config :pleroma, Oban,
|
||||
repo: Pleroma.Repo,
|
||||
|
@ -527,16 +550,14 @@
|
|||
federator_outgoing: 5
|
||||
]
|
||||
|
||||
config :auto_linker,
|
||||
opts: [
|
||||
extra: true,
|
||||
# TODO: Set to :no_scheme when it works properly
|
||||
validate_tld: true,
|
||||
class: false,
|
||||
strip_prefix: false,
|
||||
new_window: false,
|
||||
rel: "ugc"
|
||||
]
|
||||
config :pleroma, Pleroma.Formatter,
|
||||
class: false,
|
||||
rel: "ugc",
|
||||
new_window: false,
|
||||
truncate: false,
|
||||
strip_prefix: false,
|
||||
extra: true,
|
||||
validate_tld: :no_scheme
|
||||
|
||||
config :pleroma, :ldap,
|
||||
enabled: System.get_env("LDAP_ENABLED") == "true",
|
||||
|
@ -635,6 +656,16 @@
|
|||
|
||||
config :pleroma, :static_fe, enabled: false
|
||||
|
||||
# Example of frontend configuration
|
||||
# This example will make us serve the primary frontend from the
|
||||
# frontends directory within your `:pleroma, :instance, static_dir`.
|
||||
# e.g., instance/static/frontends/pleroma/develop/
|
||||
#
|
||||
# With no frontend configuration, the bundled files from the `static` directory will
|
||||
# be used.
|
||||
#
|
||||
# config :pleroma, :frontends, primary: %{"name" => "pleroma", "ref" => "develop"}
|
||||
|
||||
config :pleroma, :web_cache_ttl,
|
||||
activity_pub: nil,
|
||||
activity_pub_question: 30_000
|
||||
|
@ -696,7 +727,7 @@
|
|||
config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: false
|
||||
|
||||
config :pleroma, :mrf,
|
||||
policies: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,
|
||||
policies: Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy,
|
||||
transparency: true,
|
||||
transparency_exclusions: []
|
||||
|
||||
|
|
|
@ -661,6 +661,11 @@
|
|||
type: :boolean,
|
||||
description: "Require users to confirm their emails before signing in"
|
||||
},
|
||||
%{
|
||||
key: :account_approval_required,
|
||||
type: :boolean,
|
||||
description: "Require users to be manually approved by an admin before signing in"
|
||||
},
|
||||
%{
|
||||
key: :federating,
|
||||
type: :boolean,
|
||||
|
@ -778,23 +783,6 @@
|
|||
type: :boolean,
|
||||
description: "Enable to automatically add attachment link text to statuses"
|
||||
},
|
||||
%{
|
||||
key: :welcome_message,
|
||||
type: :string,
|
||||
description:
|
||||
"A message that will be sent to a newly registered users as a direct message",
|
||||
suggestions: [
|
||||
"Hi, @username! Welcome on board!"
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :welcome_user_nickname,
|
||||
type: :string,
|
||||
description: "The nickname of the local user that sends the welcome message",
|
||||
suggestions: [
|
||||
"lain"
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :max_report_comment_size,
|
||||
type: :integer,
|
||||
|
@ -891,6 +879,14 @@
|
|||
2048
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :registration_reason_length,
|
||||
type: :integer,
|
||||
description: "Maximum registration reason length. Default: 500.",
|
||||
suggestions: [
|
||||
500
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :external_user_synchronization,
|
||||
type: :boolean,
|
||||
|
@ -959,6 +955,118 @@
|
|||
description:
|
||||
"The instance thumbnail can be any image that represents your instance and is used by some apps or services when they display information about your instance.",
|
||||
suggestions: ["/instance/thumbnail.jpeg"]
|
||||
},
|
||||
%{
|
||||
key: :show_reactions,
|
||||
type: :boolean,
|
||||
description: "Let favourites and emoji reactions be viewed through the API."
|
||||
}
|
||||
]
|
||||
},
|
||||
%{
|
||||
group: :welcome,
|
||||
type: :group,
|
||||
description: "Welcome messages settings",
|
||||
children: [
|
||||
%{
|
||||
group: :direct_message,
|
||||
type: :group,
|
||||
descpiption: "Direct message settings",
|
||||
children: [
|
||||
%{
|
||||
key: :enabled,
|
||||
type: :boolean,
|
||||
description: "Enables sends direct message for new user after registration"
|
||||
},
|
||||
%{
|
||||
key: :message,
|
||||
type: :string,
|
||||
description:
|
||||
"A message that will be sent to a newly registered users as a direct message",
|
||||
suggestions: [
|
||||
"Hi, @username! Welcome on board!"
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :sender_nickname,
|
||||
type: :string,
|
||||
description: "The nickname of the local user that sends the welcome message",
|
||||
suggestions: [
|
||||
"lain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
%{
|
||||
group: :chat_message,
|
||||
type: :group,
|
||||
descpiption: "Chat message settings",
|
||||
children: [
|
||||
%{
|
||||
key: :enabled,
|
||||
type: :boolean,
|
||||
description: "Enables sends chat message for new user after registration"
|
||||
},
|
||||
%{
|
||||
key: :message,
|
||||
type: :string,
|
||||
description:
|
||||
"A message that will be sent to a newly registered users as a chat message",
|
||||
suggestions: [
|
||||
"Hello, welcome on board!"
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :sender_nickname,
|
||||
type: :string,
|
||||
description: "The nickname of the local user that sends the welcome message",
|
||||
suggestions: [
|
||||
"lain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
%{
|
||||
group: :email,
|
||||
type: :group,
|
||||
descpiption: "Email message settings",
|
||||
children: [
|
||||
%{
|
||||
key: :enabled,
|
||||
type: :boolean,
|
||||
description: "Enables sends direct message for new user after registration"
|
||||
},
|
||||
%{
|
||||
key: :sender,
|
||||
type: [:string, :tuple],
|
||||
description:
|
||||
"The email address or tuple with `{nickname, email}` that will use as sender to the welcome email.",
|
||||
suggestions: [
|
||||
{"Pleroma App", "welcome@pleroma.app"}
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :subject,
|
||||
type: :string,
|
||||
description:
|
||||
"The subject of welcome email. Can be use EEX template with `user` and `instance_name` variables.",
|
||||
suggestions: ["Welcome to <%= instance_name%>"]
|
||||
},
|
||||
%{
|
||||
key: :html,
|
||||
type: :string,
|
||||
description:
|
||||
"The html content of welcome email. Can be use EEX template with `user` and `instance_name` variables.",
|
||||
suggestions: ["<h1>Hello <%= user.name%>. Welcome to <%= instance_name%></h1>"]
|
||||
},
|
||||
%{
|
||||
key: :text,
|
||||
type: :string,
|
||||
description:
|
||||
"The text content of welcome email. Can be use EEX template with `user` and `instance_name` variables.",
|
||||
suggestions: ["Hello <%= user.name%>. \n Welcome to <%= instance_name%>\n"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1426,6 +1534,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_simple,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy",
|
||||
label: "MRF Simple",
|
||||
type: :group,
|
||||
description: "Simple ingress policies",
|
||||
|
@ -1462,6 +1571,12 @@
|
|||
description: "List of instances to only accept activities from (except deletes)",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :followers_only,
|
||||
type: {:list, :string},
|
||||
description: "Force posts from the given instances to be visible by followers only",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :report_removal,
|
||||
type: {:list, :string},
|
||||
|
@ -1492,6 +1607,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_activity_expiration,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy",
|
||||
label: "MRF Activity Expiration Policy",
|
||||
type: :group,
|
||||
description: "Adds automatic expiration to all local activities",
|
||||
|
@ -1508,6 +1624,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_subchain,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.SubchainPolicy",
|
||||
label: "MRF Subchain",
|
||||
type: :group,
|
||||
description:
|
||||
|
@ -1530,6 +1647,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_rejectnonpublic,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.RejectNonPublic",
|
||||
description: "RejectNonPublic drops posts with non-public visibility settings.",
|
||||
label: "MRF Reject Non Public",
|
||||
type: :group,
|
||||
|
@ -1551,6 +1669,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_hellthread,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.HellthreadPolicy",
|
||||
label: "MRF Hellthread",
|
||||
type: :group,
|
||||
description: "Block messages with excessive user mentions",
|
||||
|
@ -1576,6 +1695,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_keyword,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.KeywordPolicy",
|
||||
label: "MRF Keyword",
|
||||
type: :group,
|
||||
description: "Reject or Word-Replace messages with a keyword or regex",
|
||||
|
@ -1607,6 +1727,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_mention,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.MentionPolicy",
|
||||
label: "MRF Mention",
|
||||
type: :group,
|
||||
description: "Block messages which mention a specific user",
|
||||
|
@ -1623,6 +1744,7 @@
|
|||
group: :pleroma,
|
||||
key: :mrf_vocabulary,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.VocabularyPolicy",
|
||||
label: "MRF Vocabulary",
|
||||
type: :group,
|
||||
description: "Filter messages which belong to certain activity vocabularies",
|
||||
|
@ -1646,6 +1768,8 @@
|
|||
# %{
|
||||
# group: :pleroma,
|
||||
# key: :mrf_user_allowlist,
|
||||
# tab: :mrf,
|
||||
# related_policy: "Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy",
|
||||
# type: :map,
|
||||
# description:
|
||||
# "The keys in this section are the domain names that the policy should apply to." <>
|
||||
|
@ -2216,45 +2340,53 @@
|
|||
]
|
||||
},
|
||||
%{
|
||||
group: :auto_linker,
|
||||
key: :opts,
|
||||
group: :pleroma,
|
||||
key: Pleroma.Formatter,
|
||||
label: "Auto Linker",
|
||||
type: :group,
|
||||
description: "Configuration for the auto_linker library",
|
||||
description:
|
||||
"Configuration for Pleroma's link formatter which parses mentions, hashtags, and URLs.",
|
||||
children: [
|
||||
%{
|
||||
key: :class,
|
||||
type: [:string, false],
|
||||
type: [:string, :boolean],
|
||||
description: "Specify the class to be added to the generated link. Disable to clear.",
|
||||
suggestions: ["auto-linker", false]
|
||||
},
|
||||
%{
|
||||
key: :rel,
|
||||
type: [:string, false],
|
||||
type: [:string, :boolean],
|
||||
description: "Override the rel attribute. Disable to clear.",
|
||||
suggestions: ["ugc", "noopener noreferrer", false]
|
||||
},
|
||||
%{
|
||||
key: :new_window,
|
||||
type: :boolean,
|
||||
description: "Link URLs will open in new window/tab"
|
||||
description: "Link URLs will open in a new window/tab."
|
||||
},
|
||||
%{
|
||||
key: :truncate,
|
||||
type: [:integer, false],
|
||||
type: [:integer, :boolean],
|
||||
description:
|
||||
"Set to a number to truncate URLs longer then the number. Truncated URLs will end in `..`",
|
||||
"Set to a number to truncate URLs longer than the number. Truncated URLs will end in `...`",
|
||||
suggestions: [15, false]
|
||||
},
|
||||
%{
|
||||
key: :strip_prefix,
|
||||
type: :boolean,
|
||||
description: "Strip the scheme prefix"
|
||||
description: "Strip the scheme prefix."
|
||||
},
|
||||
%{
|
||||
key: :extra,
|
||||
type: :boolean,
|
||||
description: "Link URLs with rarely used schemes (magnet, ipfs, irc, etc.)"
|
||||
},
|
||||
%{
|
||||
key: :validate_tld,
|
||||
type: [:atom, :boolean],
|
||||
description:
|
||||
"Set to false to disable TLD validation for URLs/emails. Can be set to :no_scheme to validate TLDs only for URLs without a scheme (e.g `example.com` will be validated, but `http://example.loki` won't)",
|
||||
suggestions: [:no_scheme, true]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -2902,8 +3034,9 @@
|
|||
},
|
||||
%{
|
||||
group: :pleroma,
|
||||
tab: :mrf,
|
||||
key: :mrf_normalize_markup,
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.NormalizeMarkup",
|
||||
label: "MRF Normalize Markup",
|
||||
description: "MRF NormalizeMarkup settings. Scrub configured hypertext markup.",
|
||||
type: :group,
|
||||
|
@ -2923,6 +3056,7 @@
|
|||
%{
|
||||
key: :restricted_nicknames,
|
||||
type: {:list, :string},
|
||||
description: "List of nicknames users may not register with.",
|
||||
suggestions: [
|
||||
".well-known",
|
||||
"~",
|
||||
|
@ -2955,6 +3089,12 @@
|
|||
"users",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :email_blacklist,
|
||||
type: {:list, :string},
|
||||
description: "List of email domains users may not register with.",
|
||||
suggestions: ["mailinator.com", "maildrop.cc"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -3098,8 +3238,9 @@
|
|||
%{
|
||||
group: :pleroma,
|
||||
key: :mrf_object_age,
|
||||
label: "MRF Object Age",
|
||||
tab: :mrf,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy",
|
||||
label: "MRF Object Age",
|
||||
type: :group,
|
||||
description:
|
||||
"Rejects or delists posts based on their timestamp deviance from your server's clock.",
|
||||
|
@ -3400,5 +3541,30 @@
|
|||
suggestions: ["s3.eu-central-1.amazonaws.com"]
|
||||
}
|
||||
]
|
||||
},
|
||||
%{
|
||||
group: :pleroma,
|
||||
key: :frontends,
|
||||
type: :group,
|
||||
description: "Installed frontends management",
|
||||
children: [
|
||||
%{
|
||||
key: :primary,
|
||||
type: :map,
|
||||
description: "Primary frontend, the one that is served for all pages by default",
|
||||
children: [
|
||||
%{
|
||||
key: "name",
|
||||
type: :string,
|
||||
description: "Name of the installed primary frontend"
|
||||
},
|
||||
%{
|
||||
key: "ref",
|
||||
type: :string,
|
||||
description: "reference of the installed primary frontend to be used"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -118,6 +118,10 @@
|
|||
streaming_enabled: true,
|
||||
public_endpoint: nil
|
||||
|
||||
config :tzdata, :autoupdate, :disabled
|
||||
|
||||
config :pleroma, :mrf, policies: []
|
||||
|
||||
if File.exists?("./config/test.secret.exs") do
|
||||
import_config "test.secret.exs"
|
||||
else
|
||||
|
|
|
@ -19,6 +19,7 @@ Configuration options:
|
|||
- `local`: only local users
|
||||
- `external`: only external users
|
||||
- `active`: only active users
|
||||
- `need_approval`: only unapproved users
|
||||
- `deactivated`: only deactivated users
|
||||
- `is_admin`: users with admin role
|
||||
- `is_moderator`: users with moderator role
|
||||
|
@ -46,7 +47,10 @@ Configuration options:
|
|||
"local": bool,
|
||||
"tags": array,
|
||||
"avatar": string,
|
||||
"display_name": string
|
||||
"display_name": string,
|
||||
"confirmation_pending": bool,
|
||||
"approval_pending": bool,
|
||||
"registration_reason": string,
|
||||
},
|
||||
...
|
||||
]
|
||||
|
@ -242,6 +246,24 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
|||
}
|
||||
```
|
||||
|
||||
## `PATCH /api/pleroma/admin/users/approve`
|
||||
|
||||
### Approve user
|
||||
|
||||
- Params:
|
||||
- `nicknames`: nicknames array
|
||||
- Response:
|
||||
|
||||
```json
|
||||
{
|
||||
users: [
|
||||
{
|
||||
// user object
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## `GET /api/pleroma/admin/users/:nickname_or_id`
|
||||
|
||||
### Retrive the details of a user
|
||||
|
|
|
@ -50,7 +50,7 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
|
|||
* Authentication: not required
|
||||
* Params: none
|
||||
* Response: Provider specific JSON, the only guaranteed parameter is `type`
|
||||
* Example response: `{"type": "kocaptcha", "token": "whatever", "url": "https://captcha.kotobank.ch/endpoint"}`
|
||||
* Example response: `{"type": "kocaptcha", "token": "whatever", "url": "https://captcha.kotobank.ch/endpoint", "seconds_valid": 300}`
|
||||
|
||||
## `/api/pleroma/delete_account`
|
||||
### Delete an account
|
||||
|
|
9
docs/administration/CLI_tasks/release_environments.md
Normal file
9
docs/administration/CLI_tasks/release_environments.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Generate release environment file
|
||||
|
||||
```sh tab="OTP"
|
||||
./bin/pleroma_ctl release_env gen
|
||||
```
|
||||
|
||||
```sh tab="From Source"
|
||||
mix pleroma.release_env gen
|
||||
```
|
|
@ -75,6 +75,13 @@ Feel free to contact us to be added to this list!
|
|||
- Platform: Android, iOS
|
||||
- Features: No Streaming
|
||||
|
||||
### Indigenous
|
||||
- Homepage: <https://indigenous.realize.be/>
|
||||
- Source Code: <https://github.com/swentel/indigenous-android/>
|
||||
- Contact: [@realize.be@realize.be](@realize.be@realize.be)
|
||||
- Platforms: Android
|
||||
- Features: No Streaming
|
||||
|
||||
## Alternative Web Interfaces
|
||||
### Brutaldon
|
||||
- Homepage: <https://jfm.carcosa.net/projects/software/brutaldon/>
|
||||
|
|
|
@ -33,6 +33,7 @@ To add configuration to your config file, you can copy it from the base config.
|
|||
* `registrations_open`: Enable registrations for anyone, invitations can be enabled when false.
|
||||
* `invites_enabled`: Enable user invitations for admins (depends on `registrations_open: false`).
|
||||
* `account_activation_required`: Require users to confirm their emails before signing in.
|
||||
* `account_approval_required`: Require users to be manually approved by an admin before signing in.
|
||||
* `federating`: Enable federation with other instances.
|
||||
* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.
|
||||
* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
|
||||
|
@ -46,8 +47,6 @@ To add configuration to your config file, you can copy it from the base config.
|
|||
* `max_pinned_statuses`: The maximum number of pinned statuses. `0` will disable the feature.
|
||||
* `autofollowed_nicknames`: Set to nicknames of (local) users that every new user should automatically follow.
|
||||
* `attachment_links`: Set to true to enable automatically adding attachment link text to statuses.
|
||||
* `welcome_message`: A message that will be send to a newly registered users as a direct message.
|
||||
* `welcome_user_nickname`: The nickname of the local user that sends the welcome message.
|
||||
* `max_report_comment_size`: The maximum size of the report comment (Default: `1000`).
|
||||
* `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``.
|
||||
|
@ -60,8 +59,44 @@ To add configuration to your config file, you can copy it from the base config.
|
|||
* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `20`).
|
||||
* `account_field_name_length`: An account field name maximum length (default: `512`).
|
||||
* `account_field_value_length`: An account field value maximum length (default: `2048`).
|
||||
* `registration_reason_length`: Maximum registration reason length (default: `500`).
|
||||
* `external_user_synchronization`: Enabling following/followers counters synchronization for external users.
|
||||
* `cleanup_attachments`: Remove attachments along with statuses. Does not affect duplicate files and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances.
|
||||
* `show_reactions`: Let favourites and emoji reactions be viewed through the API (default: `true`).
|
||||
|
||||
## Welcome
|
||||
* `direct_message`: - welcome message sent as a direct message.
|
||||
* `enabled`: Enables the send a direct message to a newly registered user. Defaults to `false`.
|
||||
* `sender_nickname`: The nickname of the local user that sends the welcome message.
|
||||
* `message`: A message that will be send to a newly registered users as a direct message.
|
||||
* `chat_message`: - welcome message sent as a chat message.
|
||||
* `enabled`: Enables the send a chat message to a newly registered user. Defaults to `false`.
|
||||
* `sender_nickname`: The nickname of the local user that sends the welcome message.
|
||||
* `message`: A message that will be send to a newly registered users as a chat message.
|
||||
* `email`: - welcome message sent as a email.
|
||||
* `enabled`: Enables the send a welcome email to a newly registered user. Defaults to `false`.
|
||||
* `sender`: The email address or tuple with `{nickname, email}` that will use as sender to the welcome email.
|
||||
* `subject`: A subject of welcome email.
|
||||
* `html`: A html that will be send to a newly registered users as a email.
|
||||
* `text`: A text that will be send to a newly registered users as a email.
|
||||
|
||||
Example:
|
||||
|
||||
```elixir
|
||||
config :pleroma, :welcome,
|
||||
direct_message: [
|
||||
enabled: true,
|
||||
sender_nickname: "lain",
|
||||
message: "Hi, @username! Welcome on board!"
|
||||
],
|
||||
email: [
|
||||
enabled: true,
|
||||
sender: {"Pleroma App", "welcome@pleroma.app"},
|
||||
subject: "Welcome to <%= instance_name %>",
|
||||
html: "Welcome to <%= instance_name %>",
|
||||
text: "Welcome to <%= instance_name %>"
|
||||
]
|
||||
```
|
||||
|
||||
## Message rewrite facility
|
||||
|
||||
|
@ -94,6 +129,7 @@ To add configuration to your config file, you can copy it from the base config.
|
|||
* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline.
|
||||
* `reject`: List of instances to reject any activities from.
|
||||
* `accept`: List of instances to accept any activities from.
|
||||
* `followers_only`: List of instances to decrease post visibility to only the followers, including for DM mentions.
|
||||
* `report_removal`: List of instances to reject reports from.
|
||||
* `avatar_removal`: List of instances to strip avatars from.
|
||||
* `banner_removal`: List of instances to strip banners from.
|
||||
|
@ -171,6 +207,11 @@ config :pleroma, :mrf_user_allowlist, %{
|
|||
* `sign_object_fetches`: Sign object fetches with HTTP signatures
|
||||
* `authorized_fetch_mode`: Require HTTP signatures for AP fetches
|
||||
|
||||
## Pleroma.User
|
||||
|
||||
* `restricted_nicknames`: List of nicknames users may not register with.
|
||||
* `email_blacklist`: List of email domains users may not register with.
|
||||
|
||||
## Pleroma.ScheduledActivity
|
||||
|
||||
* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`)
|
||||
|
@ -934,30 +975,29 @@ Configure OAuth 2 provider capabilities:
|
|||
### :uri_schemes
|
||||
* `valid_schemes`: List of the scheme part that is considered valid to be an URL.
|
||||
|
||||
### :auto_linker
|
||||
### Pleroma.Formatter
|
||||
|
||||
Configuration for the `auto_linker` library:
|
||||
Configuration for Pleroma's link formatter which parses mentions, hashtags, and URLs.
|
||||
|
||||
* `class: "auto-linker"` - specify the class to be added to the generated link. false to clear.
|
||||
* `rel: "noopener noreferrer"` - override the rel attribute. false to clear.
|
||||
* `new_window: true` - set to false to remove `target='_blank'` attribute.
|
||||
* `scheme: false` - Set to true to link urls with schema `http://google.com`.
|
||||
* `truncate: false` - Set to a number to truncate urls longer then the number. Truncated urls will end in `..`.
|
||||
* `strip_prefix: true` - Strip the scheme prefix.
|
||||
* `extra: false` - link urls with rarely used schemes (magnet, ipfs, irc, etc.).
|
||||
* `class` - specify the class to be added to the generated link (default: `false`)
|
||||
* `rel` - specify the rel attribute (default: `ugc`)
|
||||
* `new_window` - adds `target="_blank"` attribute (default: `false`)
|
||||
* `truncate` - Set to a number to truncate URLs longer then the number. Truncated URLs will end in `...` (default: `false`)
|
||||
* `strip_prefix` - Strip the scheme prefix (default: `false`)
|
||||
* `extra` - link URLs with rarely used schemes (magnet, ipfs, irc, etc.) (default: `true`)
|
||||
* `validate_tld` - Set to false to disable TLD validation for URLs/emails. Can be set to :no_scheme to validate TLDs only for urls without a scheme (e.g `example.com` will be validated, but `http://example.loki` won't) (default: `:no_scheme`)
|
||||
|
||||
Example:
|
||||
|
||||
```elixir
|
||||
config :auto_linker,
|
||||
opts: [
|
||||
scheme: true,
|
||||
extra: true,
|
||||
class: false,
|
||||
strip_prefix: false,
|
||||
new_window: false,
|
||||
rel: "ugc"
|
||||
]
|
||||
config :pleroma, Pleroma.Formatter,
|
||||
class: false,
|
||||
rel: "ugc",
|
||||
new_window: false,
|
||||
truncate: false,
|
||||
strip_prefix: false,
|
||||
extra: true,
|
||||
validate_tld: :no_scheme
|
||||
```
|
||||
|
||||
## Custom Runtime Modules (`:modules`)
|
||||
|
@ -1019,3 +1059,25 @@ Note: setting `restrict_unauthenticated/timelines/local` to `true` has no practi
|
|||
Control favicons for instances.
|
||||
|
||||
* `enabled`: Allow/disallow displaying and getting instances favicons
|
||||
|
||||
## Frontend management
|
||||
|
||||
Frontends in Pleroma are swappable - you can specify which one to use here.
|
||||
|
||||
For now, you can set a frontend with the key `primary` and the options of `name` and `ref`. This will then make Pleroma serve the frontend from a folder constructed by concatenating the instance static path, `frontends` and the name and ref.
|
||||
|
||||
The key `primary` refers to the frontend that will be served by default for general requests. In the future, other frontends like the admin frontend will also be configurable here.
|
||||
|
||||
If you don't set anything here, the bundled frontend will be used.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
config :pleroma, :frontends,
|
||||
primary: %{
|
||||
"name" => "pleroma",
|
||||
"ref" => "stable"
|
||||
}
|
||||
```
|
||||
|
||||
This would serve the frontend from the the folder at `$instance_static/frontends/pleroma/stable`. You have to copy the frontend into this folder yourself. You can choose the name and ref any way you like, but they will be used by mix tasks to automate installation in the future, the name referring to the project and the ref referring to a commit.
|
||||
|
|
|
@ -5,13 +5,7 @@ The configuration of Pleroma has traditionally been managed with a config file,
|
|||
|
||||
## Migration to database config
|
||||
|
||||
1. Stop your Pleroma instance and edit your Pleroma config to enable database configuration:
|
||||
|
||||
```
|
||||
config :pleroma, configurable_from_database: true
|
||||
```
|
||||
|
||||
2. Run the mix task to migrate to the database. You'll receive some debugging output and a few messages informing you of what happened.
|
||||
1. Run the mix task to migrate to the database. You'll receive some debugging output and a few messages informing you of what happened.
|
||||
|
||||
**Source:**
|
||||
|
||||
|
@ -23,76 +17,82 @@ The configuration of Pleroma has traditionally been managed with a config file,
|
|||
|
||||
**OTP:**
|
||||
|
||||
*Note: OTP users need Pleroma to be running for `pleroma_ctl` commands to work*
|
||||
|
||||
```
|
||||
$ ./bin/pleroma_ctl config migrate_to_db
|
||||
```
|
||||
|
||||
```
|
||||
10:04:34.155 [debug] QUERY OK source="config" db=1.6ms decode=2.0ms queue=33.5ms idle=0.0ms
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 []
|
||||
Migrating settings from file: /home/pleroma/config/dev.secret.exs
|
||||
```
|
||||
10:04:34.155 [debug] QUERY OK source="config" db=1.6ms decode=2.0ms queue=33.5ms idle=0.0ms
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 []
|
||||
Migrating settings from file: /home/pleroma/config/dev.secret.exs
|
||||
|
||||
10:04:34.240 [debug] QUERY OK db=4.5ms queue=0.3ms idle=92.2ms
|
||||
TRUNCATE config; []
|
||||
|
||||
10:04:34.240 [debug] QUERY OK db=4.5ms queue=0.3ms idle=92.2ms
|
||||
TRUNCATE config; []
|
||||
|
||||
10:04:34.244 [debug] QUERY OK db=2.8ms queue=0.3ms idle=97.2ms
|
||||
ALTER SEQUENCE config_id_seq RESTART; []
|
||||
|
||||
10:04:34.256 [debug] QUERY OK source="config" db=0.8ms queue=1.4ms idle=109.8ms
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 WHERE ((c0."group" = $1) AND (c0."key" = $2)) [":pleroma", ":instance"]
|
||||
|
||||
10:04:34.292 [debug] QUERY OK db=2.6ms queue=1.7ms idle=137.7ms
|
||||
INSERT INTO "config" ("group","key","value","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" [":pleroma", ":instance", <<131, 108, 0, 0, 0, 1, 104, 2, 100, 0, 4, 110, 97, 109, 101, 109, 0, 0, 0, 7, 66, 108, 101, 114, 111, 109, 97, 106>>, ~N[2020-07-12 15:04:34], ~N[2020-07-12 15:04:34]]
|
||||
Settings for key instance migrated.
|
||||
Settings for group :pleroma migrated.
|
||||
10:04:34.244 [debug] QUERY OK db=2.8ms queue=0.3ms idle=97.2ms
|
||||
ALTER SEQUENCE config_id_seq RESTART; []
|
||||
|
||||
10:04:34.256 [debug] QUERY OK source="config" db=0.8ms queue=1.4ms idle=109.8ms
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 WHERE ((c0."group" = $1) AND (c0."key" = $2)) [":pleroma", ":instance"]
|
||||
|
||||
10:04:34.292 [debug] QUERY OK db=2.6ms queue=1.7ms idle=137.7ms
|
||||
INSERT INTO "config" ("group","key","value","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" [":pleroma", ":instance", <<131, 108, 0, 0, 0, 1, 104, 2, 100, 0, 4, 110, 97, 109, 101, 109, 0, 0, 0, 7, 66, 108, 101, 114, 111, 109, 97, 106>>, ~N[2020-07-12 15:04:34], ~N[2020-07-12 15:04:34]]
|
||||
Settings for key instance migrated.
|
||||
Settings for group :pleroma migrated.
|
||||
```
|
||||
|
||||
3. It is recommended to backup your config file now.
|
||||
2. It is recommended to backup your config file now.
|
||||
|
||||
```
|
||||
cp config/dev.secret.exs config/dev.secret.exs.orig
|
||||
```
|
||||
|
||||
4. Now you can edit your config file and strip it down to the only settings which are not possible to control in the database. e.g., the Postgres and webserver (Endpoint) settings cannot be controlled in the database because the application needs the settings to start up and access the database.
|
||||
3. Edit your Pleroma config to enable database configuration:
|
||||
|
||||
⚠️ **THIS IS NOT REQUIRED**
|
||||
```
|
||||
config :pleroma, configurable_from_database: true
|
||||
```
|
||||
|
||||
4. ⚠️ **THIS IS NOT REQUIRED** ⚠️
|
||||
|
||||
Now you can edit your config file and strip it down to the only settings which are not possible to control in the database. e.g., the Postgres (Repo) and webserver (Endpoint) settings cannot be controlled in the database because the application needs the settings to start up and access the database.
|
||||
|
||||
Any settings in the database will override those in the config file, but you may find it less confusing if the setting is only declared in one place.
|
||||
|
||||
A non-exhaustive list of settings that are only possible in the config file include the following:
|
||||
|
||||
* config :pleroma, Pleroma.Web.Endpoint
|
||||
* config :pleroma, Pleroma.Repo
|
||||
* config :pleroma, configurable\_from\_database
|
||||
* config :pleroma, :database, rum_enabled
|
||||
* config :pleroma, :connections_pool
|
||||
|
||||
Here is an example of a server config stripped down after migration:
|
||||
|
||||
```
|
||||
use Mix.Config
|
||||
|
||||
config :pleroma, Pleroma.Web.Endpoint,
|
||||
url: [host: "cool.pleroma.site", scheme: "https", port: 443]
|
||||
|
||||
config :pleroma, Pleroma.Repo,
|
||||
adapter: Ecto.Adapters.Postgres,
|
||||
username: "pleroma",
|
||||
password: "MySecretPassword",
|
||||
database: "pleroma_prod",
|
||||
hostname: "localhost"
|
||||
|
||||
config :pleroma, configurable_from_database: true
|
||||
```
|
||||
|
||||
Any settings in the database will override those in the config file, but you may find it less confusing if the setting is only declared in one place.
|
||||
|
||||
A non-exhaustive list of settings that are only possible in the config file include the following:
|
||||
|
||||
* config :pleroma, Pleroma.Web.Endpoint
|
||||
* config :pleroma, Pleroma.Repo
|
||||
* config :pleroma, configurable_from_database
|
||||
* config :pleroma, :database, rum_enabled
|
||||
* config :pleroma, :connections_pool
|
||||
|
||||
Here is an example of a server config stripped down after migration:
|
||||
|
||||
```
|
||||
use Mix.Config
|
||||
|
||||
config :pleroma, Pleroma.Web.Endpoint,
|
||||
url: [host: "cool.pleroma.site", scheme: "https", port: 443]
|
||||
|
||||
|
||||
config :pleroma, Pleroma.Repo,
|
||||
adapter: Ecto.Adapters.Postgres,
|
||||
username: "pleroma",
|
||||
password: "MySecretPassword",
|
||||
database: "pleroma_prod",
|
||||
hostname: "localhost"
|
||||
|
||||
config :pleroma, configurable_from_database: true
|
||||
```
|
||||
|
||||
5. Start your instance back up and you can now access the Settings tab in AdminFE.
|
||||
5. Restart your instance and you can now access the Settings tab in AdminFE.
|
||||
|
||||
|
||||
## Reverting back from database config
|
||||
|
||||
1. Stop your Pleroma instance.
|
||||
|
||||
2. Run the mix task to migrate back from the database. You'll receive some debugging output and a few messages informing you of what happened.
|
||||
1. Run the mix task to migrate back from the database. You'll receive some debugging output and a few messages informing you of what happened.
|
||||
|
||||
**Source:**
|
||||
|
||||
|
@ -110,14 +110,16 @@ config :pleroma, configurable_from_database: true
|
|||
|
||||
```
|
||||
10:26:30.593 [debug] QUERY OK source="config" db=9.8ms decode=1.2ms queue=26.0ms idle=0.0ms
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 []
|
||||
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 []
|
||||
|
||||
10:26:30.659 [debug] QUERY OK source="config" db=1.1ms idle=80.7ms
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 []
|
||||
Database configuration settings have been saved to config/dev.exported_from_db.secret.exs
|
||||
```
|
||||
SELECT c0."id", c0."key", c0."group", c0."value", c0."inserted_at", c0."updated_at" FROM "config" AS c0 []
|
||||
Database configuration settings have been saved to config/dev.exported_from_db.secret.exs
|
||||
```
|
||||
|
||||
3. The in-database configuration still exists, but it will not be used if you remove `config :pleroma, configurable_from_database: true` from your config.
|
||||
2. Remove `config :pleroma, configurable_from_database: true` from your config. The in-database configuration still exists, but it will not be used. Future migrations will erase the database config before importing your config file again.
|
||||
|
||||
3. Restart your instance.
|
||||
|
||||
## Debugging
|
||||
|
||||
|
|
|
@ -121,6 +121,9 @@ chown -R pleroma /etc/pleroma
|
|||
# Run the config generator
|
||||
su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql"
|
||||
|
||||
# Run the environment file generator.
|
||||
su pleroma -s $SHELL -lc "./bin/pleroma_ctl release_env gen"
|
||||
|
||||
# Create the postgres database
|
||||
su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
|
||||
|
||||
|
@ -131,7 +134,7 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
|
|||
# su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
|
||||
|
||||
# Start the instance to verify that everything is working as expected
|
||||
su pleroma -s $SHELL -lc "./bin/pleroma daemon"
|
||||
su pleroma -s $SHELL -lc "export $(cat /opt/pleroma/config/pleroma.env); ./bin/pleroma daemon"
|
||||
|
||||
# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly
|
||||
sleep 20 && curl http://localhost:4000/api/v1/instance
|
||||
|
@ -200,6 +203,7 @@ rc-update add pleroma
|
|||
# Copy the service into a proper directory
|
||||
cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service
|
||||
|
||||
|
||||
# Start pleroma and enable it on boot
|
||||
systemctl start pleroma
|
||||
systemctl enable pleroma
|
||||
|
@ -275,4 +279,3 @@ This will create an account withe the username of 'joeuser' with the email addre
|
|||
## Questions
|
||||
|
||||
Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ pidfile="/var/run/pleroma.pid"
|
|||
directory=/opt/pleroma
|
||||
healthcheck_delay=60
|
||||
healthcheck_timer=30
|
||||
export $(cat /opt/pleroma/config/pleroma.env)
|
||||
|
||||
: ${pleroma_port:-4000}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ Environment="MIX_ENV=prod"
|
|||
Environment="HOME=/var/lib/pleroma"
|
||||
; Path to the folder containing the Pleroma installation.
|
||||
WorkingDirectory=/opt/pleroma
|
||||
; Path to the environment file. the file contains RELEASE_COOKIE and etc
|
||||
EnvironmentFile=/opt/pleroma/config/pleroma.env
|
||||
; Path to the Mix binary.
|
||||
ExecStart=/usr/bin/mix phx.server
|
||||
|
||||
|
|
|
@ -24,8 +24,10 @@ def start_pleroma do
|
|||
Application.put_env(:logger, :console, level: :debug)
|
||||
end
|
||||
|
||||
adapter = Application.get_env(:tesla, :adapter)
|
||||
|
||||
apps =
|
||||
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Gun do
|
||||
if adapter == Tesla.Adapter.Gun do
|
||||
[:gun | @apps]
|
||||
else
|
||||
[:hackney | @apps]
|
||||
|
@ -33,11 +35,14 @@ def start_pleroma do
|
|||
|
||||
Enum.each(apps, &Application.ensure_all_started/1)
|
||||
|
||||
children = [
|
||||
Pleroma.Repo,
|
||||
{Pleroma.Config.TransferTask, false},
|
||||
Pleroma.Web.Endpoint
|
||||
]
|
||||
children =
|
||||
[
|
||||
Pleroma.Repo,
|
||||
{Pleroma.Config.TransferTask, false},
|
||||
Pleroma.Web.Endpoint,
|
||||
{Oban, Pleroma.Config.get(Oban)}
|
||||
] ++
|
||||
http_children(adapter)
|
||||
|
||||
cachex_children = Enum.map(@cachex_children, &Pleroma.Application.build_cachex(&1, []))
|
||||
|
||||
|
@ -115,4 +120,11 @@ def mix_shell?, do: :erlang.function_exported(Mix, :shell, 0)
|
|||
def escape_sh_path(path) do
|
||||
~S(') <> String.replace(path, ~S('), ~S(\')) <> ~S(')
|
||||
end
|
||||
|
||||
defp http_children(Tesla.Adapter.Gun) do
|
||||
Pleroma.Gun.ConnectionPool.children() ++
|
||||
[{Task, &Pleroma.HTTP.AdapterHelper.Gun.limiter_setup/0}]
|
||||
end
|
||||
|
||||
defp http_children(_), do: []
|
||||
end
|
||||
|
|
76
lib/mix/tasks/pleroma/release_env.ex
Normal file
76
lib/mix/tasks/pleroma/release_env.ex
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.ReleaseEnv do
|
||||
use Mix.Task
|
||||
import Mix.Pleroma
|
||||
|
||||
@shortdoc "Generate Pleroma environment file."
|
||||
@moduledoc File.read!("docs/administration/CLI_tasks/release_environments.md")
|
||||
|
||||
def run(["gen" | rest]) do
|
||||
{options, [], []} =
|
||||
OptionParser.parse(
|
||||
rest,
|
||||
strict: [
|
||||
force: :boolean,
|
||||
path: :string
|
||||
],
|
||||
aliases: [
|
||||
p: :path,
|
||||
f: :force
|
||||
]
|
||||
)
|
||||
|
||||
file_path =
|
||||
get_option(
|
||||
options,
|
||||
:path,
|
||||
"Environment file path",
|
||||
"./config/pleroma.env"
|
||||
)
|
||||
|
||||
env_path = Path.expand(file_path)
|
||||
|
||||
proceed? =
|
||||
if File.exists?(env_path) do
|
||||
get_option(
|
||||
options,
|
||||
:force,
|
||||
"Environment file already exists. Do you want to overwrite the #{env_path} file? (y/n)",
|
||||
"n"
|
||||
) === "y"
|
||||
else
|
||||
true
|
||||
end
|
||||
|
||||
if proceed? do
|
||||
case do_generate(env_path) do
|
||||
{:error, reason} ->
|
||||
shell_error(
|
||||
File.Error.message(%{action: "write to file", reason: reason, path: env_path})
|
||||
)
|
||||
|
||||
_ ->
|
||||
shell_info("\nThe file generated: #{env_path}.\n")
|
||||
|
||||
shell_info("""
|
||||
WARNING: before start pleroma app please make sure to make the file read-only and non-modifiable.
|
||||
Example:
|
||||
chmod 0444 #{file_path}
|
||||
chattr +i #{file_path}
|
||||
""")
|
||||
end
|
||||
else
|
||||
shell_info("\nThe file is exist. #{env_path}.\n")
|
||||
end
|
||||
end
|
||||
|
||||
def do_generate(path) do
|
||||
content = "RELEASE_COOKIE=#{Base.encode32(:crypto.strong_rand_bytes(32))}"
|
||||
|
||||
File.mkdir_p!(Path.dirname(path))
|
||||
File.write(path, content)
|
||||
end
|
||||
end
|
|
@ -16,7 +16,9 @@ defmodule VerifyError, do: defexception([:message])
|
|||
@spec verify!() :: :ok | VerifyError.t()
|
||||
def verify! do
|
||||
:ok
|
||||
|> check_confirmation_accounts!
|
||||
|> check_migrations_applied!()
|
||||
|> check_welcome_message_config!()
|
||||
|> check_rum!()
|
||||
|> handle_result()
|
||||
end
|
||||
|
@ -24,6 +26,40 @@ def verify! do
|
|||
defp handle_result(:ok), do: :ok
|
||||
defp handle_result({:error, message}), do: raise(VerifyError, message: message)
|
||||
|
||||
defp check_welcome_message_config!(:ok) do
|
||||
if Pleroma.Config.get([:welcome, :email, :enabled], false) and
|
||||
not Pleroma.Emails.Mailer.enabled?() do
|
||||
Logger.error("""
|
||||
To send welcome email do you need to enable mail.
|
||||
\nconfig :pleroma, Pleroma.Emails.Mailer, enabled: true
|
||||
""")
|
||||
|
||||
{:error, "The mail disabled."}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp check_welcome_message_config!(result), do: result
|
||||
|
||||
# Checks account confirmation email
|
||||
#
|
||||
def check_confirmation_accounts!(:ok) do
|
||||
if Pleroma.Config.get([:instance, :account_activation_required]) &&
|
||||
not Pleroma.Config.get([Pleroma.Emails.Mailer, :enabled]) do
|
||||
Logger.error(
|
||||
"Account activation enabled, but no Mailer settings enabled.\nPlease set config :pleroma, :instance, account_activation_required: false\nOtherwise setup and enable Mailer."
|
||||
)
|
||||
|
||||
{:error,
|
||||
"Account activation enabled, but Mailer is disabled. Cannot send confirmation emails."}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def check_confirmation_accounts!(result), do: result
|
||||
|
||||
# Checks for pending migrations.
|
||||
#
|
||||
def check_migrations_applied!(:ok) do
|
||||
|
|
|
@ -21,7 +21,8 @@ def new do
|
|||
type: :kocaptcha,
|
||||
token: json_resp["token"],
|
||||
url: endpoint <> json_resp["url"],
|
||||
answer_data: json_resp["md5"]
|
||||
answer_data: json_resp["md5"],
|
||||
seconds_valid: Pleroma.Config.get([Pleroma.Captcha, :seconds_valid])
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,7 +17,8 @@ def new do
|
|||
type: :native,
|
||||
token: token(),
|
||||
url: "data:image/png;base64," <> Base.encode64(img_binary),
|
||||
answer_data: answer_data
|
||||
answer_data: answer_data,
|
||||
seconds_valid: Pleroma.Config.get([Pleroma.Captcha, :seconds_valid])
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,12 +11,10 @@ def get(key), do: get(key, nil)
|
|||
|
||||
def get([key], default), do: get(key, default)
|
||||
|
||||
def get([parent_key | keys], default) do
|
||||
case :pleroma
|
||||
|> Application.get_env(parent_key)
|
||||
|> get_in(keys) do
|
||||
nil -> default
|
||||
any -> any
|
||||
def get([_ | _] = path, default) do
|
||||
case fetch(path) do
|
||||
{:ok, value} -> value
|
||||
:error -> default
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -34,6 +32,24 @@ def get!(key) do
|
|||
end
|
||||
end
|
||||
|
||||
def fetch(key) when is_atom(key), do: fetch([key])
|
||||
|
||||
def fetch([root_key | keys]) do
|
||||
Enum.reduce_while(keys, Application.fetch_env(:pleroma, root_key), fn
|
||||
key, {:ok, config} when is_map(config) or is_list(config) ->
|
||||
case Access.fetch(config, key) do
|
||||
:error ->
|
||||
{:halt, :error}
|
||||
|
||||
value ->
|
||||
{:cont, value}
|
||||
end
|
||||
|
||||
_key, _config ->
|
||||
{:halt, :error}
|
||||
end)
|
||||
end
|
||||
|
||||
def put([key], value), do: put(key, value)
|
||||
|
||||
def put([parent_key | keys], value) do
|
||||
|
@ -50,12 +66,15 @@ def put(key, value) do
|
|||
|
||||
def delete([key]), do: delete(key)
|
||||
|
||||
def delete([parent_key | keys]) do
|
||||
{_, parent} =
|
||||
Application.get_env(:pleroma, parent_key)
|
||||
|> get_and_update_in(keys, fn _ -> :pop end)
|
||||
def delete([parent_key | keys] = path) do
|
||||
with {:ok, _} <- fetch(path) do
|
||||
{_, parent} =
|
||||
parent_key
|
||||
|> get()
|
||||
|> get_and_update_in(keys, fn _ -> :pop end)
|
||||
|
||||
Application.put_env(:pleroma, parent_key, parent)
|
||||
Application.put_env(:pleroma, parent_key, parent)
|
||||
end
|
||||
end
|
||||
|
||||
def delete(key) do
|
||||
|
|
|
@ -156,7 +156,6 @@ defp only_full_update?(%ConfigDB{group: group, key: key}) do
|
|||
{:quack, :meta},
|
||||
{:mime, :types},
|
||||
{:cors_plug, [:max_age, :methods, :expose, :headers]},
|
||||
{:auto_linker, :opts},
|
||||
{:swarm, :node_blacklist},
|
||||
{:logger, :backends}
|
||||
]
|
||||
|
|
|
@ -55,6 +55,24 @@ def warn do
|
|||
mrf_user_allowlist()
|
||||
check_old_mrf_config()
|
||||
check_media_proxy_whitelist_config()
|
||||
check_welcome_message_config()
|
||||
end
|
||||
|
||||
def check_welcome_message_config do
|
||||
instance_config = Pleroma.Config.get([:instance])
|
||||
|
||||
use_old_config =
|
||||
Keyword.has_key?(instance_config, :welcome_user_nickname) or
|
||||
Keyword.has_key?(instance_config, :welcome_message)
|
||||
|
||||
if use_old_config do
|
||||
Logger.error("""
|
||||
!!!DEPRECATION WARNING!!!
|
||||
Your config is using the old namespace for Welcome messages configuration. You need to change to the new namespace:
|
||||
\n* `config :pleroma, :instance, welcome_user_nickname` is now `config :pleroma, :welcome, :direct_message, :sender_nickname`
|
||||
\n* `config :pleroma, :instance, welcome_message` is now `config :pleroma, :welcome, :direct_message, :message`
|
||||
""")
|
||||
end
|
||||
end
|
||||
|
||||
def check_old_mrf_config do
|
||||
|
|
17
lib/pleroma/config/helpers.ex
Normal file
17
lib/pleroma/config/helpers.ex
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Config.Helpers do
|
||||
alias Pleroma.Config
|
||||
|
||||
def instance_name, do: Config.get([:instance, :name])
|
||||
|
||||
defp instance_notify_email do
|
||||
Config.get([:instance, :notify_email]) || Config.get([:instance, :email])
|
||||
end
|
||||
|
||||
def sender do
|
||||
{instance_name(), instance_notify_email()}
|
||||
end
|
||||
end
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Emails.AdminEmail do
|
|||
import Swoosh.Email
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.HTML
|
||||
alias Pleroma.Web.Router.Helpers
|
||||
|
||||
defp instance_config, do: Config.get(:instance)
|
||||
|
@ -82,4 +83,18 @@ def report(to, reporter, account, statuses, comment) do
|
|||
|> subject("#{instance_name()} Report")
|
||||
|> html_body(html_body)
|
||||
end
|
||||
|
||||
def new_unapproved_registration(to, account) do
|
||||
html_body = """
|
||||
<p>New account for review: <a href="#{user_url(account)}">@#{account.nickname}</a></p>
|
||||
<blockquote>#{HTML.strip_tags(account.registration_reason)}</blockquote>
|
||||
<a href="#{Pleroma.Web.base_url()}/pleroma/admin">Visit AdminFE</a>
|
||||
"""
|
||||
|
||||
new()
|
||||
|> to({to.name, to.email})
|
||||
|> from({instance_name(), instance_notify_email()})
|
||||
|> subject("New account up for review on #{instance_name()} (@#{account.nickname})")
|
||||
|> html_body(html_body)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,17 +12,22 @@ defmodule Pleroma.Emails.UserEmail do
|
|||
alias Pleroma.Web.Endpoint
|
||||
alias Pleroma.Web.Router
|
||||
|
||||
defp instance_name, do: Config.get([:instance, :name])
|
||||
|
||||
defp sender do
|
||||
email = Config.get([:instance, :notify_email]) || Config.get([:instance, :email])
|
||||
{instance_name(), email}
|
||||
end
|
||||
import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
|
||||
|
||||
defp recipient(email, nil), do: email
|
||||
defp recipient(email, name), do: {name, email}
|
||||
defp recipient(%User{} = user), do: recipient(user.email, user.name)
|
||||
|
||||
@spec welcome(User.t(), map()) :: Swoosh.Email.t()
|
||||
def welcome(user, opts \\ %{}) do
|
||||
new()
|
||||
|> to(recipient(user))
|
||||
|> from(Map.get(opts, :sender, sender()))
|
||||
|> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
|
||||
|> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
|
||||
|> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
|
||||
end
|
||||
|
||||
def password_reset_email(user, token) when is_binary(token) do
|
||||
password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
|
||||
|
||||
|
|
|
@ -95,7 +95,11 @@ def followers_query(%User{} = user) do
|
|||
|> where([r], r.state == ^:follow_accept)
|
||||
end
|
||||
|
||||
def followers_ap_ids(%User{} = user, from_ap_ids \\ nil) do
|
||||
def followers_ap_ids(user, from_ap_ids \\ nil)
|
||||
|
||||
def followers_ap_ids(_, []), do: []
|
||||
|
||||
def followers_ap_ids(%User{} = user, from_ap_ids) do
|
||||
query =
|
||||
user
|
||||
|> followers_query()
|
||||
|
|
|
@ -10,11 +10,15 @@ defmodule Pleroma.Formatter do
|
|||
@link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui
|
||||
@markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
|
||||
|
||||
@auto_linker_config hashtag: true,
|
||||
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
|
||||
mention: true,
|
||||
mention_handler: &Pleroma.Formatter.mention_handler/4,
|
||||
scheme: true
|
||||
defp linkify_opts do
|
||||
Pleroma.Config.get(Pleroma.Formatter) ++
|
||||
[
|
||||
hashtag: true,
|
||||
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
|
||||
mention: true,
|
||||
mention_handler: &Pleroma.Formatter.mention_handler/4
|
||||
]
|
||||
end
|
||||
|
||||
def escape_mention_handler("@" <> nickname = mention, buffer, _, _) do
|
||||
case User.get_cached_by_nickname(nickname) do
|
||||
|
@ -80,19 +84,19 @@ def hashtag_handler("#" <> tag = tag_text, _buffer, _opts, acc) do
|
|||
@spec linkify(String.t(), keyword()) ::
|
||||
{String.t(), [{String.t(), User.t()}], [{String.t(), String.t()}]}
|
||||
def linkify(text, options \\ []) do
|
||||
options = options ++ @auto_linker_config
|
||||
options = linkify_opts() ++ options
|
||||
|
||||
if options[:safe_mention] && Regex.named_captures(@safe_mention_regex, text) do
|
||||
%{"mentions" => mentions, "rest" => rest} = Regex.named_captures(@safe_mention_regex, text)
|
||||
acc = %{mentions: MapSet.new(), tags: MapSet.new()}
|
||||
|
||||
{text_mentions, %{mentions: mentions}} = AutoLinker.link_map(mentions, acc, options)
|
||||
{text_rest, %{tags: tags}} = AutoLinker.link_map(rest, acc, options)
|
||||
{text_mentions, %{mentions: mentions}} = Linkify.link_map(mentions, acc, options)
|
||||
{text_rest, %{tags: tags}} = Linkify.link_map(rest, acc, options)
|
||||
|
||||
{text_mentions <> text_rest, MapSet.to_list(mentions), MapSet.to_list(tags)}
|
||||
else
|
||||
acc = %{mentions: MapSet.new(), tags: MapSet.new()}
|
||||
{text, %{mentions: mentions, tags: tags}} = AutoLinker.link_map(text, acc, options)
|
||||
{text, %{mentions: mentions, tags: tags}} = Linkify.link_map(text, acc, options)
|
||||
|
||||
{text, MapSet.to_list(mentions), MapSet.to_list(tags)}
|
||||
end
|
||||
|
@ -111,9 +115,9 @@ def mentions_escape(text, options \\ []) do
|
|||
|
||||
if options[:safe_mention] && Regex.named_captures(@safe_mention_regex, text) do
|
||||
%{"mentions" => mentions, "rest" => rest} = Regex.named_captures(@safe_mention_regex, text)
|
||||
AutoLinker.link(mentions, options) <> AutoLinker.link(rest, options)
|
||||
Linkify.link(mentions, options) <> Linkify.link(rest, options)
|
||||
else
|
||||
AutoLinker.link(text, options)
|
||||
Linkify.link(text, options)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -96,16 +96,18 @@ def response("") do
|
|||
|
||||
def response("/main/public") do
|
||||
posts =
|
||||
ActivityPub.fetch_public_activities(%{"type" => ["Create"], "local_only" => true})
|
||||
|> render_activities
|
||||
%{type: ["Create"], local_only: true}
|
||||
|> ActivityPub.fetch_public_activities()
|
||||
|> render_activities()
|
||||
|
||||
info("Welcome to the Public Timeline!") <> posts <> ".\r\n"
|
||||
end
|
||||
|
||||
def response("/main/all") do
|
||||
posts =
|
||||
ActivityPub.fetch_public_activities(%{"type" => ["Create"]})
|
||||
|> render_activities
|
||||
%{type: ["Create"]}
|
||||
|> ActivityPub.fetch_public_activities()
|
||||
|> render_activities()
|
||||
|
||||
info("Welcome to the Federated Timeline!") <> posts <> ".\r\n"
|
||||
end
|
||||
|
@ -130,13 +132,14 @@ def response("/notices/" <> id) do
|
|||
def response("/users/" <> nickname) do
|
||||
with %User{} = user <- User.get_cached_by_nickname(nickname) do
|
||||
params = %{
|
||||
"type" => ["Create"],
|
||||
"actor_id" => user.ap_id
|
||||
type: ["Create"],
|
||||
actor_id: user.ap_id
|
||||
}
|
||||
|
||||
activities =
|
||||
ActivityPub.fetch_public_activities(params)
|
||||
|> render_activities
|
||||
params
|
||||
|> ActivityPub.fetch_public_activities()
|
||||
|> render_activities()
|
||||
|
||||
info("Posts by #{user.nickname}") <> activities <> ".\r\n"
|
||||
else
|
||||
|
|
|
@ -10,6 +10,7 @@ def children do
|
|||
]
|
||||
end
|
||||
|
||||
@spec get_conn(URI.t(), keyword()) :: {:ok, pid()} | {:error, term()}
|
||||
def get_conn(uri, opts) do
|
||||
key = "#{uri.scheme}:#{uri.host}:#{uri.port}"
|
||||
|
||||
|
@ -19,7 +20,7 @@ def get_conn(uri, opts) do
|
|||
get_gun_pid_from_worker(worker_pid, true)
|
||||
|
||||
[{worker_pid, {gun_pid, _used_by, _crf, _last_reference}}] ->
|
||||
GenServer.cast(worker_pid, {:add_client, self(), false})
|
||||
GenServer.call(worker_pid, :add_client)
|
||||
{:ok, gun_pid}
|
||||
|
||||
[] ->
|
||||
|
@ -45,7 +46,7 @@ defp get_gun_pid_from_worker(worker_pid, register) do
|
|||
# so instead we use cast + monitor
|
||||
|
||||
ref = Process.monitor(worker_pid)
|
||||
if register, do: GenServer.cast(worker_pid, {:add_client, self(), true})
|
||||
if register, do: GenServer.cast(worker_pid, {:add_client, self()})
|
||||
|
||||
receive do
|
||||
{:conn_pid, pid} ->
|
||||
|
@ -54,12 +55,14 @@ defp get_gun_pid_from_worker(worker_pid, register) do
|
|||
|
||||
{:DOWN, ^ref, :process, ^worker_pid, reason} ->
|
||||
case reason do
|
||||
{:shutdown, error} -> error
|
||||
{:shutdown, {:error, _} = error} -> error
|
||||
{:shutdown, error} -> {:error, error}
|
||||
_ -> {:error, reason}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@spec release_conn(pid()) :: :ok
|
||||
def release_conn(conn_pid) do
|
||||
# :ets.fun2ms(fn {_, {worker_pid, {gun_pid, _, _, _}}} when gun_pid == conn_pid ->
|
||||
# worker_pid end)
|
||||
|
@ -70,7 +73,7 @@ def release_conn(conn_pid) do
|
|||
|
||||
case query_result do
|
||||
[worker_pid] ->
|
||||
GenServer.cast(worker_pid, {:remove_client, self()})
|
||||
GenServer.call(worker_pid, :remove_client)
|
||||
|
||||
[] ->
|
||||
:ok
|
||||
|
|
|
@ -36,7 +36,24 @@ def handle_continue({:connect, [key, uri, opts, client_pid]}, _) do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:add_client, client_pid, send_pid_back}, %{key: key} = state) do
|
||||
def handle_cast({:add_client, client_pid}, state) do
|
||||
case handle_call(:add_client, {client_pid, nil}, state) do
|
||||
{:reply, conn_pid, state, :hibernate} ->
|
||||
send(client_pid, {:conn_pid, conn_pid})
|
||||
{:noreply, state, :hibernate}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:remove_client, client_pid}, state) do
|
||||
case handle_call(:remove_client, {client_pid, nil}, state) do
|
||||
{:reply, _, state, :hibernate} ->
|
||||
{:noreply, state, :hibernate}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(:add_client, {client_pid, _}, %{key: key} = state) do
|
||||
time = :erlang.monotonic_time(:millisecond)
|
||||
|
||||
{{conn_pid, _, _, _}, _} =
|
||||
|
@ -44,8 +61,6 @@ def handle_cast({:add_client, client_pid, send_pid_back}, %{key: key} = state) d
|
|||
{conn_pid, [client_pid | used_by], crf(time - last_reference, crf), time}
|
||||
end)
|
||||
|
||||
if send_pid_back, do: send(client_pid, {:conn_pid, conn_pid})
|
||||
|
||||
state =
|
||||
if state.timer != nil do
|
||||
Process.cancel_timer(state[:timer])
|
||||
|
@ -57,11 +72,11 @@ def handle_cast({:add_client, client_pid, send_pid_back}, %{key: key} = state) d
|
|||
ref = Process.monitor(client_pid)
|
||||
|
||||
state = put_in(state.client_monitors[client_pid], ref)
|
||||
{:noreply, state, :hibernate}
|
||||
{:reply, conn_pid, state, :hibernate}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:remove_client, client_pid}, %{key: key} = state) do
|
||||
def handle_call(:remove_client, {client_pid, _}, %{key: key} = state) do
|
||||
{{_conn_pid, used_by, _crf, _last_reference}, _} =
|
||||
Registry.update_value(@registry, key, fn {conn_pid, used_by, crf, last_reference} ->
|
||||
{conn_pid, List.delete(used_by, client_pid), crf, last_reference}
|
||||
|
@ -78,7 +93,7 @@ def handle_cast({:remove_client, client_pid}, %{key: key} = state) do
|
|||
nil
|
||||
end
|
||||
|
||||
{:noreply, %{state | timer: timer}, :hibernate}
|
||||
{:reply, :ok, %{state | timer: timer}, :hibernate}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
@ -102,22 +117,13 @@ def handle_info({:gun_down, _pid, _protocol, _reason, _killed_streams} = down_me
|
|||
|
||||
@impl true
|
||||
def handle_info({:DOWN, _ref, :process, pid, reason}, state) do
|
||||
# Sometimes the client is dead before we demonitor it in :remove_client, so the message
|
||||
# arrives anyway
|
||||
:telemetry.execute(
|
||||
[:pleroma, :connection_pool, :client_death],
|
||||
%{client_pid: pid, reason: reason},
|
||||
%{key: state.key}
|
||||
)
|
||||
|
||||
case state.client_monitors[pid] do
|
||||
nil ->
|
||||
{:noreply, state, :hibernate}
|
||||
|
||||
_ref ->
|
||||
:telemetry.execute(
|
||||
[:pleroma, :connection_pool, :client_death],
|
||||
%{client_pid: pid, reason: reason},
|
||||
%{key: state.key}
|
||||
)
|
||||
|
||||
handle_cast({:remove_client, pid}, state)
|
||||
end
|
||||
handle_cast({:remove_client, pid}, state)
|
||||
end
|
||||
|
||||
# LRFU policy: https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.55.1478
|
||||
|
|
|
@ -69,7 +69,8 @@ def request(method, url, body, headers, options) when is_binary(url) do
|
|||
request = build_request(method, headers, options, url, body, params)
|
||||
|
||||
adapter = Application.get_env(:tesla, :adapter)
|
||||
client = Tesla.client([Pleroma.HTTP.Middleware.FollowRedirects], adapter)
|
||||
|
||||
client = Tesla.client(adapter_middlewares(adapter), adapter)
|
||||
|
||||
maybe_limit(
|
||||
fn ->
|
||||
|
@ -107,4 +108,10 @@ defp maybe_limit(fun, Tesla.Adapter.Gun, opts) do
|
|||
defp maybe_limit(fun, _, _) do
|
||||
fun.()
|
||||
end
|
||||
|
||||
defp adapter_middlewares(Tesla.Adapter.Gun) do
|
||||
[Pleroma.HTTP.Middleware.FollowRedirects]
|
||||
end
|
||||
|
||||
defp adapter_middlewares(_), do: []
|
||||
end
|
||||
|
|
|
@ -34,10 +34,12 @@ def url(request, u), do: %{request | url: u}
|
|||
@spec headers(Request.t(), Request.headers()) :: Request.t()
|
||||
def headers(request, headers) do
|
||||
headers_list =
|
||||
if Pleroma.Config.get([:http, :send_user_agent]) do
|
||||
with true <- Pleroma.Config.get([:http, :send_user_agent]),
|
||||
nil <- Enum.find(headers, fn {key, _val} -> String.downcase(key) == "user-agent" end) do
|
||||
[{"user-agent", Pleroma.Application.user_agent()} | headers]
|
||||
else
|
||||
headers
|
||||
_ ->
|
||||
headers
|
||||
end
|
||||
|
||||
%{request | headers: headers_list}
|
||||
|
|
|
@ -409,6 +409,17 @@ def get_log_entry_message(%ModerationLog{
|
|||
"@#{actor_nickname} deactivated users: #{users_to_nicknames_string(users)}"
|
||||
end
|
||||
|
||||
@spec get_log_entry_message(ModerationLog) :: String.t()
|
||||
def get_log_entry_message(%ModerationLog{
|
||||
data: %{
|
||||
"actor" => %{"nickname" => actor_nickname},
|
||||
"action" => "approve",
|
||||
"subject" => users
|
||||
}
|
||||
}) do
|
||||
"@#{actor_nickname} approved users: #{users_to_nicknames_string(users)}"
|
||||
end
|
||||
|
||||
@spec get_log_entry_message(ModerationLog) :: String.t()
|
||||
def get_log_entry_message(%ModerationLog{
|
||||
data: %{
|
||||
|
|
|
@ -124,6 +124,10 @@ def fetch_object_from_id!(id, options \\ []) do
|
|||
{:error, "Object has been deleted"} ->
|
||||
nil
|
||||
|
||||
{:reject, reason} ->
|
||||
Logger.info("Rejected #{id} while fetching: #{inspect(reason)}")
|
||||
nil
|
||||
|
||||
e ->
|
||||
Logger.error("Error while fetching #{id}: #{inspect(e)}")
|
||||
nil
|
||||
|
|
54
lib/pleroma/plugs/frontend_static.ex
Normal file
54
lib/pleroma/plugs/frontend_static.ex
Normal file
|
@ -0,0 +1,54 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Plugs.FrontendStatic do
|
||||
require Pleroma.Constants
|
||||
|
||||
@moduledoc """
|
||||
This is a shim to call `Plug.Static` but with runtime `from` configuration`. It dispatches to the different frontends.
|
||||
"""
|
||||
@behaviour Plug
|
||||
|
||||
def file_path(path, frontend_type \\ :primary) do
|
||||
if configuration = Pleroma.Config.get([:frontends, frontend_type]) do
|
||||
instance_static_path = Pleroma.Config.get([:instance, :static_dir], "instance/static")
|
||||
|
||||
Path.join([
|
||||
instance_static_path,
|
||||
"frontends",
|
||||
configuration["name"],
|
||||
configuration["ref"],
|
||||
path
|
||||
])
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def init(opts) do
|
||||
opts
|
||||
|> Keyword.put(:from, "__unconfigured_frontend_static_plug")
|
||||
|> Plug.Static.init()
|
||||
end
|
||||
|
||||
def call(conn, opts) do
|
||||
frontend_type = Map.get(opts, :frontend_type, :primary)
|
||||
path = file_path("", frontend_type)
|
||||
|
||||
if path do
|
||||
conn
|
||||
|> call_static(opts, path)
|
||||
else
|
||||
conn
|
||||
end
|
||||
end
|
||||
|
||||
defp call_static(conn, opts, from) do
|
||||
opts =
|
||||
opts
|
||||
|> Map.put(:from, from)
|
||||
|
||||
Plug.Static.call(conn, opts)
|
||||
end
|
||||
end
|
|
@ -16,28 +16,24 @@ def file_path(path) do
|
|||
instance_path =
|
||||
Path.join(Pleroma.Config.get([:instance, :static_dir], "instance/static/"), path)
|
||||
|
||||
if File.exists?(instance_path) do
|
||||
instance_path
|
||||
else
|
||||
frontend_path = Pleroma.Plugs.FrontendStatic.file_path(path, :primary)
|
||||
|
||||
(File.exists?(instance_path) && instance_path) ||
|
||||
(frontend_path && File.exists?(frontend_path) && frontend_path) ||
|
||||
Path.join(Application.app_dir(:pleroma, "priv/static/"), path)
|
||||
end
|
||||
end
|
||||
|
||||
def init(opts) do
|
||||
opts
|
||||
|> Keyword.put(:from, "__unconfigured_instance_static_plug")
|
||||
|> Keyword.put(:at, "/__unconfigured_instance_static_plug")
|
||||
|> Plug.Static.init()
|
||||
end
|
||||
|
||||
for only <- Pleroma.Constants.static_only_files() do
|
||||
at = Plug.Router.Utils.split("/")
|
||||
|
||||
def call(%{request_path: "/" <> unquote(only) <> _} = conn, opts) do
|
||||
call_static(
|
||||
conn,
|
||||
opts,
|
||||
unquote(at),
|
||||
Pleroma.Config.get([:instance, :static_dir], "instance/static")
|
||||
)
|
||||
end
|
||||
|
@ -47,11 +43,10 @@ def call(conn, _) do
|
|||
conn
|
||||
end
|
||||
|
||||
defp call_static(conn, opts, at, from) do
|
||||
defp call_static(conn, opts, from) do
|
||||
opts =
|
||||
opts
|
||||
|> Map.put(:from, from)
|
||||
|> Map.put(:at, at)
|
||||
|
||||
Plug.Static.call(conn, opts)
|
||||
end
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
defmodule Pleroma.ReverseProxy.Client.Tesla do
|
||||
@behaviour Pleroma.ReverseProxy.Client
|
||||
|
||||
alias Pleroma.Gun.ConnectionPool
|
||||
|
||||
@type headers() :: [{String.t(), String.t()}]
|
||||
@type status() :: pos_integer()
|
||||
|
||||
|
@ -31,6 +33,8 @@ def request(method, url, headers, body, opts \\ []) do
|
|||
if is_map(response.body) and method != :head do
|
||||
{:ok, response.status, response.headers, response.body}
|
||||
else
|
||||
conn_pid = response.opts[:adapter][:conn]
|
||||
ConnectionPool.release_conn(conn_pid)
|
||||
{:ok, response.status, response.headers}
|
||||
end
|
||||
else
|
||||
|
@ -41,15 +45,8 @@ def request(method, url, headers, body, opts \\ []) do
|
|||
@impl true
|
||||
@spec stream_body(map()) ::
|
||||
{:ok, binary(), map()} | {:error, atom() | String.t()} | :done | no_return()
|
||||
def stream_body(%{pid: pid, opts: opts, fin: true}) do
|
||||
# if connection was reused, but in tesla were redirects,
|
||||
# tesla returns new opened connection, which must be closed manually
|
||||
if opts[:old_conn], do: Tesla.Adapter.Gun.close(pid)
|
||||
# if there were redirects we need to checkout old conn
|
||||
conn = opts[:old_conn] || opts[:conn]
|
||||
|
||||
if conn, do: :ok = Pleroma.Gun.ConnectionPool.release_conn(conn)
|
||||
|
||||
def stream_body(%{pid: pid, fin: true}) do
|
||||
ConnectionPool.release_conn(pid)
|
||||
:done
|
||||
end
|
||||
|
||||
|
@ -74,8 +71,7 @@ defp read_chunk!(%{pid: pid, stream: stream, opts: opts}) do
|
|||
@impl true
|
||||
@spec close(map) :: :ok | no_return()
|
||||
def close(%{pid: pid}) do
|
||||
adapter = check_adapter()
|
||||
adapter.close(pid)
|
||||
ConnectionPool.release_conn(pid)
|
||||
end
|
||||
|
||||
defp check_adapter do
|
||||
|
|
|
@ -165,6 +165,9 @@ defp request(method, url, headers, opts) do
|
|||
{:ok, code, _, _} ->
|
||||
{:error, {:invalid_http_response, code}}
|
||||
|
||||
{:ok, code, _} ->
|
||||
{:error, {:invalid_http_response, code}}
|
||||
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
end
|
||||
|
|
|
@ -42,7 +42,12 @@ defmodule Pleroma.User do
|
|||
require Logger
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
@type account_status :: :active | :deactivated | :password_reset_pending | :confirmation_pending
|
||||
@type account_status ::
|
||||
:active
|
||||
| :deactivated
|
||||
| :password_reset_pending
|
||||
| :confirmation_pending
|
||||
| :approval_pending
|
||||
@primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
|
||||
|
||||
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
||||
|
@ -106,6 +111,8 @@ defmodule Pleroma.User do
|
|||
field(:locked, :boolean, default: false)
|
||||
field(:confirmation_pending, :boolean, default: false)
|
||||
field(:password_reset_pending, :boolean, default: false)
|
||||
field(:approval_pending, :boolean, default: false)
|
||||
field(:registration_reason, :string, default: nil)
|
||||
field(:confirmation_token, :string, default: nil)
|
||||
field(:default_scope, :string, default: "public")
|
||||
field(:domain_blocks, {:array, :string}, default: [])
|
||||
|
@ -262,6 +269,7 @@ def binary_id(%User{} = user), do: binary_id(user.id)
|
|||
@spec account_status(User.t()) :: account_status()
|
||||
def account_status(%User{deactivated: true}), do: :deactivated
|
||||
def account_status(%User{password_reset_pending: true}), do: :password_reset_pending
|
||||
def account_status(%User{approval_pending: true}), do: :approval_pending
|
||||
|
||||
def account_status(%User{confirmation_pending: true}) do
|
||||
if Config.get([:instance, :account_activation_required]) do
|
||||
|
@ -633,6 +641,7 @@ def force_password_reset(user), do: update_password_reset_pending(user, true)
|
|||
def register_changeset(struct, params \\ %{}, opts \\ []) do
|
||||
bio_limit = Config.get([:instance, :user_bio_length], 5000)
|
||||
name_limit = Config.get([:instance, :user_name_length], 100)
|
||||
reason_limit = Config.get([:instance, :registration_reason_length], 500)
|
||||
params = Map.put_new(params, :accepts_chat_messages, true)
|
||||
|
||||
need_confirmation? =
|
||||
|
@ -642,8 +651,16 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do
|
|||
opts[:need_confirmation]
|
||||
end
|
||||
|
||||
need_approval? =
|
||||
if is_nil(opts[:need_approval]) do
|
||||
Config.get([:instance, :account_approval_required])
|
||||
else
|
||||
opts[:need_approval]
|
||||
end
|
||||
|
||||
struct
|
||||
|> confirmation_changeset(need_confirmation: need_confirmation?)
|
||||
|> approval_changeset(need_approval: need_approval?)
|
||||
|> cast(params, [
|
||||
:bio,
|
||||
:raw_bio,
|
||||
|
@ -653,17 +670,28 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do
|
|||
:password,
|
||||
:password_confirmation,
|
||||
:emoji,
|
||||
:accepts_chat_messages
|
||||
:accepts_chat_messages,
|
||||
:registration_reason
|
||||
])
|
||||
|> validate_required([:name, :nickname, :password, :password_confirmation])
|
||||
|> validate_confirmation(:password)
|
||||
|> unique_constraint(:email)
|
||||
|> validate_format(:email, @email_regex)
|
||||
|> validate_change(:email, fn :email, email ->
|
||||
valid? =
|
||||
Config.get([User, :email_blacklist])
|
||||
|> Enum.all?(fn blacklisted_domain ->
|
||||
!String.ends_with?(email, ["@" <> blacklisted_domain, "." <> blacklisted_domain])
|
||||
end)
|
||||
|
||||
if valid?, do: [], else: [email: "Invalid email"]
|
||||
end)
|
||||
|> unique_constraint(:nickname)
|
||||
|> validate_exclusion(:nickname, Config.get([User, :restricted_nicknames]))
|
||||
|> validate_format(:nickname, local_nickname_regex())
|
||||
|> validate_format(:email, @email_regex)
|
||||
|> validate_length(:bio, max: bio_limit)
|
||||
|> validate_length(:name, min: 1, max: name_limit)
|
||||
|> validate_length(:registration_reason, max: reason_limit)
|
||||
|> maybe_validate_required_email(opts[:external])
|
||||
|> put_password_hash
|
||||
|> put_ap_id()
|
||||
|
@ -713,27 +741,62 @@ def register(%Ecto.Changeset{} = changeset) do
|
|||
def post_register_action(%User{} = user) do
|
||||
with {:ok, user} <- autofollow_users(user),
|
||||
{:ok, user} <- set_cache(user),
|
||||
{:ok, _} <- User.WelcomeMessage.post_welcome_message_to_user(user),
|
||||
{:ok, _} <- send_welcome_email(user),
|
||||
{:ok, _} <- send_welcome_message(user),
|
||||
{:ok, _} <- send_welcome_chat_message(user),
|
||||
{:ok, _} <- try_send_confirmation_email(user) do
|
||||
{:ok, user}
|
||||
end
|
||||
end
|
||||
|
||||
def try_send_confirmation_email(%User{} = user) do
|
||||
if user.confirmation_pending &&
|
||||
Config.get([:instance, :account_activation_required]) do
|
||||
user
|
||||
|> Pleroma.Emails.UserEmail.account_confirmation_email()
|
||||
|> Pleroma.Emails.Mailer.deliver_async()
|
||||
|
||||
def send_welcome_message(user) do
|
||||
if User.WelcomeMessage.enabled?() do
|
||||
User.WelcomeMessage.post_message(user)
|
||||
{:ok, :enqueued}
|
||||
else
|
||||
{:ok, :noop}
|
||||
end
|
||||
end
|
||||
|
||||
def try_send_confirmation_email(users) do
|
||||
Enum.each(users, &try_send_confirmation_email/1)
|
||||
def send_welcome_chat_message(user) do
|
||||
if User.WelcomeChatMessage.enabled?() do
|
||||
User.WelcomeChatMessage.post_message(user)
|
||||
{:ok, :enqueued}
|
||||
else
|
||||
{:ok, :noop}
|
||||
end
|
||||
end
|
||||
|
||||
def send_welcome_email(%User{email: email} = user) when is_binary(email) do
|
||||
if User.WelcomeEmail.enabled?() do
|
||||
User.WelcomeEmail.send_email(user)
|
||||
{:ok, :enqueued}
|
||||
else
|
||||
{:ok, :noop}
|
||||
end
|
||||
end
|
||||
|
||||
def send_welcome_email(_), do: {:ok, :noop}
|
||||
|
||||
@spec try_send_confirmation_email(User.t()) :: {:ok, :enqueued | :noop}
|
||||
def try_send_confirmation_email(%User{confirmation_pending: true} = user) do
|
||||
if Config.get([:instance, :account_activation_required]) do
|
||||
send_confirmation_email(user)
|
||||
{:ok, :enqueued}
|
||||
else
|
||||
{:ok, :noop}
|
||||
end
|
||||
end
|
||||
|
||||
def try_send_confirmation_email(_), do: {:ok, :noop}
|
||||
|
||||
@spec send_confirmation_email(Uset.t()) :: User.t()
|
||||
def send_confirmation_email(%User{} = user) do
|
||||
user
|
||||
|> Pleroma.Emails.UserEmail.account_confirmation_email()
|
||||
|> Pleroma.Emails.Mailer.deliver_async()
|
||||
|
||||
user
|
||||
end
|
||||
|
||||
def needs_update?(%User{local: true}), do: false
|
||||
|
@ -1469,6 +1532,19 @@ def deactivate(%User{} = user, status) do
|
|||
end
|
||||
end
|
||||
|
||||
def approve(users) when is_list(users) do
|
||||
Repo.transaction(fn ->
|
||||
Enum.map(users, fn user ->
|
||||
with {:ok, user} <- approve(user), do: user
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
def approve(%User{} = user) do
|
||||
change(user, approval_pending: false)
|
||||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
def update_notification_settings(%User{} = user, settings) do
|
||||
user
|
||||
|> cast(%{notification_settings: settings}, [])
|
||||
|
@ -1495,12 +1571,17 @@ defp delete_or_deactivate(%User{local: false} = user), do: delete_and_invalidate
|
|||
defp delete_or_deactivate(%User{local: true} = user) do
|
||||
status = account_status(user)
|
||||
|
||||
if status == :confirmation_pending do
|
||||
delete_and_invalidate_cache(user)
|
||||
else
|
||||
user
|
||||
|> change(%{deactivated: true, email: nil})
|
||||
|> update_and_set_cache()
|
||||
case status do
|
||||
:confirmation_pending ->
|
||||
delete_and_invalidate_cache(user)
|
||||
|
||||
:approval_pending ->
|
||||
delete_and_invalidate_cache(user)
|
||||
|
||||
_ ->
|
||||
user
|
||||
|> change(%{deactivated: true, email: nil})
|
||||
|> update_and_set_cache()
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2153,6 +2234,12 @@ def confirmation_changeset(user, need_confirmation: need_confirmation?) do
|
|||
cast(user, params, [:confirmation_pending, :confirmation_token])
|
||||
end
|
||||
|
||||
@spec approval_changeset(User.t(), keyword()) :: Changeset.t()
|
||||
def approval_changeset(user, need_approval: need_approval?) do
|
||||
params = if need_approval?, do: %{approval_pending: true}, else: %{approval_pending: false}
|
||||
cast(user, params, [:approval_pending])
|
||||
end
|
||||
|
||||
def add_pinnned_activity(user, %Pleroma.Activity{id: id}) do
|
||||
if id not in user.pinned_activities do
|
||||
max_pinned_statuses = Config.get([:instance, :max_pinned_statuses], 0)
|
||||
|
|
|
@ -42,6 +42,7 @@ defmodule Pleroma.User.Query do
|
|||
external: boolean(),
|
||||
active: boolean(),
|
||||
deactivated: boolean(),
|
||||
need_approval: boolean(),
|
||||
is_admin: boolean(),
|
||||
is_moderator: boolean(),
|
||||
super_users: boolean(),
|
||||
|
@ -146,6 +147,10 @@ defp compose_query({:deactivated, true}, query) do
|
|||
|> where([u], not is_nil(u.nickname))
|
||||
end
|
||||
|
||||
defp compose_query({:need_approval, _}, query) do
|
||||
where(query, [u], u.approval_pending)
|
||||
end
|
||||
|
||||
defp compose_query({:followers, %User{id: id}}, query) do
|
||||
query
|
||||
|> where([u], u.id != ^id)
|
||||
|
|
45
lib/pleroma/user/welcome_chat_message.ex
Normal file
45
lib/pleroma/user/welcome_chat_message.ex
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.User.WelcomeChatMessage do
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
@spec enabled?() :: boolean()
|
||||
def enabled?, do: Config.get([:welcome, :chat_message, :enabled], false)
|
||||
|
||||
@spec post_message(User.t()) :: {:ok, Pleroma.Activity.t() | nil}
|
||||
def post_message(user) do
|
||||
[:welcome, :chat_message, :sender_nickname]
|
||||
|> Config.get(nil)
|
||||
|> fetch_sender()
|
||||
|> do_post(user, welcome_message())
|
||||
end
|
||||
|
||||
defp do_post(%User{} = sender, recipient, message)
|
||||
when is_binary(message) do
|
||||
CommonAPI.post_chat_message(
|
||||
sender,
|
||||
recipient,
|
||||
message
|
||||
)
|
||||
end
|
||||
|
||||
defp do_post(_sender, _recipient, _message), do: {:ok, nil}
|
||||
|
||||
defp fetch_sender(nickname) when is_binary(nickname) do
|
||||
with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
|
||||
user
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp fetch_sender(_), do: nil
|
||||
|
||||
defp welcome_message do
|
||||
Config.get([:welcome, :chat_message, :message], nil)
|
||||
end
|
||||
end
|
62
lib/pleroma/user/welcome_email.ex
Normal file
62
lib/pleroma/user/welcome_email.ex
Normal file
|
@ -0,0 +1,62 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.User.WelcomeEmail do
|
||||
@moduledoc """
|
||||
The module represents the functions to send welcome email.
|
||||
"""
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Emails
|
||||
alias Pleroma.User
|
||||
|
||||
import Pleroma.Config.Helpers, only: [instance_name: 0]
|
||||
|
||||
@spec enabled?() :: boolean()
|
||||
def enabled?, do: Config.get([:welcome, :email, :enabled], false)
|
||||
|
||||
@spec send_email(User.t()) :: {:ok, Oban.Job.t()}
|
||||
def send_email(%User{} = user) do
|
||||
user
|
||||
|> Emails.UserEmail.welcome(email_options(user))
|
||||
|> Emails.Mailer.deliver_async()
|
||||
end
|
||||
|
||||
defp email_options(user) do
|
||||
bindings = [user: user, instance_name: instance_name()]
|
||||
|
||||
%{}
|
||||
|> add_sender(Config.get([:welcome, :email, :sender], nil))
|
||||
|> add_option(:subject, bindings)
|
||||
|> add_option(:html, bindings)
|
||||
|> add_option(:text, bindings)
|
||||
end
|
||||
|
||||
defp add_option(opts, option, bindings) do
|
||||
[:welcome, :email, option]
|
||||
|> Config.get(nil)
|
||||
|> eval_string(bindings)
|
||||
|> merge_options(opts, option)
|
||||
end
|
||||
|
||||
defp add_sender(opts, {_name, _email} = sender) do
|
||||
merge_options(sender, opts, :sender)
|
||||
end
|
||||
|
||||
defp add_sender(opts, sender) when is_binary(sender) do
|
||||
add_sender(opts, {instance_name(), sender})
|
||||
end
|
||||
|
||||
defp add_sender(opts, _), do: opts
|
||||
|
||||
defp merge_options(nil, options, _option), do: options
|
||||
|
||||
defp merge_options(value, options, option) do
|
||||
Map.merge(options, %{option => value})
|
||||
end
|
||||
|
||||
defp eval_string(nil, _), do: nil
|
||||
defp eval_string("", _), do: nil
|
||||
defp eval_string(str, bindings), do: EEx.eval_string(str, bindings)
|
||||
end
|
|
@ -3,32 +3,45 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.User.WelcomeMessage do
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
def post_welcome_message_to_user(user) do
|
||||
with %User{} = sender_user <- welcome_user(),
|
||||
message when is_binary(message) <- welcome_message() do
|
||||
CommonAPI.post(sender_user, %{
|
||||
visibility: "direct",
|
||||
status: "@#{user.nickname}\n#{message}"
|
||||
})
|
||||
else
|
||||
_ -> {:ok, nil}
|
||||
end
|
||||
@spec enabled?() :: boolean()
|
||||
def enabled?, do: Config.get([:welcome, :direct_message, :enabled], false)
|
||||
|
||||
@spec post_message(User.t()) :: {:ok, Pleroma.Activity.t() | nil}
|
||||
def post_message(user) do
|
||||
[:welcome, :direct_message, :sender_nickname]
|
||||
|> Config.get(nil)
|
||||
|> fetch_sender()
|
||||
|> do_post(user, welcome_message())
|
||||
end
|
||||
|
||||
defp welcome_user do
|
||||
with nickname when is_binary(nickname) <-
|
||||
Pleroma.Config.get([:instance, :welcome_user_nickname]),
|
||||
%User{local: true} = user <- User.get_cached_by_nickname(nickname) do
|
||||
defp do_post(%User{} = sender, %User{nickname: nickname}, message)
|
||||
when is_binary(message) do
|
||||
CommonAPI.post(
|
||||
sender,
|
||||
%{
|
||||
visibility: "direct",
|
||||
status: "@#{nickname}\n#{message}"
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
defp do_post(_sender, _recipient, _message), do: {:ok, nil}
|
||||
|
||||
defp fetch_sender(nickname) when is_binary(nickname) do
|
||||
with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
|
||||
user
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp fetch_sender(_), do: nil
|
||||
|
||||
defp welcome_message do
|
||||
Pleroma.Config.get([:instance, :welcome_message])
|
||||
Config.get([:welcome, :direct_message, :message], nil)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1365,6 +1365,10 @@ def fetch_and_prepare_user_from_ap_id(ap_id) do
|
|||
Logger.debug("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
|
||||
{:error, e}
|
||||
|
||||
{:error, {:reject, reason} = e} ->
|
||||
Logger.info("Rejected user #{ap_id}: #{inspect(reason)}")
|
||||
{:error, e}
|
||||
|
||||
{:error, e} ->
|
||||
Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
|
||||
{:error, e}
|
||||
|
|
|
@ -21,8 +21,8 @@ def filter(activity) do
|
|||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
||||
defp local?(%{"id" => id}) do
|
||||
String.starts_with?(id, Pleroma.Web.Endpoint.url())
|
||||
defp local?(%{"actor" => actor}) do
|
||||
String.starts_with?(actor, Pleroma.Web.Endpoint.url())
|
||||
end
|
||||
|
||||
defp note?(activity) do
|
||||
|
|
|
@ -27,7 +27,8 @@ def filter_by_summary(
|
|||
|
||||
def filter_by_summary(_in_reply_to, child), do: child
|
||||
|
||||
def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||
def filter(%{"type" => "Create", "object" => child_object} = object)
|
||||
when is_map(child_object) do
|
||||
child =
|
||||
child_object["inReplyTo"]
|
||||
|> Object.normalize(child_object["inReplyTo"])
|
||||
|
|
|
@ -37,8 +37,13 @@ defp check_reject(message, actions) do
|
|||
defp check_delist(message, actions) do
|
||||
if :delist in actions do
|
||||
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
||||
to = List.delete(message["to"], Pleroma.Constants.as_public()) ++ [user.follower_address]
|
||||
cc = List.delete(message["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()]
|
||||
to =
|
||||
List.delete(message["to"] || [], Pleroma.Constants.as_public()) ++
|
||||
[user.follower_address]
|
||||
|
||||
cc =
|
||||
List.delete(message["cc"] || [], user.follower_address) ++
|
||||
[Pleroma.Constants.as_public()]
|
||||
|
||||
message =
|
||||
message
|
||||
|
@ -58,8 +63,8 @@ defp check_delist(message, actions) do
|
|||
defp check_strip_followers(message, actions) do
|
||||
if :strip_followers in actions do
|
||||
with %User{} = user <- User.get_cached_by_ap_id(message["actor"]) do
|
||||
to = List.delete(message["to"], user.follower_address)
|
||||
cc = List.delete(message["cc"], user.follower_address)
|
||||
to = List.delete(message["to"] || [], user.follower_address)
|
||||
cc = List.delete(message["cc"] || [], user.follower_address)
|
||||
|
||||
message =
|
||||
message
|
||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.FollowingRelationship
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
|
@ -108,6 +109,35 @@ defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
|
|||
{:ok, object}
|
||||
end
|
||||
|
||||
defp intersection(list1, list2) do
|
||||
list1 -- list1 -- list2
|
||||
end
|
||||
|
||||
defp check_followers_only(%{host: actor_host} = _actor_info, object) do
|
||||
followers_only =
|
||||
Config.get([:mrf_simple, :followers_only])
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
with true <- MRF.subdomain_match?(followers_only, actor_host),
|
||||
user <- User.get_cached_by_ap_id(object["actor"]) do
|
||||
# Don't use Map.get/3 intentionally, these must not be nil
|
||||
fixed_to = object["to"] || []
|
||||
fixed_cc = object["cc"] || []
|
||||
|
||||
to = FollowingRelationship.followers_ap_ids(user, fixed_to)
|
||||
cc = FollowingRelationship.followers_ap_ids(user, fixed_cc)
|
||||
|
||||
object
|
||||
|> Map.put("to", intersection([user.follower_address | to], fixed_to))
|
||||
|> Map.put("cc", intersection([user.follower_address | cc], fixed_cc))
|
||||
else
|
||||
_ -> object
|
||||
end
|
||||
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do
|
||||
report_removal =
|
||||
Config.get([:mrf_simple, :report_removal])
|
||||
|
@ -174,6 +204,7 @@ def filter(%{"actor" => actor} = object) do
|
|||
{:ok, object} <- check_media_removal(actor_info, object),
|
||||
{:ok, object} <- check_media_nsfw(actor_info, object),
|
||||
{:ok, object} <- check_ftl_removal(actor_info, object),
|
||||
{:ok, object} <- check_followers_only(actor_info, object),
|
||||
{:ok, object} <- check_report_removal(actor_info, object) do
|
||||
{:ok, object}
|
||||
else
|
||||
|
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
the system.
|
||||
"""
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
|
@ -71,6 +72,12 @@ def validate(%{"type" => "Undo"} = object, meta) do
|
|||
|> UndoValidator.cast_and_validate()
|
||||
|> Ecto.Changeset.apply_action(:insert) do
|
||||
object = stringify_keys(object)
|
||||
undone_object = Activity.get_by_ap_id(object["object"])
|
||||
|
||||
meta =
|
||||
meta
|
||||
|> Keyword.put(:object_data, undone_object.data)
|
||||
|
||||
{:ok, object, meta}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,10 +34,15 @@ def validate_actor_presence(cng, options \\ []) do
|
|||
|
||||
cng
|
||||
|> validate_change(field_name, fn field_name, actor ->
|
||||
if User.get_cached_by_ap_id(actor) do
|
||||
[]
|
||||
else
|
||||
[{field_name, "can't find user"}]
|
||||
case User.get_cached_by_ap_id(actor) do
|
||||
%User{deactivated: true} ->
|
||||
[{field_name, "user is deactivated"}]
|
||||
|
||||
%User{} ->
|
||||
[]
|
||||
|
||||
_ ->
|
||||
[{field_name, "can't find user"}]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
@ -52,6 +52,13 @@ defp maybe_federate(%Activity{} = activity, meta) do
|
|||
do_not_federate = meta[:do_not_federate] || !Config.get([:instance, :federating])
|
||||
|
||||
if !do_not_federate && local do
|
||||
activity =
|
||||
if object = Keyword.get(meta, :object_data) do
|
||||
%{activity | data: Map.put(activity.data, "object", object)}
|
||||
else
|
||||
activity
|
||||
end
|
||||
|
||||
Federator.publish(activity)
|
||||
{:ok, :federated}
|
||||
else
|
||||
|
|
|
@ -178,7 +178,7 @@ def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options)
|
|||
|> Map.drop(["conversation"])
|
||||
else
|
||||
e ->
|
||||
Logger.error("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}")
|
||||
Logger.warn("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}")
|
||||
object
|
||||
end
|
||||
else
|
||||
|
|
|
@ -719,15 +719,18 @@ defp build_flag_object(act) when is_map(act) or is_binary(act) do
|
|||
|
||||
case Activity.get_by_ap_id_with_object(id) do
|
||||
%Activity{} = activity ->
|
||||
activity_actor = User.get_by_ap_id(activity.object.data["actor"])
|
||||
|
||||
%{
|
||||
"type" => "Note",
|
||||
"id" => activity.data["id"],
|
||||
"content" => activity.object.data["content"],
|
||||
"published" => activity.object.data["published"],
|
||||
"actor" =>
|
||||
AccountView.render("show.json", %{
|
||||
user: User.get_by_ap_id(activity.object.data["actor"])
|
||||
})
|
||||
AccountView.render(
|
||||
"show.json",
|
||||
%{user: activity_actor, skip_visibility_check: true}
|
||||
)
|
||||
}
|
||||
|
||||
_ ->
|
||||
|
|
|
@ -44,6 +44,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
:user_toggle_activation,
|
||||
:user_activate,
|
||||
:user_deactivate,
|
||||
:user_approve,
|
||||
:tag_users,
|
||||
:untag_users,
|
||||
:right_add,
|
||||
|
@ -303,6 +304,21 @@ def user_deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nickname
|
|||
|> render("index.json", %{users: Keyword.values(updated_users)})
|
||||
end
|
||||
|
||||
def user_approve(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
{:ok, updated_users} = User.approve(users)
|
||||
|
||||
ModerationLog.insert_log(%{
|
||||
actor: admin,
|
||||
subject: users,
|
||||
action: "approve"
|
||||
})
|
||||
|
||||
conn
|
||||
|> put_view(AccountView)
|
||||
|> render("index.json", %{users: updated_users})
|
||||
end
|
||||
|
||||
def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
|
||||
with {:ok, _} <- User.tag(nicknames, tags) do
|
||||
ModerationLog.insert_log(%{
|
||||
|
@ -345,12 +361,16 @@ def list_users(conn, params) do
|
|||
with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)) do
|
||||
json(
|
||||
conn,
|
||||
AccountView.render("index.json", users: users, count: count, page_size: page_size)
|
||||
AccountView.render("index.json",
|
||||
users: users,
|
||||
count: count,
|
||||
page_size: page_size
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@filters ~w(local external active deactivated is_admin is_moderator)
|
||||
@filters ~w(local external active deactivated need_approval is_admin is_moderator)
|
||||
|
||||
@spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
|
||||
defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
|
||||
|
@ -616,29 +636,24 @@ def reload_emoji(conn, _params) do
|
|||
end
|
||||
|
||||
def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
|
||||
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
|
||||
User.toggle_confirmation(users)
|
||||
|
||||
ModerationLog.insert_log(%{
|
||||
actor: admin,
|
||||
subject: users,
|
||||
action: "confirm_email"
|
||||
})
|
||||
ModerationLog.insert_log(%{actor: admin, subject: users, action: "confirm_email"})
|
||||
|
||||
json(conn, "")
|
||||
end
|
||||
|
||||
def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
|
||||
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
|
||||
users =
|
||||
Enum.map(nicknames, fn nickname ->
|
||||
nickname
|
||||
|> User.get_cached_by_nickname()
|
||||
|> User.send_confirmation_email()
|
||||
end)
|
||||
|
||||
User.try_send_confirmation_email(users)
|
||||
|
||||
ModerationLog.insert_log(%{
|
||||
actor: admin,
|
||||
subject: users,
|
||||
action: "resend_confirmation_email"
|
||||
})
|
||||
ModerationLog.insert_log(%{actor: admin, subject: users, action: "resend_confirmation_email"})
|
||||
|
||||
json(conn, "")
|
||||
end
|
||||
|
|
|
@ -77,7 +77,9 @@ def render("show.json", %{user: user}) do
|
|||
"roles" => User.roles(user),
|
||||
"tags" => user.tags || [],
|
||||
"confirmation_pending" => user.confirmation_pending,
|
||||
"url" => user.uri || user.ap_id
|
||||
"approval_pending" => user.approval_pending,
|
||||
"url" => user.uri || user.ap_id,
|
||||
"registration_reason" => user.registration_reason
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -105,7 +107,7 @@ def render("create-error.json", %{changeset: %Ecto.Changeset{changes: changes, e
|
|||
end
|
||||
|
||||
def merge_account_views(%User{} = user) do
|
||||
MastodonAPI.AccountView.render("show.json", %{user: user})
|
||||
MastodonAPI.AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
||||
|> Map.merge(AdminAPI.AccountView.render("show.json", %{user: user}))
|
||||
end
|
||||
|
||||
|
|
|
@ -449,21 +449,32 @@ defp create_request do
|
|||
}
|
||||
end
|
||||
|
||||
# TODO: This is actually a token respone, but there's no oauth operation file yet.
|
||||
# Note: this is a token response (if login succeeds!), but there's no oauth operation file yet.
|
||||
defp create_response do
|
||||
%Schema{
|
||||
title: "AccountCreateResponse",
|
||||
description: "Response schema for an account",
|
||||
type: :object,
|
||||
properties: %{
|
||||
# The response when auto-login on create succeeds (token is issued):
|
||||
token_type: %Schema{type: :string},
|
||||
access_token: %Schema{type: :string},
|
||||
refresh_token: %Schema{type: :string},
|
||||
scope: %Schema{type: :string},
|
||||
created_at: %Schema{type: :integer, format: :"date-time"},
|
||||
me: %Schema{type: :string},
|
||||
expires_in: %Schema{type: :integer}
|
||||
expires_in: %Schema{type: :integer},
|
||||
#
|
||||
# The response when registration succeeds but auto-login fails (no token):
|
||||
identifier: %Schema{type: :string},
|
||||
message: %Schema{type: :string}
|
||||
},
|
||||
required: [],
|
||||
# Note: example of successful registration with failed login response:
|
||||
# example: %{
|
||||
# "identifier" => "missing_confirmed_email",
|
||||
# "message" => "You have been registered. Please check your email for further instructions."
|
||||
# },
|
||||
example: %{
|
||||
"token_type" => "Bearer",
|
||||
"access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
|
||||
|
|
|
@ -300,11 +300,11 @@ def chat_messages_response do
|
|||
"content" => "Check this out :firefox:",
|
||||
"id" => "13",
|
||||
"chat_id" => "1",
|
||||
"actor_id" => "someflakeid",
|
||||
"account_id" => "someflakeid",
|
||||
"unread" => false
|
||||
},
|
||||
%{
|
||||
"actor_id" => "someflakeid",
|
||||
"account_id" => "someflakeid",
|
||||
"content" => "Whats' up?",
|
||||
"id" => "12",
|
||||
"chat_id" => "1",
|
||||
|
|
|
@ -31,6 +31,7 @@ def index_operation do
|
|||
}
|
||||
end
|
||||
|
||||
# Supporting domain query parameter is deprecated in Mastodon API
|
||||
def create_operation do
|
||||
%Operation{
|
||||
tags: ["domain_blocks"],
|
||||
|
@ -45,11 +46,13 @@ def create_operation do
|
|||
""",
|
||||
operationId: "DomainBlockController.create",
|
||||
requestBody: domain_block_request(),
|
||||
parameters: [Operation.parameter(:domain, :query, %Schema{type: :string}, "Domain name")],
|
||||
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
||||
responses: %{200 => empty_object_response()}
|
||||
}
|
||||
end
|
||||
|
||||
# Supporting domain query parameter is deprecated in Mastodon API
|
||||
def delete_operation do
|
||||
%Operation{
|
||||
tags: ["domain_blocks"],
|
||||
|
@ -57,6 +60,7 @@ def delete_operation do
|
|||
description: "Remove a domain block, if it exists in the user's array of blocked domains.",
|
||||
operationId: "DomainBlockController.delete",
|
||||
requestBody: domain_block_request(),
|
||||
parameters: [Operation.parameter(:domain, :query, %Schema{type: :string}, "Domain name")],
|
||||
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
||||
|
@ -71,10 +75,9 @@ defp domain_block_request do
|
|||
type: :object,
|
||||
properties: %{
|
||||
domain: %Schema{type: :string}
|
||||
},
|
||||
required: [:domain]
|
||||
}
|
||||
},
|
||||
required: true,
|
||||
required: false,
|
||||
example: %{
|
||||
"domain" => "facebook.com"
|
||||
}
|
||||
|
|
|
@ -19,13 +19,46 @@ defmodule Pleroma.Web.ApiSpec.Schemas.ChatMessage do
|
|||
content: %Schema{type: :string, nullable: true},
|
||||
created_at: %Schema{type: :string, format: :"date-time"},
|
||||
emojis: %Schema{type: :array},
|
||||
attachment: %Schema{type: :object, nullable: true}
|
||||
attachment: %Schema{type: :object, nullable: true},
|
||||
card: %Schema{
|
||||
type: :object,
|
||||
nullable: true,
|
||||
description: "Preview card for links included within status content",
|
||||
required: [:url, :title, :description, :type],
|
||||
properties: %{
|
||||
type: %Schema{
|
||||
type: :string,
|
||||
enum: ["link", "photo", "video", "rich"],
|
||||
description: "The type of the preview card"
|
||||
},
|
||||
provider_name: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
description: "The provider of the original resource"
|
||||
},
|
||||
provider_url: %Schema{
|
||||
type: :string,
|
||||
format: :uri,
|
||||
description: "A link to the provider of the original resource"
|
||||
},
|
||||
url: %Schema{type: :string, format: :uri, description: "Location of linked resource"},
|
||||
image: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
format: :uri,
|
||||
description: "Preview thumbnail"
|
||||
},
|
||||
title: %Schema{type: :string, description: "Title of linked resource"},
|
||||
description: %Schema{type: :string, description: "Description of preview"}
|
||||
}
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
"account_id" => "someflakeid",
|
||||
"chat_id" => "1",
|
||||
"content" => "hey you again",
|
||||
"created_at" => "2020-04-21T15:06:45.000Z",
|
||||
"card" => nil,
|
||||
"emojis" => [
|
||||
%{
|
||||
"static_url" => "https://dontbulling.me/emoji/Firefox.gif",
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
defmodule Pleroma.Web.ChatChannel do
|
||||
use Phoenix.Channel
|
||||
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ChatChannel.ChatChannelState
|
||||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
|
||||
def join("chat:public", _message, socket) do
|
||||
send(self(), :after_join)
|
||||
|
@ -22,9 +24,9 @@ def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}}
|
|||
|
||||
if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do
|
||||
author = User.get_cached_by_nickname(user_name)
|
||||
author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author)
|
||||
author_json = AccountView.render("show.json", user: author, skip_visibility_check: true)
|
||||
|
||||
message = ChatChannelState.add_message(%{text: text, author: author})
|
||||
message = ChatChannelState.add_message(%{text: text, author: author_json})
|
||||
|
||||
broadcast!(socket, "new_msg", message)
|
||||
end
|
||||
|
|
|
@ -28,6 +28,17 @@ defmodule Pleroma.Web.Endpoint do
|
|||
}
|
||||
)
|
||||
|
||||
# Careful! No `only` restriction here, as we don't know what frontends contain.
|
||||
plug(Pleroma.Plugs.FrontendStatic,
|
||||
at: "/",
|
||||
frontend_type: :primary,
|
||||
gzip: true,
|
||||
cache_control_for_etags: @static_cache_control,
|
||||
headers: %{
|
||||
"cache-control" => @static_cache_control
|
||||
}
|
||||
)
|
||||
|
||||
# Serve at "/" the static files from "priv/static" directory.
|
||||
#
|
||||
# You should set gzip to true if you are running phoenix.digest
|
||||
|
|
|
@ -47,7 +47,7 @@ def feed(conn, %{"nickname" => nickname} = params) do
|
|||
"atom"
|
||||
end
|
||||
|
||||
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
|
||||
with {_, %User{local: true} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
|
||||
activities =
|
||||
%{
|
||||
type: ["Create"],
|
||||
|
@ -71,6 +71,7 @@ def errors(conn, {:error, :not_found}) do
|
|||
render_error(conn, :not_found, "Not found")
|
||||
end
|
||||
|
||||
def errors(conn, {:fetch_user, %User{local: false}}), do: errors(conn, {:error, :not_found})
|
||||
def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
|
||||
|
||||
def errors(conn, _) do
|
||||
|
|
|
@ -27,8 +27,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPIController
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
alias Pleroma.Web.OAuth.OAuthController
|
||||
alias Pleroma.Web.OAuth.OAuthView
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
|
@ -100,11 +100,34 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
def create(%{assigns: %{app: app}, body_params: params} = conn, _params) do
|
||||
with :ok <- validate_email_param(params),
|
||||
:ok <- TwitterAPI.validate_captcha(app, params),
|
||||
{:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
|
||||
{:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
|
||||
{:ok, user} <- TwitterAPI.register_user(params),
|
||||
{_, {:ok, token}} <-
|
||||
{:login, OAuthController.login(user, app, app.scopes)} do
|
||||
json(conn, OAuthView.render("token.json", %{user: user, token: token}))
|
||||
else
|
||||
{:error, error} -> json_response(conn, :bad_request, %{error: error})
|
||||
{:login, {:account_status, :confirmation_pending}} ->
|
||||
json_response(conn, :ok, %{
|
||||
message: "You have been registered. Please check your email for further instructions.",
|
||||
identifier: "missing_confirmed_email"
|
||||
})
|
||||
|
||||
{:login, {:account_status, :approval_pending}} ->
|
||||
json_response(conn, :ok, %{
|
||||
message:
|
||||
"You have been registered. You'll be able to log in once your account is approved.",
|
||||
identifier: "awaiting_approval"
|
||||
})
|
||||
|
||||
{:login, _} ->
|
||||
json_response(conn, :ok, %{
|
||||
message:
|
||||
"You have been registered. Some post-registration steps may be pending. " <>
|
||||
"Please log in manually.",
|
||||
identifier: "manual_login_required"
|
||||
})
|
||||
|
||||
{:error, error} ->
|
||||
json_response(conn, :bad_request, %{error: error})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -32,9 +32,19 @@ def create(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn,
|
|||
json(conn, %{})
|
||||
end
|
||||
|
||||
def create(%{assigns: %{user: blocker}} = conn, %{domain: domain}) do
|
||||
User.block_domain(blocker, domain)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
@doc "DELETE /api/v1/domain_blocks"
|
||||
def delete(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
|
||||
User.unblock_domain(blocker, domain)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
def delete(%{assigns: %{user: blocker}} = conn, %{domain: domain}) do
|
||||
User.unblock_domain(blocker, domain)
|
||||
json(conn, %{})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -93,7 +93,6 @@ defp resource_search(_, "accounts", query, options) do
|
|||
AccountView.render("index.json",
|
||||
users: accounts,
|
||||
for: options[:for_user],
|
||||
as: :user,
|
||||
embed_relationships: options[:embed_relationships]
|
||||
)
|
||||
end
|
||||
|
|
|
@ -314,7 +314,8 @@ def card(%{assigns: %{user: user}} = conn, %{id: status_id}) do
|
|||
|
||||
@doc "GET /api/v1/statuses/:id/favourited_by"
|
||||
def favourited_by(%{assigns: %{user: user}} = conn, %{id: id}) do
|
||||
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||
with true <- Pleroma.Config.get([:instance, :show_reactions]),
|
||||
%Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||
{:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
|
||||
%Object{data: %{"likes" => likes}} <- Object.normalize(activity) do
|
||||
users =
|
||||
|
|
|
@ -27,21 +27,40 @@ def render("index.json", %{users: users} = opts) do
|
|||
UserRelationship.view_relationships_option(reading_user, users)
|
||||
end
|
||||
|
||||
opts = Map.put(opts, :relationships, relationships_opt)
|
||||
opts =
|
||||
opts
|
||||
|> Map.merge(%{relationships: relationships_opt, as: :user})
|
||||
|> Map.delete(:users)
|
||||
|
||||
users
|
||||
|> render_many(AccountView, "show.json", opts)
|
||||
|> Enum.filter(&Enum.any?/1)
|
||||
end
|
||||
|
||||
def render("show.json", %{user: user} = opts) do
|
||||
if User.visible_for(user, opts[:for]) == :visible do
|
||||
@doc """
|
||||
Renders specified user account.
|
||||
:skip_visibility_check option skips visibility check and renders any user (local or remote)
|
||||
regardless of [:pleroma, :restrict_unauthenticated] setting.
|
||||
:for option specifies the requester and can be a User record or nil.
|
||||
Only use `user: user, for: user` when `user` is the actual requester of own profile.
|
||||
"""
|
||||
def render("show.json", %{user: _user, skip_visibility_check: true} = opts) do
|
||||
do_render("show.json", opts)
|
||||
end
|
||||
|
||||
def render("show.json", %{user: user, for: for_user_or_nil} = opts) do
|
||||
if User.visible_for(user, for_user_or_nil) == :visible do
|
||||
do_render("show.json", opts)
|
||||
else
|
||||
%{}
|
||||
end
|
||||
end
|
||||
|
||||
def render("show.json", _) do
|
||||
raise "In order to prevent account accessibility issues, " <>
|
||||
":skip_visibility_check or :for option is required."
|
||||
end
|
||||
|
||||
def render("mention.json", %{user: user}) do
|
||||
%{
|
||||
id: to_string(user.id),
|
||||
|
|
|
@ -38,7 +38,7 @@ def render("participation.json", %{participation: participation, for: user}) do
|
|||
|
||||
%{
|
||||
id: participation.id |> to_string(),
|
||||
accounts: render(AccountView, "index.json", users: users, as: :user),
|
||||
accounts: render(AccountView, "index.json", users: users, for: user),
|
||||
unread: !participation.read,
|
||||
last_status:
|
||||
render(StatusView, "show.json",
|
||||
|
|
|
@ -26,6 +26,7 @@ def render("show.json", _) do
|
|||
thumbnail: Keyword.get(instance, :instance_thumbnail),
|
||||
languages: ["en"],
|
||||
registrations: Keyword.get(instance, :registrations_open),
|
||||
approval_required: Keyword.get(instance, :account_approval_required),
|
||||
# Extra (not present in Mastodon):
|
||||
max_toot_chars: Keyword.get(instance, :limit),
|
||||
poll_limits: Keyword.get(instance, :poll_limits),
|
||||
|
|
|
@ -297,13 +297,17 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
|||
|
||||
emoji_reactions =
|
||||
with %{data: %{"reactions" => emoji_reactions}} <- object do
|
||||
Enum.map(emoji_reactions, fn [emoji, users] ->
|
||||
%{
|
||||
name: emoji,
|
||||
count: length(users),
|
||||
me: !!(opts[:for] && opts[:for].ap_id in users)
|
||||
}
|
||||
Enum.map(emoji_reactions, fn
|
||||
[emoji, users] when is_list(users) ->
|
||||
build_emoji_map(emoji, users, opts[:for])
|
||||
|
||||
{emoji, users} when is_list(users) ->
|
||||
build_emoji_map(emoji, users, opts[:for])
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
else
|
||||
_ -> []
|
||||
end
|
||||
|
@ -545,4 +549,12 @@ defp present?(_), do: true
|
|||
|
||||
defp pinned?(%Activity{id: id}, %User{pinned_activities: pinned_activities}),
|
||||
do: id in pinned_activities
|
||||
|
||||
defp build_emoji_map(emoji, users, current_user) do
|
||||
%{
|
||||
name: emoji,
|
||||
count: length(users),
|
||||
me: !!(current_user && current_user.ap_id in users)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -260,11 +260,8 @@ def token_exchange(
|
|||
) do
|
||||
with {:ok, %User{} = user} <- Authenticator.get_user(conn),
|
||||
{:ok, app} <- Token.Utils.fetch_app(conn),
|
||||
{:account_status, :active} <- {:account_status, User.account_status(user)},
|
||||
{:ok, scopes} <- validate_scopes(app, params),
|
||||
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
|
||||
{:mfa_required, _, _, false} <- {:mfa_required, user, auth, MFA.require?(user)},
|
||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||
requested_scopes <- Scopes.fetch_scopes(params, app.scopes),
|
||||
{:ok, token} <- login(user, app, requested_scopes) do
|
||||
json(conn, OAuthView.render("token.json", %{user: user, token: token}))
|
||||
else
|
||||
error ->
|
||||
|
@ -337,6 +334,16 @@ defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :confirm
|
|||
)
|
||||
end
|
||||
|
||||
defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :approval_pending}) do
|
||||
render_error(
|
||||
conn,
|
||||
:forbidden,
|
||||
"Your account is awaiting approval.",
|
||||
%{},
|
||||
"awaiting_approval"
|
||||
)
|
||||
end
|
||||
|
||||
defp handle_token_exchange_error(%Plug.Conn{} = conn, _error) do
|
||||
render_invalid_credentials_error(conn)
|
||||
end
|
||||
|
@ -512,6 +519,8 @@ def register(%Plug.Conn{} = conn, %{"authorization" => _, "op" => "register"} =
|
|||
end
|
||||
end
|
||||
|
||||
defp do_create_authorization(conn, auth_attrs, user \\ nil)
|
||||
|
||||
defp do_create_authorization(
|
||||
%Plug.Conn{} = conn,
|
||||
%{
|
||||
|
@ -521,19 +530,37 @@ defp do_create_authorization(
|
|||
"redirect_uri" => redirect_uri
|
||||
} = auth_attrs
|
||||
},
|
||||
user \\ nil
|
||||
user
|
||||
) do
|
||||
with {_, {:ok, %User{} = user}} <-
|
||||
{:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},
|
||||
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
||||
true <- redirect_uri in String.split(app.redirect_uris),
|
||||
{:ok, scopes} <- validate_scopes(app, auth_attrs),
|
||||
{:account_status, :active} <- {:account_status, User.account_status(user)},
|
||||
{:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
|
||||
requested_scopes <- Scopes.fetch_scopes(auth_attrs, app.scopes),
|
||||
{:ok, auth} <- do_create_authorization(user, app, requested_scopes) do
|
||||
{:ok, auth, user}
|
||||
end
|
||||
end
|
||||
|
||||
defp do_create_authorization(%User{} = user, %App{} = app, requested_scopes)
|
||||
when is_list(requested_scopes) do
|
||||
with {:account_status, :active} <- {:account_status, User.account_status(user)},
|
||||
{:ok, scopes} <- validate_scopes(app, requested_scopes),
|
||||
{:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
|
||||
{:ok, auth}
|
||||
end
|
||||
end
|
||||
|
||||
# Note: intended to be a private function but opened for AccountController that logs in on signup
|
||||
@doc "If checks pass, creates authorization and token for given user, app and requested scopes."
|
||||
def login(%User{} = user, %App{} = app, requested_scopes) when is_list(requested_scopes) do
|
||||
with {:ok, auth} <- do_create_authorization(user, app, requested_scopes),
|
||||
{:mfa_required, _, _, false} <- {:mfa_required, user, auth, MFA.require?(user)},
|
||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||
{:ok, token}
|
||||
end
|
||||
end
|
||||
|
||||
# Special case: Local MastodonFE
|
||||
defp redirect_uri(%Plug.Conn{} = conn, "."), do: auth_url(conn, :login)
|
||||
|
||||
|
@ -550,12 +577,15 @@ defp build_and_response_mfa_token(user, auth) do
|
|||
end
|
||||
end
|
||||
|
||||
@spec validate_scopes(App.t(), map()) ::
|
||||
@spec validate_scopes(App.t(), map() | list()) ::
|
||||
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
|
||||
defp validate_scopes(%App{} = app, params) do
|
||||
params
|
||||
|> Scopes.fetch_scopes(app.scopes)
|
||||
|> Scopes.validate(app.scopes)
|
||||
defp validate_scopes(%App{} = app, params) when is_map(params) do
|
||||
requested_scopes = Scopes.fetch_scopes(params, app.scopes)
|
||||
validate_scopes(app, requested_scopes)
|
||||
end
|
||||
|
||||
defp validate_scopes(%App{} = app, requested_scopes) when is_list(requested_scopes) do
|
||||
Scopes.validate(requested_scopes, app.scopes)
|
||||
end
|
||||
|
||||
def default_redirect_uri(%App{} = app) do
|
||||
|
|
|
@ -89,11 +89,11 @@ def post_chat_message(
|
|||
cm_ref <- MessageReference.for_chat_and_object(chat, message) do
|
||||
conn
|
||||
|> put_view(MessageReferenceView)
|
||||
|> render("show.json", for: user, chat_message_reference: cm_ref)
|
||||
|> render("show.json", chat_message_reference: cm_ref)
|
||||
end
|
||||
end
|
||||
|
||||
def mark_message_as_read(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
|
||||
def mark_message_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{
|
||||
id: chat_id,
|
||||
message_id: message_id
|
||||
}) do
|
||||
|
@ -104,12 +104,15 @@ def mark_message_as_read(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
|
|||
{:ok, cm_ref} <- MessageReference.mark_as_read(cm_ref) do
|
||||
conn
|
||||
|> put_view(MessageReferenceView)
|
||||
|> render("show.json", for: user, chat_message_reference: cm_ref)
|
||||
|> render("show.json", chat_message_reference: cm_ref)
|
||||
end
|
||||
end
|
||||
|
||||
def mark_as_read(
|
||||
%{body_params: %{last_read_id: last_read_id}, assigns: %{user: %{id: user_id}}} = conn,
|
||||
%{
|
||||
body_params: %{last_read_id: last_read_id},
|
||||
assigns: %{user: %{id: user_id}}
|
||||
} = conn,
|
||||
%{id: id}
|
||||
) do
|
||||
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
|
||||
|
@ -121,7 +124,7 @@ def mark_as_read(
|
|||
end
|
||||
end
|
||||
|
||||
def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = params) do
|
||||
def messages(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id} = params) do
|
||||
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
|
||||
cm_refs =
|
||||
chat
|
||||
|
@ -130,7 +133,7 @@ def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = para
|
|||
|
||||
conn
|
||||
|> put_view(MessageReferenceView)
|
||||
|> render("index.json", for: user, chat_message_references: cm_refs)
|
||||
|> render("index.json", chat_message_references: cm_refs)
|
||||
else
|
||||
_ ->
|
||||
conn
|
||||
|
|
|
@ -21,8 +21,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
|
|||
]
|
||||
)
|
||||
|
||||
@skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug]
|
||||
plug(:skip_plug, @skip_plugs when action in [:archive, :show, :list])
|
||||
@skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug]
|
||||
plug(:skip_plug, @skip_plugs when action in [:index, :show, :archive])
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
|
|||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
|
||||
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
|
||||
with true <- Pleroma.Config.get([:instance, :show_reactions]),
|
||||
%Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
|
||||
%Object{data: %{"reactions" => reactions}} when is_list(reactions) <-
|
||||
Object.normalize(activity) do
|
||||
reactions = filter(reactions, params)
|
||||
|
|
|
@ -14,7 +14,7 @@ def render(
|
|||
%{
|
||||
chat_message_reference: %{
|
||||
id: id,
|
||||
object: %{data: chat_message},
|
||||
object: %{data: chat_message} = object,
|
||||
chat_id: chat_id,
|
||||
unread: unread
|
||||
}
|
||||
|
@ -30,7 +30,12 @@ def render(
|
|||
attachment:
|
||||
chat_message["attachment"] &&
|
||||
StatusView.render("attachment.json", attachment: chat_message["attachment"]),
|
||||
unread: unread
|
||||
unread: unread,
|
||||
card:
|
||||
StatusView.render(
|
||||
"card.json",
|
||||
Pleroma.Web.RichMedia.Helpers.fetch_data_for_object(object)
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -15,10 +15,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatView do
|
|||
def render("show.json", %{chat: %Chat{} = chat} = opts) do
|
||||
recipient = User.get_cached_by_ap_id(chat.recipient)
|
||||
last_message = opts[:last_message] || MessageReference.last_message_for_chat(chat)
|
||||
account_view_opts = account_view_opts(opts, recipient)
|
||||
|
||||
%{
|
||||
id: chat.id |> to_string(),
|
||||
account: AccountView.render("show.json", Map.put(opts, :user, recipient)),
|
||||
account: AccountView.render("show.json", account_view_opts),
|
||||
unread: MessageReference.unread_count_for_chat(chat),
|
||||
last_message:
|
||||
last_message &&
|
||||
|
@ -27,7 +28,17 @@ def render("show.json", %{chat: %Chat{} = chat} = opts) do
|
|||
}
|
||||
end
|
||||
|
||||
def render("index.json", %{chats: chats}) do
|
||||
render_many(chats, __MODULE__, "show.json")
|
||||
def render("index.json", %{chats: chats} = opts) do
|
||||
render_many(chats, __MODULE__, "show.json", Map.delete(opts, :chats))
|
||||
end
|
||||
|
||||
defp account_view_opts(opts, recipient) do
|
||||
account_view_opts = Map.put(opts, :user, recipient)
|
||||
|
||||
if Map.has_key?(account_view_opts, :for) do
|
||||
account_view_opts
|
||||
else
|
||||
Map.put(account_view_opts, :skip_visibility_check, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ def render("show.json", %{emoji_reaction: [emoji, user_ap_ids], user: user}) do
|
|||
%{
|
||||
name: emoji,
|
||||
count: length(users),
|
||||
accounts: render(AccountView, "index.json", users: users, for: user, as: :user),
|
||||
accounts: render(AccountView, "index.json", users: users, for: user),
|
||||
me: !!(user && user.ap_id in user_ap_ids)
|
||||
}
|
||||
end
|
||||
|
|
|
@ -9,12 +9,17 @@ defmodule Pleroma.Web.RichMedia.Helpers do
|
|||
alias Pleroma.Object
|
||||
alias Pleroma.Web.RichMedia.Parser
|
||||
|
||||
@rich_media_options [
|
||||
pool: :media,
|
||||
max_body: 2_000_000
|
||||
]
|
||||
|
||||
@spec validate_page_url(URI.t() | binary()) :: :ok | :error
|
||||
defp validate_page_url(page_url) when is_binary(page_url) do
|
||||
validate_tld = Application.get_env(:auto_linker, :opts)[:validate_tld]
|
||||
validate_tld = Pleroma.Config.get([Pleroma.Formatter, :validate_tld])
|
||||
|
||||
page_url
|
||||
|> AutoLinker.Parser.url?(scheme: true, validate_tld: validate_tld)
|
||||
|> Linkify.Parser.url?(validate_tld: validate_tld)
|
||||
|> parse_uri(page_url)
|
||||
end
|
||||
|
||||
|
@ -49,11 +54,11 @@ defp get_tld(host) do
|
|||
|> hd
|
||||
end
|
||||
|
||||
def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) do
|
||||
def fetch_data_for_object(object) do
|
||||
with true <- Config.get([:rich_media, :enabled]),
|
||||
%Object{} = object <- Object.normalize(activity),
|
||||
false <- object.data["sensitive"] || false,
|
||||
{:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]),
|
||||
{:ok, page_url} <-
|
||||
HTML.extract_first_external_url(object, object.data["content"]),
|
||||
:ok <- validate_page_url(page_url),
|
||||
{:ok, rich_media} <- Parser.parse(page_url) do
|
||||
%{page_url: page_url, rich_media: rich_media}
|
||||
|
@ -62,10 +67,35 @@ def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) d
|
|||
end
|
||||
end
|
||||
|
||||
def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) do
|
||||
with true <- Config.get([:rich_media, :enabled]),
|
||||
%Object{} = object <- Object.normalize(activity) do
|
||||
fetch_data_for_object(object)
|
||||
else
|
||||
_ -> %{}
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_data_for_activity(_), do: %{}
|
||||
|
||||
def perform(:fetch, %Activity{} = activity) do
|
||||
fetch_data_for_activity(activity)
|
||||
:ok
|
||||
end
|
||||
|
||||
def rich_media_get(url) do
|
||||
headers = [{"user-agent", Pleroma.Application.user_agent() <> "; Bot"}]
|
||||
|
||||
options =
|
||||
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
|
||||
Keyword.merge(@rich_media_options,
|
||||
recv_timeout: 2_000,
|
||||
with_body: true
|
||||
)
|
||||
else
|
||||
@rich_media_options
|
||||
end
|
||||
|
||||
Pleroma.HTTP.get(url, headers, options)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,11 +3,6 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.RichMedia.Parser do
|
||||
@options [
|
||||
pool: :media,
|
||||
max_body: 2_000_000
|
||||
]
|
||||
|
||||
defp parsers do
|
||||
Pleroma.Config.get([:rich_media, :parsers])
|
||||
end
|
||||
|
@ -75,21 +70,8 @@ defp get_ttl_from_image(data, url) do
|
|||
end
|
||||
|
||||
defp parse_url(url) do
|
||||
opts =
|
||||
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
|
||||
Keyword.merge(@options,
|
||||
recv_timeout: 2_000,
|
||||
with_body: true
|
||||
)
|
||||
else
|
||||
@options
|
||||
end
|
||||
|
||||
try do
|
||||
rich_media_agent = Pleroma.Application.user_agent() <> "; Bot"
|
||||
|
||||
{:ok, %Tesla.Env{body: html}} =
|
||||
Pleroma.HTTP.get(url, [{"user-agent", rich_media_agent}], adapter: opts)
|
||||
{:ok, %Tesla.Env{body: html}} = Pleroma.Web.RichMedia.Helpers.rich_media_get(url)
|
||||
|
||||
html
|
||||
|> parse_html()
|
||||
|
|
|
@ -22,7 +22,7 @@ defp get_oembed_url([{"link", attributes, _children} | _]) do
|
|||
end
|
||||
|
||||
defp get_oembed_data(url) do
|
||||
with {:ok, %Tesla.Env{body: json}} <- Pleroma.HTTP.get(url, [], adapter: [pool: :media]) do
|
||||
with {:ok, %Tesla.Env{body: json}} <- Pleroma.Web.RichMedia.Helpers.rich_media_get(url) do
|
||||
Jason.decode(json)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -138,6 +138,7 @@ defmodule Pleroma.Web.Router do
|
|||
patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
|
||||
patch("/users/activate", AdminAPIController, :user_activate)
|
||||
patch("/users/deactivate", AdminAPIController, :user_deactivate)
|
||||
patch("/users/approve", AdminAPIController, :user_approve)
|
||||
put("/users/tag", AdminAPIController, :tag_users)
|
||||
delete("/users/tag", AdminAPIController, :untag_users)
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
}
|
||||
|
||||
a {
|
||||
color: color: #d8a070;
|
||||
color: #d8a070;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ def register_user(params, opts \\ []) do
|
|||
|> Map.put(:nickname, params[:username])
|
||||
|> Map.put(:name, Map.get(params, :fullname, params[:username]))
|
||||
|> Map.put(:password_confirmation, params[:password])
|
||||
|> Map.put(:registration_reason, params[:reason])
|
||||
|
||||
if Pleroma.Config.get([:instance, :registrations_open]) do
|
||||
create_user(params, opts)
|
||||
|
@ -44,6 +45,7 @@ defp create_user(params, opts) do
|
|||
|
||||
case User.register(changeset) do
|
||||
{:ok, user} ->
|
||||
maybe_notify_admins(user)
|
||||
{:ok, user}
|
||||
|
||||
{:error, changeset} ->
|
||||
|
@ -56,6 +58,18 @@ defp create_user(params, opts) do
|
|||
end
|
||||
end
|
||||
|
||||
defp maybe_notify_admins(%User{} = account) do
|
||||
if Pleroma.Config.get([:instance, :account_approval_required]) do
|
||||
User.all_superusers()
|
||||
|> Enum.filter(fn user -> not is_nil(user.email) end)
|
||||
|> Enum.each(fn superuser ->
|
||||
superuser
|
||||
|> Pleroma.Emails.AdminEmail.new_unapproved_registration(account)
|
||||
|> Pleroma.Emails.Mailer.deliver_async()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
def password_reset(nickname_or_email) do
|
||||
with true <- is_binary(nickname_or_email),
|
||||
%User{local: true, email: email} = user when is_binary(email) <-
|
||||
|
|
|
@ -9,36 +9,6 @@ defmodule Pleroma.Web.MastoFEView do
|
|||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MastodonAPI.CustomEmojiView
|
||||
|
||||
@default_settings %{
|
||||
onboarded: true,
|
||||
home: %{
|
||||
shows: %{
|
||||
reblog: true,
|
||||
reply: true
|
||||
}
|
||||
},
|
||||
notifications: %{
|
||||
alerts: %{
|
||||
follow: true,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true
|
||||
},
|
||||
shows: %{
|
||||
follow: true,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true
|
||||
},
|
||||
sounds: %{
|
||||
follow: true,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def initial_state(token, user, custom_emojis) do
|
||||
limit = Config.get([:instance, :limit])
|
||||
|
||||
|
@ -86,7 +56,7 @@ def initial_state(token, user, custom_emojis) do
|
|||
"video\/mp4"
|
||||
]
|
||||
},
|
||||
settings: user.mastofe_settings || @default_settings,
|
||||
settings: user.mastofe_settings || %{},
|
||||
push_subscription: nil,
|
||||
accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)},
|
||||
custom_emojis: render(CustomEmojiView, "index.json", custom_emojis: custom_emojis),
|
||||
|
|
78
mix.exs
78
mix.exs
|
@ -114,64 +114,52 @@ defp oauth_deps do
|
|||
# Type `mix help deps` for examples and options.
|
||||
defp deps do
|
||||
[
|
||||
{:phoenix, "~> 1.4.8"},
|
||||
{:phoenix, "~> 1.4.17"},
|
||||
{:tzdata, "~> 1.0.3"},
|
||||
{:plug_cowboy, "~> 2.0"},
|
||||
{:plug_cowboy, "~> 2.3"},
|
||||
{:phoenix_pubsub, "~> 1.1"},
|
||||
{:phoenix_ecto, "~> 4.0"},
|
||||
{:ecto_enum, "~> 1.4"},
|
||||
{:ecto_sql, "~> 3.4.4"},
|
||||
{:postgrex, ">= 0.13.5"},
|
||||
{:postgrex, ">= 0.15.5"},
|
||||
{:oban, "~> 2.0.0"},
|
||||
{:gettext, "~> 0.15"},
|
||||
{:pbkdf2_elixir, "~> 1.0"},
|
||||
{:bcrypt_elixir, "~> 2.0"},
|
||||
{:gettext, "~> 0.18"},
|
||||
{:pbkdf2_elixir, "~> 1.2"},
|
||||
{:bcrypt_elixir, "~> 2.2"},
|
||||
{:trailing_format_plug, "~> 0.0.7"},
|
||||
{:fast_sanitize, "~> 0.1"},
|
||||
{:html_entities, "~> 0.5", override: true},
|
||||
{:phoenix_html, "~> 2.10"},
|
||||
{:calendar, "~> 0.17.4"},
|
||||
{:phoenix_html, "~> 2.14"},
|
||||
{:calendar, "~> 1.0"},
|
||||
{:cachex, "~> 3.2"},
|
||||
{:poison, "~> 3.0", override: true},
|
||||
# {:tesla, "~> 1.3", override: true},
|
||||
{:tesla,
|
||||
github: "teamon/tesla", ref: "af3707078b10793f6a534938e56b963aff82fe3c", override: true},
|
||||
{:castore, "~> 0.1"},
|
||||
{:cowlib, "~> 2.8", override: true},
|
||||
{:cowlib, "~> 2.9", override: true},
|
||||
{:gun,
|
||||
github: "ninenines/gun", ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", override: true},
|
||||
{:jason, "~> 1.0"},
|
||||
{:mogrify, "~> 0.6.1"},
|
||||
{:jason, "~> 1.2"},
|
||||
{:mogrify, "~> 0.7.4"},
|
||||
{:ex_aws, "~> 2.1"},
|
||||
{:ex_aws_s3, "~> 2.0"},
|
||||
{:sweet_xml, "~> 0.6.6"},
|
||||
{:earmark, "~> 1.3"},
|
||||
{:earmark, "1.4.3"},
|
||||
{:bbcode_pleroma, "~> 0.2.0"},
|
||||
{:ex_machina, "~> 2.3", only: :test},
|
||||
{:credo, "~> 1.1.0", only: [:dev, :test], runtime: false},
|
||||
{:mock, "~> 0.3.3", only: :test},
|
||||
{:crypt,
|
||||
git: "https://github.com/msantos/crypt", ref: "f63a705f92c26955977ee62a313012e309a4d77a"},
|
||||
{:cors_plug, "~> 1.5"},
|
||||
{:ex_doc, "~> 0.21", only: :dev, runtime: false},
|
||||
{:web_push_encryption, "~> 0.2.1"},
|
||||
{:swoosh,
|
||||
git: "https://github.com/swoosh/swoosh",
|
||||
ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5",
|
||||
override: true},
|
||||
{:phoenix_swoosh, "~> 0.2"},
|
||||
git: "https://github.com/msantos/crypt.git",
|
||||
ref: "f63a705f92c26955977ee62a313012e309a4d77a"},
|
||||
{:cors_plug, "~> 2.0"},
|
||||
{:web_push_encryption, "~> 0.3"},
|
||||
{:swoosh, "~> 1.0"},
|
||||
{:phoenix_swoosh, "~> 0.3"},
|
||||
{:gen_smtp, "~> 0.13"},
|
||||
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test},
|
||||
{:ex_syslogger, "~> 1.4"},
|
||||
{:floki, "~> 0.25"},
|
||||
{:timex, "~> 3.5"},
|
||||
{:floki, "~> 0.27"},
|
||||
{:timex, "~> 3.6"},
|
||||
{:ueberauth, "~> 0.4"},
|
||||
{:auto_linker,
|
||||
git: "https://git.pleroma.social/pleroma/auto_linker.git",
|
||||
ref: "95e8188490e97505c56636c1379ffdf036c1fdde"},
|
||||
{:http_signatures,
|
||||
git: "https://git.pleroma.social/pleroma/http_signatures.git",
|
||||
ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"},
|
||||
{:linkify, "~> 0.2.0"},
|
||||
{:http_signatures, "~> 0.1.0"},
|
||||
{:telemetry, "~> 0.3"},
|
||||
{:poolboy, "~> 1.5"},
|
||||
{:prometheus, "~> 4.6"},
|
||||
|
@ -183,26 +171,33 @@ defp deps do
|
|||
{:quack, "~> 0.1.1"},
|
||||
{:joken, "~> 2.0"},
|
||||
{:benchee, "~> 1.0"},
|
||||
{:pot, "~> 0.10.2"},
|
||||
{:pot, "~> 0.11"},
|
||||
{:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)},
|
||||
{:ex_const, "~> 0.2"},
|
||||
{:plug_static_index_html, "~> 1.0.0"},
|
||||
{:excoveralls, "~> 0.12.1", only: :test},
|
||||
{:flake_id, "~> 0.1.0"},
|
||||
{:concurrent_limiter,
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter",
|
||||
ref: "8eee96c6ba39b9286ec44c51c52d9f2758951365"},
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter.git",
|
||||
ref: "55e92f84b4ed531bd487952a71040a9c69dc2807"},
|
||||
{:remote_ip,
|
||||
git: "https://git.pleroma.social/pleroma/remote_ip.git",
|
||||
ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"},
|
||||
{:captcha,
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
||||
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
|
||||
{:mox, "~> 0.5", only: :test},
|
||||
{:restarter, path: "./restarter"},
|
||||
{:open_api_spex,
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git",
|
||||
ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"}
|
||||
ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"},
|
||||
|
||||
## dev & test
|
||||
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
|
||||
{:ex_machina, "~> 2.4", only: :test},
|
||||
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
|
||||
{:mock, "~> 0.3.5", only: :test},
|
||||
{:excoveralls, "~> 0.13.1", only: :test},
|
||||
{:mox, "~> 0.5", only: :test},
|
||||
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test}
|
||||
] ++ oauth_deps()
|
||||
end
|
||||
|
||||
|
@ -219,7 +214,8 @@ defp aliases do
|
|||
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
|
||||
"ecto.reset": ["ecto.drop", "ecto.setup"],
|
||||
test: ["ecto.create --quiet", "ecto.migrate", "test"],
|
||||
docs: ["pleroma.docs", "docs"]
|
||||
docs: ["pleroma.docs", "docs"],
|
||||
analyze: ["credo --strict --only=warnings,todo,fixme,consistency,readability"]
|
||||
]
|
||||
end
|
||||
|
||||
|
|
69
mix.lock
69
mix.lock
|
@ -1,6 +1,5 @@
|
|||
%{
|
||||
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
|
||||
"auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "95e8188490e97505c56636c1379ffdf036c1fdde", [ref: "95e8188490e97505c56636c1379ffdf036c1fdde"]},
|
||||
"base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "3b29948de2013d3f93aa898c884a9dff847e7aec75d9d6d8c1dc4c61c2716c42"},
|
||||
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
|
||||
"bbcode": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/bbcode.git", "f2d267675e9a7e1ad1ea9beb4cc23382762b66c2", [ref: "v0.2.0"]},
|
||||
|
@ -9,25 +8,26 @@
|
|||
"benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"},
|
||||
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
|
||||
"cachex": {:hex, :cachex, "3.2.0", "a596476c781b0646e6cb5cd9751af2e2974c3e0d5498a8cab71807618b74fe2f", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "aef93694067a43697ae0531727e097754a9e992a1e7946296f5969d6dd9ac986"},
|
||||
"calendar": {:hex, :calendar, "0.17.6", "ec291cb2e4ba499c2e8c0ef5f4ace974e2f9d02ae9e807e711a9b0c7850b9aee", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "738d0e17a93c2ccfe4ddc707bdc8e672e9074c8569498483feb1c4530fb91b2b"},
|
||||
"calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
|
||||
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]},
|
||||
"castore": {:hex, :castore, "0.1.5", "591c763a637af2cc468a72f006878584bc6c306f8d111ef8ba1d4c10e0684010", [:mix], [], "hexpm", "6db356b2bc6cc22561e051ff545c20ad064af57647e436650aa24d7d06cd941a"},
|
||||
"castore": {:hex, :castore, "0.1.7", "1ca19eee705cde48c9e809e37fdd0730510752cc397745e550f6065a56a701e9", [:mix], [], "hexpm", "a2ae2c13d40e9c308387f1aceb14786dca019ebc2a11484fb2a9f797ea0aa0d8"},
|
||||
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||
"comeonin": {:hex, :comeonin, "5.3.1", "7fe612b739c78c9c1a75186ef2d322ce4d25032d119823269d0aa1e2f1e20025", [:mix], [], "hexpm", "d6222483060c17f0977fad1b7401ef0c5863c985a64352755f366aee3799c245"},
|
||||
"concurrent_limiter": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter", "8eee96c6ba39b9286ec44c51c52d9f2758951365", [ref: "8eee96c6ba39b9286ec44c51c52d9f2758951365"]},
|
||||
"concurrent_limiter": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter.git", "55e92f84b4ed531bd487952a71040a9c69dc2807", [ref: "55e92f84b4ed531bd487952a71040a9c69dc2807"]},
|
||||
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
|
||||
"cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9af027d20dc12dd0c4345a6b87247e0c62965871feea0bfecf9764648b02cc69"},
|
||||
"cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "04fd8c6a39edc6aaa9c26123009200fc61f92a3a94f3178c527b70b767c6e605"},
|
||||
"cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"},
|
||||
"credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d0bbd3222607ccaaac5c0340f7f525c627ae4d7aee6c8c8c108922620c5b6446"},
|
||||
"cors_plug": {:hex, :cors_plug, "2.0.2", "2b46083af45e4bc79632bd951550509395935d3e7973275b2b743bd63cc942ce", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f0d0e13f71c51fd4ef8b2c7e051388e4dfb267522a83a22392c856de7e46465f"},
|
||||
"cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"},
|
||||
"cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"},
|
||||
"credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"},
|
||||
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
|
||||
"crypt": {:git, "https://github.com/msantos/crypt", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]},
|
||||
"crypt": {:git, "https://github.com/msantos/crypt.git", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]},
|
||||
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
|
||||
"db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
|
||||
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
|
||||
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
||||
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.10", "6603d7a603b9c18d3d20db69921527f82ef09990885ed7525003c7fe7dc86c56", [:mix], [], "hexpm", "8e2d5370b732385db2c9b22215c3f59c84ac7dda7ed7e544d7c459496ae519c0"},
|
||||
"ecto": {:hex, :ecto, "3.4.5", "2bcd262f57b2c888b0bd7f7a28c8a48aa11dc1a2c6a858e45dd8f8426d504265", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8c6d1d4d524559e9b7a062f0498e2c206122552d63eacff0a6567ffe7a8e8691"},
|
||||
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
|
||||
|
@ -35,27 +35,27 @@
|
|||
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
|
||||
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
|
||||
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
|
||||
"ex_aws": {:hex, :ex_aws, "2.1.1", "1e4de2106cfbf4e837de41be41cd15813eabc722315e388f0d6bb3732cec47cd", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "06b6fde12b33bb6d65d5d3493e903ba5a56d57a72350c15285a4298338089e10"},
|
||||
"ex_aws": {:hex, :ex_aws, "2.1.3", "26b6f036f0127548706aade4a509978fc7c26bd5334b004fba9bfe2687a525df", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "0bdbe2aed9f326922fc5a6a80417e32f0c895f4b3b2b0b9676ebf23dd16c5da4"},
|
||||
"ex_aws_s3": {:hex, :ex_aws_s3, "2.0.2", "c0258bbdfea55de4f98f0b2f0ca61fe402cc696f573815134beb1866e778f47b", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "0569f5b211b1a3b12b705fe2a9d0e237eb1360b9d76298028df2346cad13097a"},
|
||||
"ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"},
|
||||
"ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "b84f6af156264530b312a8ab98ac6088f6b77ae5fe2058305c81434aa01fbaf9"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.22.2", "03a2a58bdd2ba0d83d004507c4ee113b9c521956938298eba16e55cc4aba4a6c", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "cf60e1b3e2efe317095b6bb79651f83a2c1b3edcb4d319c421d7fcda8b3aff26"},
|
||||
"ex_machina": {:hex, :ex_machina, "2.4.0", "09a34c5d371bfb5f78399029194a8ff67aff340ebe8ba19040181af35315eabb", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "a20bc9ddc721b33ea913b93666c5d0bdca5cbad7a67540784ae277228832d72c"},
|
||||
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
|
||||
"excoveralls": {:hex, :excoveralls, "0.12.2", "a513defac45c59e310ac42fcf2b8ae96f1f85746410f30b1ff2b710a4b6cd44b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "151c476331d49b45601ffc45f43cb3a8beb396b02a34e3777fea0ad34ae57d89"},
|
||||
"excoveralls": {:hex, :excoveralls, "0.13.1", "b9f1697f7c9e0cfe15d1a1d737fb169c398803ffcbc57e672aa007e9fd42864c", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b4bb550e045def1b4d531a37fb766cbbe1307f7628bf8f0414168b3f52021cce"},
|
||||
"fast_html": {:hex, :fast_html, "1.0.3", "2cc0d4b68496266a1530e0c852cafeaede0bd10cfdee26fda50dc696c203162f", [:make, :mix], [], "hexpm", "ab3d782b639d3c4655fbaec0f9d032c91f8cab8dd791ac7469c2381bc7c32f85"},
|
||||
"fast_sanitize": {:hex, :fast_sanitize, "0.1.7", "2a7cd8734c88a2de6de55022104f8a3b87f1fdbe8bbf131d9049764b53d50d0d", [:mix], [{:fast_html, "~> 1.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f39fe8ea08fbac17487c30bf09b7d9f3e12472e51fb07a88ffeb8fd17da8ab67"},
|
||||
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
|
||||
"floki": {:hex, :floki, "0.25.0", "b1c9ddf5f32a3a90b43b76f3386ca054325dc2478af020e87b5111c19f2284ac", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "631f4e627c46d5ecd347df5a2accdaf0621c77c3693c5b75a8ad58e84c61f242"},
|
||||
"floki": {:hex, :floki, "0.27.0", "6b29a14283f1e2e8fad824bc930eaa9477c462022075df6bea8f0ad811c13599", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "583b8c13697c37179f1f82443bcc7ad2f76fbc0bf4c186606eebd658f7f2631b"},
|
||||
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
|
||||
"gen_stage": {:hex, :gen_stage, "0.14.3", "d0c66f1c87faa301c1a85a809a3ee9097a4264b2edf7644bf5c123237ef732bf", [:mix], [], "hexpm"},
|
||||
"gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"},
|
||||
"gettext": {:hex, :gettext, "0.17.4", "f13088e1ec10ce01665cf25f5ff779e7df3f2dc71b37084976cf89d1aa124d5c", [:mix], [], "hexpm", "3c75b5ea8288e2ee7ea503ff9e30dfe4d07ad3c054576a6e60040e79a801e14d"},
|
||||
"gettext": {:hex, :gettext, "0.18.0", "406d6b9e0e3278162c2ae1de0a60270452c553536772167e2d701f028116f870", [:mix], [], "hexpm", "c3f850be6367ebe1a08616c2158affe4a23231c70391050bf359d5f92f66a571"},
|
||||
"gun": {:git, "https://github.com/ninenines/gun.git", "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", [ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327"]},
|
||||
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
|
||||
"html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm", "30efab070904eb897ff05cd52fa61c1025d7f8ef3a9ca250bc4e6513d16c32de"},
|
||||
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]},
|
||||
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
|
||||
"http_signatures": {:hex, :http_signatures, "0.1.0", "4e4b501a936dbf4cb5222597038a89ea10781776770d2e185849fa829686b34c", [:mix], [], "hexpm", "f8a7b3731e3fd17d38fa6e343fcad7b03d6874a3b0a108c8568a71ed9c2cf824"},
|
||||
"httpoison": {:hex, :httpoison, "1.7.0", "abba7d086233c2d8574726227b6c2c4f6e53c4deae7fe5f6de531162ce9929a0", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "975cc87c845a103d3d1ea1ccfd68a2700c211a434d8428b10c323dc95dc5b980"},
|
||||
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"},
|
||||
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
|
||||
"jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"},
|
||||
|
@ -63,36 +63,37 @@
|
|||
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
|
||||
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
|
||||
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
|
||||
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"},
|
||||
"linkify": {:hex, :linkify, "0.2.0", "2518bbbea21d2caa9d372424e1ad845b640c6630e2d016f1bd1f518f9ebcca28", [:mix], [], "hexpm", "b8ca8a68b79e30b7938d6c996085f3db14939f29538a59ca5101988bb7f917f6"},
|
||||
"makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
|
||||
"meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm", "d34f013c156db51ad57cc556891b9720e6a1c1df5fe2e15af999c84d6cebeb1a"},
|
||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
||||
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"},
|
||||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
||||
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
|
||||
"mock": {:hex, :mock, "0.3.4", "c5862eb3b8c64237f45f586cf00c9d892ba07bb48305a43319d428ce3c2897dd", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "e6d886252f1a41f4ba06ecf2b4c8d38760b34b1c08a11c28f7397b2e03995964"},
|
||||
"mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm", "3bc928d817974fa10cc11e6c89b9a9361e37e96dbbf3d868c41094ec05745dcd"},
|
||||
"mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm", "052346cf322311c49a0f22789f3698eea030eec09b8c47367f0686ef2634ae14"},
|
||||
"mock": {:hex, :mock, "0.3.5", "feb81f52b8dcf0a0d65001d2fec459f6b6a8c22562d94a965862f6cc066b5431", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "6fae404799408300f863550392635d8f7e3da6b71abdd5c393faf41b131c8728"},
|
||||
"mogrify": {:hex, :mogrify, "0.7.4", "9b2496dde44b1ce12676f85d7dc531900939e6367bc537c7243a1b089435b32d", [:mix], [], "hexpm", "50d79e337fba6bc95bfbef918058c90f50b17eed9537771e61d4619488f099c3"},
|
||||
"mox": {:hex, :mox, "0.5.2", "55a0a5ba9ccc671518d068c8dddd20eeb436909ea79d1799e2209df7eaa98b6c", [:mix], [], "hexpm", "df4310628cd628ee181df93f50ddfd07be3e5ecc30232d3b6aadf30bdfe6092b"},
|
||||
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
|
||||
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
|
||||
"oban": {:hex, :oban, "2.0.0", "e6ce70d94dd46815ec0882a1ffb7356df9a9d5b8a40a64ce5c2536617a447379", [:mix], [{:ecto_sql, ">= 3.4.3", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cf574813bd048b98a698aa587c21367d2e06842d4e1b1993dcd6a696e9e633bd"},
|
||||
"open_api_spex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git", "f296ac0924ba3cf79c7a588c4c252889df4c2edd", [ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"]},
|
||||
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
|
||||
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
|
||||
"phoenix": {:hex, :phoenix, "1.4.13", "67271ad69b51f3719354604f4a3f968f83aa61c19199343656c9caee057ff3b8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ab765a0feddb81fc62e2116c827b5f068df85159c162bee760745276ad7ddc1b"},
|
||||
"phoenix": {:hex, :phoenix, "1.4.17", "1b1bd4cff7cfc87c94deaa7d60dd8c22e04368ab95499483c50640ef3bd838d8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a8e5d7a3d76d452bb5fb86e8b7bd115f737e4f8efe202a463d4aeb4a5809611"},
|
||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "2.14.0", "d8c6bc28acc8e65f8ea0080ee05aa13d912c8758699283b8d3427b655aabe284", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "b0bb30eda478a06dbfbe96728061a93833db3861a49ccb516f839ecb08493fbb"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm", "1f13f9f0f3e769a667a6b6828d29dec37497a082d195cc52dbef401a9b69bf38"},
|
||||
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "ebf1bfa7b3c1c850c04929afe02e2e0d7ab135e0706332c865de03e761676b1f"},
|
||||
"plug": {:hex, :plug, "1.9.0", "8d7c4e26962283ff9f8f3347bd73838e2413fbc38b7bb5467d5924f68f3a5a4a", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "9902eda2c52ada2a096434682e99a2493f5d06a94d6ac6bcfff9805f952350f1"},
|
||||
"plug_cowboy": {:hex, :plug_cowboy, "2.1.2", "8b0addb5908c5238fac38e442e81b6fcd32788eaa03246b4d55d147c47c5805e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "7d722581ce865a237e14da6d946f92704101740a256bd13ec91e63c0b122fc70"},
|
||||
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.0", "2acfa0db038a7649e0a4614eee970e6ed9a39d191ccd79a03583b51d0da98165", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "b8bbae4b59a676de6b8bd8675eda37bc8b4424812ae429d6fdcb2b039e00003b"},
|
||||
"plug": {:hex, :plug, "1.10.3", "c9cebe917637d8db0e759039cc106adca069874e1a9034fd6e3fdd427fd3c283", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "01f9037a2a1de1d633b5a881101e6a444bcabb1d386ca1e00bb273a1f1d9d939"},
|
||||
"plug_cowboy": {:hex, :plug_cowboy, "2.3.0", "149a50e05cb73c12aad6506a371cd75750c0b19a32f81866e1a323dda9e0e99d", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bc595a1870cef13f9c1e03df56d96804db7f702175e4ccacdb8fc75c02a7b97e"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
|
||||
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
|
||||
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
|
||||
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
|
||||
"postgrex": {:hex, :postgrex, "0.15.5", "aec40306a622d459b01bff890fa42f1430dac61593b122754144ad9033a2152f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ed90c81e1525f65a2ba2279dbcebf030d6d13328daa2f8088b9661eb9143af7f"},
|
||||
"pot": {:hex, :pot, "0.10.2", "9895c83bcff8cd22d9f5bc79dfc88a188176b261b618ad70d93faf5c5ca36e67", [:rebar3], [], "hexpm", "ac589a8e296b7802681e93cd0a436faec117ea63e9916709c628df31e17e91e2"},
|
||||
"pot": {:hex, :pot, "0.11.0", "61bad869a94534739dd4614a25a619bc5c47b9970e9a0ea5bef4628036fc7a16", [:rebar3], [], "hexpm", "57ee6ee6bdeb639661ffafb9acefe3c8f966e45394de6a766813bb9e1be4e54b"},
|
||||
"prometheus": {:hex, :prometheus, "4.6.0", "20510f381db1ccab818b4cf2fac5fa6ab5cc91bc364a154399901c001465f46f", [:mix, :rebar3], [], "hexpm", "4905fd2992f8038eccd7aa0cd22f40637ed618c0bed1f75c05aacec15b7545de"},
|
||||
"prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
|
||||
"prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm", "9fd13404a48437e044b288b41f76e64acd9735fb8b0e3809f494811dfa66d0fb"},
|
||||
|
@ -100,21 +101,21 @@
|
|||
"prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"},
|
||||
"quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"},
|
||||
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
|
||||
"recon": {:hex, :recon, "2.5.0", "2f7fcbec2c35034bade2f9717f77059dc54eb4e929a3049ca7ba6775c0bd66cd", [:mix, :rebar3], [], "hexpm", "72f3840fedd94f06315c523f6cecf5b4827233bed7ae3fe135b2a0ebeab5e196"},
|
||||
"recon": {:hex, :recon, "2.5.1", "430ffa60685ac1efdfb1fe4c97b8767c92d0d92e6e7c3e8621559ba77598678a", [:mix, :rebar3], [], "hexpm", "5721c6b6d50122d8f68cccac712caa1231f97894bab779eff5ff0f886cb44648"},
|
||||
"remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]},
|
||||
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
|
||||
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"},
|
||||
"swoosh": {:git, "https://github.com/swoosh/swoosh", "c96e0ca8a00d8f211ec1f042a4626b09f249caa5", [ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5"]},
|
||||
"swoosh": {:hex, :swoosh, "1.0.0", "c547cfc83f30e12d5d1fdcb623d7de2c2e29a5becfc68bf8f42ba4d23d2c2756", [: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: true]}, {: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", "b3b08e463f876cb6167f7168e9ad99a069a724e124bcee61847e0e1ed13f4a0d"},
|
||||
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
|
||||
"telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
|
||||
"tesla": {:git, "https://github.com/teamon/tesla.git", "af3707078b10793f6a534938e56b963aff82fe3c", [ref: "af3707078b10793f6a534938e56b963aff82fe3c"]},
|
||||
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "f354efb2400dd7a80fd9eb6c8419068c4f632da4ac47f3d8822d6e33f08bc852"},
|
||||
"timex": {:hex, :timex, "3.6.2", "845cdeb6119e2fef10751c0b247b6c59d86d78554c83f78db612e3290f819bc2", [: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", "26030b46199d02a590be61c2394b37ea25a3664c02fafbeca0b24c972025d47a"},
|
||||
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
|
||||
"tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"},
|
||||
"ueberauth": {:hex, :ueberauth, "0.6.2", "25a31111249d60bad8b65438b2306a4dc91f3208faa62f5a8c33e8713989b2e8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "db9fbfb5ac707bc4f85a297758406340bf0358b4af737a88113c1a9eee120ac7"},
|
||||
"ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"},
|
||||
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
|
||||
"web_push_encryption": {:hex, :web_push_encryption, "0.2.3", "a0ceab85a805a30852f143d22d71c434046fbdbafbc7292e7887cec500826a80", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm", "9315c8f37c108835cf3f8e9157d7a9b8f420a34f402d1b1620a31aed5b93ecdf"},
|
||||
"web_push_encryption": {:hex, :web_push_encryption, "0.3.0", "598b5135e696fd1404dc8d0d7c0fa2c027244a4e5d5e5a98ba267f14fdeaabc8", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "f10bdd1afe527ede694749fb77a2f22f146a51b054c7fa541c9fd920fba7c875"},
|
||||
"websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
defmodule Pleroma.Repo.Migrations.AddApprovalFieldsToUsers do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:users) do
|
||||
add(:approval_pending, :boolean)
|
||||
add(:registration_reason, :text)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,36 @@
|
|||
defmodule Pleroma.Repo.Migrations.AutolinkerToLinkify do
|
||||
use Ecto.Migration
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
@autolinker_path %{group: :auto_linker, key: :opts}
|
||||
@linkify_path %{group: :pleroma, key: Pleroma.Formatter}
|
||||
|
||||
@compat_opts [:class, :rel, :new_window, :truncate, :strip_prefix, :extra]
|
||||
|
||||
def change do
|
||||
with {:ok, {old, new}} <- maybe_get_params() do
|
||||
move_config(old, new)
|
||||
end
|
||||
end
|
||||
|
||||
defp move_config(%{} = old, %{} = new) do
|
||||
{:ok, _} = ConfigDB.update_or_create(new)
|
||||
{:ok, _} = ConfigDB.delete(old)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp maybe_get_params() do
|
||||
with %ConfigDB{value: opts} <- ConfigDB.get_by_params(@autolinker_path),
|
||||
opts <- transform_opts(opts),
|
||||
%{} = linkify_params <- Map.put(@linkify_path, :value, opts) do
|
||||
{:ok, {@autolinker_path, linkify_params}}
|
||||
end
|
||||
end
|
||||
|
||||
def transform_opts(opts) when is_list(opts) do
|
||||
opts
|
||||
|> Enum.into(%{})
|
||||
|> Map.take(@compat_opts)
|
||||
|> Map.to_list()
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfig do
|
||||
use Ecto.Migration
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
@config_path %{group: :pleroma, key: Pleroma.Formatter}
|
||||
|
||||
def change do
|
||||
with %ConfigDB{value: %{} = opts} <- ConfigDB.get_by_params(@config_path),
|
||||
fixed_opts <- Map.to_list(opts) do
|
||||
fix_config(fixed_opts)
|
||||
else
|
||||
_ -> :skipped
|
||||
end
|
||||
end
|
||||
|
||||
defp fix_config(fixed_opts) when is_list(fixed_opts) do
|
||||
{:ok, _} =
|
||||
ConfigDB.update_or_create(%{
|
||||
group: :pleroma,
|
||||
key: Pleroma.Formatter,
|
||||
value: fixed_opts
|
||||
})
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
|
@ -0,0 +1,94 @@
|
|||
defmodule Pleroma.Repo.Migrations.MoveWelcomeSettings do
|
||||
use Ecto.Migration
|
||||
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
@old_keys [:welcome_user_nickname, :welcome_message]
|
||||
|
||||
def up do
|
||||
with {:ok, config, {keep_values, move_values}} <- get_old_values() do
|
||||
insert_welcome_settings(move_values)
|
||||
update_instance_config(config, keep_values)
|
||||
end
|
||||
end
|
||||
|
||||
def down do
|
||||
with {:ok, welcome_config, revert_values} <- get_revert_values() do
|
||||
revert_instance_config(revert_values)
|
||||
Pleroma.Repo.delete(welcome_config)
|
||||
end
|
||||
end
|
||||
|
||||
defp insert_welcome_settings([_ | _] = values) do
|
||||
unless String.trim(values[:welcome_message]) == "" do
|
||||
config_values = [
|
||||
direct_message: %{
|
||||
enabled: true,
|
||||
sender_nickname: values[:welcome_user_nickname],
|
||||
message: values[:welcome_message]
|
||||
},
|
||||
email: %{
|
||||
enabled: false,
|
||||
sender: nil,
|
||||
subject: "Welcome to <%= instance_name %>",
|
||||
html: "Welcome to <%= instance_name %>",
|
||||
text: "Welcome to <%= instance_name %>"
|
||||
}
|
||||
]
|
||||
|
||||
{:ok, _} =
|
||||
%ConfigDB{}
|
||||
|> ConfigDB.changeset(%{group: :pleroma, key: :welcome, value: config_values})
|
||||
|> Pleroma.Repo.insert()
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
defp insert_welcome_settings(_), do: :noop
|
||||
|
||||
defp revert_instance_config(%{} = revert_values) do
|
||||
values = [
|
||||
welcome_user_nickname: revert_values[:sender_nickname],
|
||||
welcome_message: revert_values[:message]
|
||||
]
|
||||
|
||||
ConfigDB.update_or_create(%{group: :pleroma, key: :instance, value: values})
|
||||
end
|
||||
|
||||
defp revert_instance_config(_), do: :noop
|
||||
|
||||
defp update_instance_config(config, values) do
|
||||
{:ok, _} =
|
||||
config
|
||||
|> ConfigDB.changeset(%{value: values})
|
||||
|> Pleroma.Repo.update()
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
defp get_revert_values do
|
||||
config = ConfigDB.get_by_params(%{group: :pleroma, key: :welcome})
|
||||
|
||||
cond do
|
||||
is_nil(config) -> {:noop, nil, nil}
|
||||
true -> {:ok, config, config.value[:direct_message]}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_old_values do
|
||||
config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
|
||||
|
||||
cond do
|
||||
is_nil(config) ->
|
||||
{:noop, config, {}}
|
||||
|
||||
is_binary(config.value[:welcome_message]) ->
|
||||
{:ok, config,
|
||||
{Keyword.drop(config.value, @old_keys), Keyword.take(config.value, @old_keys)}}
|
||||
|
||||
true ->
|
||||
{:ok, config, {Keyword.drop(config.value, @old_keys), []}}
|
||||
end
|
||||
end
|
||||
end
|
37
priv/repo/migrations/20200802170532_fix_legacy_tags.exs
Normal file
37
priv/repo/migrations/20200802170532_fix_legacy_tags.exs
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Fix legacy tags set by AdminFE that don't align with TagPolicy MRF
|
||||
|
||||
defmodule Pleroma.Repo.Migrations.FixLegacyTags do
|
||||
use Ecto.Migration
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
import Ecto.Query
|
||||
|
||||
@old_new_map %{
|
||||
"force_nsfw" => "mrf_tag:media-force-nsfw",
|
||||
"strip_media" => "mrf_tag:media-strip",
|
||||
"force_unlisted" => "mrf_tag:force-unlisted",
|
||||
"sandbox" => "mrf_tag:sandbox",
|
||||
"disable_remote_subscription" => "mrf_tag:disable-remote-subscription",
|
||||
"disable_any_subscription" => "mrf_tag:disable-any-subscription"
|
||||
}
|
||||
|
||||
def change do
|
||||
legacy_tags = Map.keys(@old_new_map)
|
||||
|
||||
from(u in User, where: fragment("? && ?", u.tags, ^legacy_tags))
|
||||
|> Repo.all()
|
||||
|> Enum.each(fn user ->
|
||||
fix_tags_changeset(user)
|
||||
|> Repo.update()
|
||||
end)
|
||||
end
|
||||
|
||||
defp fix_tags_changeset(%User{tags: tags} = user) do
|
||||
new_tags =
|
||||
Enum.map(tags, fn tag ->
|
||||
Map.get(@old_new_map, tag, tag)
|
||||
end)
|
||||
|
||||
Ecto.Changeset.change(user, tags: new_tags)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
defmodule Pleroma.Repo.Migrations.RemoveNonlocalExpirations do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
statement = """
|
||||
DELETE FROM
|
||||
activity_expirations A USING activities B
|
||||
WHERE
|
||||
A.activity_id = B.id
|
||||
AND B.local = false;
|
||||
"""
|
||||
|
||||
execute(statement)
|
||||
end
|
||||
|
||||
def down do
|
||||
:ok
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
defmodule Pleroma.Repo.Migrations.AddUniqueIndexToAppClientId do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create(unique_index(:apps, [:client_id]))
|
||||
end
|
||||
end
|
|
@ -9,6 +9,56 @@ defmodule Pleroma.ApplicationRequirementsTest do
|
|||
|
||||
alias Pleroma.Repo
|
||||
|
||||
describe "check_welcome_message_config!/1" do
|
||||
setup do: clear_config([:welcome])
|
||||
setup do: clear_config([Pleroma.Emails.Mailer])
|
||||
|
||||
test "raises if welcome email enabled but mail disabled" do
|
||||
Pleroma.Config.put([:welcome, :email, :enabled], true)
|
||||
Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
|
||||
|
||||
assert_raise Pleroma.ApplicationRequirements.VerifyError, "The mail disabled.", fn ->
|
||||
capture_log(&Pleroma.ApplicationRequirements.verify!/0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "check_confirmation_accounts!" do
|
||||
setup_with_mocks([
|
||||
{Pleroma.ApplicationRequirements, [:passthrough],
|
||||
[
|
||||
check_migrations_applied!: fn _ -> :ok end
|
||||
]}
|
||||
]) do
|
||||
:ok
|
||||
end
|
||||
|
||||
setup do: clear_config([:instance, :account_activation_required])
|
||||
|
||||
test "raises if account confirmation is required but mailer isn't enable" do
|
||||
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||
Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
|
||||
|
||||
assert_raise Pleroma.ApplicationRequirements.VerifyError,
|
||||
"Account activation enabled, but Mailer is disabled. Cannot send confirmation emails.",
|
||||
fn ->
|
||||
capture_log(&Pleroma.ApplicationRequirements.verify!/0)
|
||||
end
|
||||
end
|
||||
|
||||
test "doesn't do anything if account confirmation is disabled" do
|
||||
Pleroma.Config.put([:instance, :account_activation_required], false)
|
||||
Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
|
||||
assert Pleroma.ApplicationRequirements.verify!() == :ok
|
||||
end
|
||||
|
||||
test "doesn't do anything if account confirmation is required and mailer is enabled" do
|
||||
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||
Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], true)
|
||||
assert Pleroma.ApplicationRequirements.verify!() == :ok
|
||||
end
|
||||
end
|
||||
|
||||
describe "check_rum!" do
|
||||
setup_with_mocks([
|
||||
{Pleroma.ApplicationRequirements, [:passthrough],
|
||||
|
|
|
@ -41,7 +41,8 @@ test "new and validate" do
|
|||
answer_data: answer,
|
||||
token: ^token,
|
||||
url: ^url,
|
||||
type: :kocaptcha
|
||||
type: :kocaptcha,
|
||||
seconds_valid: 300
|
||||
} = new
|
||||
|
||||
assert Kocaptcha.validate(token, "7oEy8c", answer) == :ok
|
||||
|
@ -56,7 +57,8 @@ test "new and validate" do
|
|||
answer_data: answer,
|
||||
token: token,
|
||||
type: :native,
|
||||
url: "data:image/png;base64," <> _
|
||||
url: "data:image/png;base64," <> _,
|
||||
seconds_valid: 300
|
||||
} = new
|
||||
|
||||
assert is_binary(answer)
|
||||
|
|
|
@ -28,6 +28,34 @@ test "get/1 with a list of keys" do
|
|||
assert Pleroma.Config.get([:azerty, :uiop], true) == true
|
||||
end
|
||||
|
||||
describe "nil values" do
|
||||
setup do
|
||||
Pleroma.Config.put(:lorem, nil)
|
||||
Pleroma.Config.put(:ipsum, %{dolor: [sit: nil]})
|
||||
Pleroma.Config.put(:dolor, sit: %{amet: nil})
|
||||
|
||||
on_exit(fn -> Enum.each(~w(lorem ipsum dolor)a, &Pleroma.Config.delete/1) end)
|
||||
end
|
||||
|
||||
test "get/1 with an atom for nil value" do
|
||||
assert Pleroma.Config.get(:lorem) == nil
|
||||
end
|
||||
|
||||
test "get/2 with an atom for nil value" do
|
||||
assert Pleroma.Config.get(:lorem, true) == nil
|
||||
end
|
||||
|
||||
test "get/1 with a list of keys for nil value" do
|
||||
assert Pleroma.Config.get([:ipsum, :dolor, :sit]) == nil
|
||||
assert Pleroma.Config.get([:dolor, :sit, :amet]) == nil
|
||||
end
|
||||
|
||||
test "get/2 with a list of keys for nil value" do
|
||||
assert Pleroma.Config.get([:ipsum, :dolor, :sit], true) == nil
|
||||
assert Pleroma.Config.get([:dolor, :sit, :amet], true) == nil
|
||||
end
|
||||
end
|
||||
|
||||
test "get/1 when value is false" do
|
||||
Pleroma.Config.put([:instance, :false_test], false)
|
||||
Pleroma.Config.put([:instance, :nested], [])
|
||||
|
@ -89,5 +117,23 @@ test "delete/2 with a list of keys" do
|
|||
Pleroma.Config.put([:delete_me, :delete_me], hello: "world", world: "Hello")
|
||||
Pleroma.Config.delete([:delete_me, :delete_me, :world])
|
||||
assert Pleroma.Config.get([:delete_me, :delete_me]) == [hello: "world"]
|
||||
|
||||
assert Pleroma.Config.delete([:this_key_does_not_exist])
|
||||
assert Pleroma.Config.delete([:non, :existing, :key])
|
||||
end
|
||||
|
||||
test "fetch/1" do
|
||||
Pleroma.Config.put([:lorem], :ipsum)
|
||||
Pleroma.Config.put([:ipsum], dolor: :sit)
|
||||
|
||||
assert Pleroma.Config.fetch([:lorem]) == {:ok, :ipsum}
|
||||
assert Pleroma.Config.fetch(:lorem) == {:ok, :ipsum}
|
||||
assert Pleroma.Config.fetch([:ipsum, :dolor]) == {:ok, :sit}
|
||||
assert Pleroma.Config.fetch([:lorem, :ipsum]) == :error
|
||||
assert Pleroma.Config.fetch([:loremipsum]) == :error
|
||||
assert Pleroma.Config.fetch(:loremipsum) == :error
|
||||
|
||||
Pleroma.Config.delete([:lorem])
|
||||
Pleroma.Config.delete([:ipsum])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,4 +46,24 @@ test "it works when the reporter is a remote user without email" do
|
|||
assert res.to == [{to_user.name, to_user.email}]
|
||||
assert res.from == {config[:name], config[:notify_email]}
|
||||
end
|
||||
|
||||
test "new unapproved registration email" do
|
||||
config = Pleroma.Config.get(:instance)
|
||||
to_user = insert(:user)
|
||||
account = insert(:user, registration_reason: "Plz let me in")
|
||||
|
||||
res = AdminEmail.new_unapproved_registration(to_user, account)
|
||||
|
||||
account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)
|
||||
|
||||
assert res.to == [{to_user.name, to_user.email}]
|
||||
assert res.from == {config[:name], config[:notify_email]}
|
||||
assert res.subject == "New account up for review on #{config[:name]} (@#{account.nickname})"
|
||||
|
||||
assert res.html_body == """
|
||||
<p>New account for review: <a href="#{account_url}">@#{account.nickname}</a></p>
|
||||
<blockquote>Plz let me in</blockquote>
|
||||
<a href="http://localhost:4001/pleroma/admin">Visit AdminFE</a>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.FormatterTest do
|
|||
import Pleroma.Factory
|
||||
|
||||
setup_all do
|
||||
clear_config(Pleroma.Formatter)
|
||||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||
:ok
|
||||
end
|
||||
|
@ -255,6 +256,36 @@ test "it can parse mentions and return the relevant users" do
|
|||
|
||||
assert {_text, ^expected_mentions, []} = Formatter.linkify(text)
|
||||
end
|
||||
|
||||
test "it parses URL containing local mention" do
|
||||
_user = insert(:user, %{nickname: "lain"})
|
||||
|
||||
text = "https://example.com/@lain"
|
||||
|
||||
expected = ~S(<a href="https://example.com/@lain" rel="ugc">https://example.com/@lain</a>)
|
||||
|
||||
assert {^expected, [], []} = Formatter.linkify(text)
|
||||
end
|
||||
|
||||
test "it correctly parses angry face D:< with mention" do
|
||||
lain =
|
||||
insert(:user, %{
|
||||
nickname: "lain@lain.com",
|
||||
ap_id: "https://lain.com/users/lain",
|
||||
id: "9qrWmR0cKniB0YU0TA"
|
||||
})
|
||||
|
||||
text = "@lain@lain.com D:<"
|
||||
|
||||
expected_text =
|
||||
~S(<span class="h-card"><a class="u-url mention" data-user="9qrWmR0cKniB0YU0TA" href="https://lain.com/users/lain" rel="ugc">@<span>lain</span></a></span> D:<)
|
||||
|
||||
expected_mentions = [
|
||||
{"@lain@lain.com", lain}
|
||||
]
|
||||
|
||||
assert {^expected_text, ^expected_mentions, []} = Formatter.linkify(text)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".parse_tags" do
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
import Pleroma.Tests.Helpers
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
setup do: clear_config(Pleroma.Formatter)
|
||||
setup_all do: require_migration("20200716195806_autolinker_to_linkify")
|
||||
|
||||
test "change/0 converts auto_linker opts for Pleroma.Formatter", %{migration: migration} do
|
||||
autolinker_opts = [
|
||||
extra: true,
|
||||
validate_tld: true,
|
||||
class: false,
|
||||
strip_prefix: false,
|
||||
new_window: false,
|
||||
rel: "testing"
|
||||
]
|
||||
|
||||
insert(:config, group: :auto_linker, key: :opts, value: autolinker_opts)
|
||||
|
||||
migration.change()
|
||||
|
||||
assert nil == ConfigDB.get_by_params(%{group: :auto_linker, key: :opts})
|
||||
|
||||
%{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter})
|
||||
|
||||
assert new_opts == [
|
||||
class: false,
|
||||
extra: true,
|
||||
new_window: false,
|
||||
rel: "testing",
|
||||
strip_prefix: false
|
||||
]
|
||||
|
||||
Pleroma.Config.put(Pleroma.Formatter, new_opts)
|
||||
assert new_opts == Pleroma.Config.get(Pleroma.Formatter)
|
||||
|
||||
{text, _mentions, []} =
|
||||
Pleroma.Formatter.linkify(
|
||||
"https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\n\nOmg will COVID finally end Black Friday???"
|
||||
)
|
||||
|
||||
assert text ==
|
||||
"<a href=\"https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\" rel=\"testing\">https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7</a>\n\nOmg will COVID finally end Black Friday???"
|
||||
end
|
||||
|
||||
test "transform_opts/1 returns a list of compatible opts", %{migration: migration} do
|
||||
old_opts = [
|
||||
extra: true,
|
||||
validate_tld: true,
|
||||
class: false,
|
||||
strip_prefix: false,
|
||||
new_window: false,
|
||||
rel: "qqq"
|
||||
]
|
||||
|
||||
expected_opts = [
|
||||
class: false,
|
||||
extra: true,
|
||||
new_window: false,
|
||||
rel: "qqq",
|
||||
strip_prefix: false
|
||||
]
|
||||
|
||||
assert migration.transform_opts(old_opts) == expected_opts
|
||||
end
|
||||
end
|
|
@ -0,0 +1,66 @@
|
|||
defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfigTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
import Pleroma.Tests.Helpers
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
setup do: clear_config(Pleroma.Formatter)
|
||||
setup_all do: require_migration("20200722185515_fix_malformed_formatter_config")
|
||||
|
||||
test "change/0 converts a map into a list", %{migration: migration} do
|
||||
incorrect_opts = %{
|
||||
class: false,
|
||||
extra: true,
|
||||
new_window: false,
|
||||
rel: "F",
|
||||
strip_prefix: false
|
||||
}
|
||||
|
||||
insert(:config, group: :pleroma, key: Pleroma.Formatter, value: incorrect_opts)
|
||||
|
||||
assert :ok == migration.change()
|
||||
|
||||
%{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter})
|
||||
|
||||
assert new_opts == [
|
||||
class: false,
|
||||
extra: true,
|
||||
new_window: false,
|
||||
rel: "F",
|
||||
strip_prefix: false
|
||||
]
|
||||
|
||||
Pleroma.Config.put(Pleroma.Formatter, new_opts)
|
||||
assert new_opts == Pleroma.Config.get(Pleroma.Formatter)
|
||||
|
||||
{text, _mentions, []} =
|
||||
Pleroma.Formatter.linkify(
|
||||
"https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\n\nOmg will COVID finally end Black Friday???"
|
||||
)
|
||||
|
||||
assert text ==
|
||||
"<a href=\"https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7\" rel=\"F\">https://www.businessinsider.com/walmart-will-close-stores-on-thanksgiving-ending-black-friday-tradition-2020-7</a>\n\nOmg will COVID finally end Black Friday???"
|
||||
end
|
||||
|
||||
test "change/0 skips if Pleroma.Formatter config is already a list", %{migration: migration} do
|
||||
opts = [
|
||||
class: false,
|
||||
extra: true,
|
||||
new_window: false,
|
||||
rel: "ugc",
|
||||
strip_prefix: false
|
||||
]
|
||||
|
||||
insert(:config, group: :pleroma, key: Pleroma.Formatter, value: opts)
|
||||
|
||||
assert :skipped == migration.change()
|
||||
|
||||
%{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter})
|
||||
|
||||
assert new_opts == opts
|
||||
end
|
||||
|
||||
test "change/0 skips if Pleroma.Formatter is empty", %{migration: migration} do
|
||||
assert :skipped == migration.change()
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue