Merge branch 'develop' into 'feature/custom-runtime-modules'
# Conflicts: # CHANGELOG.md
This commit is contained in:
commit
43d9c06a2a
|
@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Mastodon API: Mark the direct conversation as read for the author when they send a new direct message
|
- Mastodon API: Mark the direct conversation as read for the author when they send a new direct message
|
||||||
- Mastodon API, streaming: Add `pleroma.direct_conversation_id` to the `conversation` stream event payload.
|
- Mastodon API, streaming: Add `pleroma.direct_conversation_id` to the `conversation` stream event payload.
|
||||||
- Admin API: Render whole status in grouped reports
|
- Admin API: Render whole status in grouped reports
|
||||||
|
- Mastodon API: User timelines will now respect blocks, unless you are getting the user timeline of somebody you blocked (which would be empty otherwise).
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -50,6 +51,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- MRF: New module which handles incoming posts based on their age. By default, all incoming posts that are older than 2 days will be unlisted and not shown to their followers.
|
- MRF: New module which handles incoming posts based on their age. By default, all incoming posts that are older than 2 days will be unlisted and not shown to their followers.
|
||||||
- User notification settings: Add `privacy_option` option.
|
- User notification settings: Add `privacy_option` option.
|
||||||
- Support for custom Elixir modules (such as MRF policies)
|
- Support for custom Elixir modules (such as MRF policies)
|
||||||
|
- User settings: Add _This account is a_ option.
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
|
|
||||||
|
@ -78,6 +80,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Pleroma API: Add Emoji reactions
|
- Pleroma API: Add Emoji reactions
|
||||||
- Admin API: Add `/api/pleroma/admin/instances/:instance/statuses` - lists all statuses from a given instance
|
- Admin API: Add `/api/pleroma/admin/instances/:instance/statuses` - lists all statuses from a given instance
|
||||||
- Admin API: `PATCH /api/pleroma/users/confirm_email` to confirm email for multiple users, `PATCH /api/pleroma/users/resend_confirmation_email` to resend confirmation email for multiple users
|
- Admin API: `PATCH /api/pleroma/users/confirm_email` to confirm email for multiple users, `PATCH /api/pleroma/users/resend_confirmation_email` to resend confirmation email for multiple users
|
||||||
|
- ActivityPub: Configurable `type` field of the actors.
|
||||||
|
- Mastodon API: `/api/v1/accounts/:id` has `source/pleroma/actor_type` field.
|
||||||
|
- Mastodon API: `/api/v1/update_credentials` accepts `actor_type` field.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -66,6 +66,8 @@ Has these additional fields under the `pleroma` object:
|
||||||
|
|
||||||
- `show_role`: boolean, nullable, true when the user wants his role (e.g admin, moderator) to be shown
|
- `show_role`: boolean, nullable, true when the user wants his role (e.g admin, moderator) to be shown
|
||||||
- `no_rich_text` - boolean, nullable, true when html tags are stripped from all statuses requested from the API
|
- `no_rich_text` - boolean, nullable, true when html tags are stripped from all statuses requested from the API
|
||||||
|
- `discoverable`: boolean, true when the user allows discovery of the account in search results and other services.
|
||||||
|
- `actor_type`: string, the type of this account.
|
||||||
|
|
||||||
## Conversations
|
## Conversations
|
||||||
|
|
||||||
|
@ -146,6 +148,8 @@ Additional parameters can be added to the JSON body/Form data:
|
||||||
- `skip_thread_containment` - if true, skip filtering out broken threads
|
- `skip_thread_containment` - if true, skip filtering out broken threads
|
||||||
- `allow_following_move` - if true, allows automatically follow moved following accounts
|
- `allow_following_move` - if true, allows automatically follow moved following accounts
|
||||||
- `pleroma_background_image` - sets the background image of the user.
|
- `pleroma_background_image` - sets the background image of the user.
|
||||||
|
- `discoverable` - if true, discovery of this account in search results and other services is allowed.
|
||||||
|
- `actor_type` - the type of this account.
|
||||||
|
|
||||||
### Pleroma Settings Store
|
### Pleroma Settings Store
|
||||||
Pleroma has mechanism that allows frontends to save blobs of json for each user on the backend. This can be used to save frontend-specific settings for a user that the backend does not need to know about.
|
Pleroma has mechanism that allows frontends to save blobs of json for each user on the backend. This can be used to save frontend-specific settings for a user that the backend does not need to know about.
|
||||||
|
|
|
@ -52,7 +52,9 @@ def run(["migrate_from_db", env, delete?]) do
|
||||||
|> Enum.each(fn config ->
|
|> Enum.each(fn config ->
|
||||||
IO.write(
|
IO.write(
|
||||||
file,
|
file,
|
||||||
"config :#{config.group}, #{config.key}, #{inspect(Config.from_binary(config.value))}\r\n\r\n"
|
"config :#{config.group}, #{config.key}, #{
|
||||||
|
inspect(Config.from_binary(config.value), limit: :infinity)
|
||||||
|
}\r\n\r\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
if delete? do
|
if delete? do
|
||||||
|
|
|
@ -86,7 +86,7 @@ defp maybe_fetch(activities, user, search_query) do
|
||||||
{:ok, object} <- Fetcher.fetch_object_from_id(search_query),
|
{:ok, object} <- Fetcher.fetch_object_from_id(search_query),
|
||||||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
|
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
|
||||||
true <- Visibility.visible_for_user?(activity, user) do
|
true <- Visibility.visible_for_user?(activity, user) do
|
||||||
activities ++ [activity]
|
[activity | activities]
|
||||||
else
|
else
|
||||||
_ -> activities
|
_ -> activities
|
||||||
end
|
end
|
||||||
|
|
|
@ -127,6 +127,7 @@ defmodule Pleroma.User do
|
||||||
field(:invisible, :boolean, default: false)
|
field(:invisible, :boolean, default: false)
|
||||||
field(:allow_following_move, :boolean, default: true)
|
field(:allow_following_move, :boolean, default: true)
|
||||||
field(:skip_thread_containment, :boolean, default: false)
|
field(:skip_thread_containment, :boolean, default: false)
|
||||||
|
field(:actor_type, :string, default: "Person")
|
||||||
field(:also_known_as, {:array, :string}, default: [])
|
field(:also_known_as, {:array, :string}, default: [])
|
||||||
|
|
||||||
embeds_one(
|
embeds_one(
|
||||||
|
@ -346,6 +347,7 @@ def remote_user_creation(params) do
|
||||||
:following_count,
|
:following_count,
|
||||||
:discoverable,
|
:discoverable,
|
||||||
:invisible,
|
:invisible,
|
||||||
|
:actor_type,
|
||||||
:also_known_as
|
:also_known_as
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -396,6 +398,7 @@ def update_changeset(struct, params \\ %{}) do
|
||||||
:raw_fields,
|
:raw_fields,
|
||||||
:pleroma_settings_store,
|
:pleroma_settings_store,
|
||||||
:discoverable,
|
:discoverable,
|
||||||
|
:actor_type,
|
||||||
:also_known_as
|
:also_known_as
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -438,6 +441,7 @@ def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do
|
||||||
:discoverable,
|
:discoverable,
|
||||||
:hide_followers_count,
|
:hide_followers_count,
|
||||||
:hide_follows_count,
|
:hide_follows_count,
|
||||||
|
:actor_type,
|
||||||
:also_known_as
|
:also_known_as
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -1217,6 +1217,7 @@ defp object_to_user_data(data) do
|
||||||
data = Transmogrifier.maybe_fix_user_object(data)
|
data = Transmogrifier.maybe_fix_user_object(data)
|
||||||
discoverable = data["discoverable"] || false
|
discoverable = data["discoverable"] || false
|
||||||
invisible = data["invisible"] || false
|
invisible = data["invisible"] || false
|
||||||
|
actor_type = data["type"] || "Person"
|
||||||
|
|
||||||
user_data = %{
|
user_data = %{
|
||||||
ap_id: data["id"],
|
ap_id: data["id"],
|
||||||
|
@ -1232,6 +1233,7 @@ defp object_to_user_data(data) do
|
||||||
follower_address: data["followers"],
|
follower_address: data["followers"],
|
||||||
following_address: data["following"],
|
following_address: data["following"],
|
||||||
bio: data["summary"],
|
bio: data["summary"],
|
||||||
|
actor_type: actor_type,
|
||||||
also_known_as: Map.get(data, "alsoKnownAs", [])
|
also_known_as: Map.get(data, "alsoKnownAs", [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ def render("user.json", %{user: user}) do
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"id" => user.ap_id,
|
"id" => user.ap_id,
|
||||||
"type" => "Person",
|
"type" => user.actor_type,
|
||||||
"following" => "#{user.ap_id}/following",
|
"following" => "#{user.ap_id}/following",
|
||||||
"followers" => "#{user.ap_id}/followers",
|
"followers" => "#{user.ap_id}/followers",
|
||||||
"inbox" => "#{user.ap_id}/inbox",
|
"inbox" => "#{user.ap_id}/inbox",
|
||||||
|
|
|
@ -188,6 +188,7 @@ def update_credentials(%{assigns: %{user: original_user}} = conn, params) do
|
||||||
{:ok, Map.merge(user.pleroma_settings_store, value)}
|
{:ok, Map.merge(user.pleroma_settings_store, value)}
|
||||||
end)
|
end)
|
||||||
|> add_if_present(params, "default_scope", :default_scope)
|
|> add_if_present(params, "default_scope", :default_scope)
|
||||||
|
|> add_if_present(params, "actor_type", :actor_type)
|
||||||
|
|
||||||
emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "")
|
emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "")
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ defp do_render("show.json", %{user: user} = opts) do
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
bot = (user.source_data["type"] || "Person") in ["Application", "Service"]
|
bot = user.actor_type in ["Application", "Service"]
|
||||||
|
|
||||||
emojis =
|
emojis =
|
||||||
(user.source_data["tag"] || [])
|
(user.source_data["tag"] || [])
|
||||||
|
@ -137,7 +137,8 @@ defp do_render("show.json", %{user: user} = opts) do
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
fields: user.raw_fields,
|
fields: user.raw_fields,
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
discoverable: user.discoverable
|
discoverable: user.discoverable,
|
||||||
|
actor_type: user.actor_type
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddActivitypubActorType do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table("users") do
|
||||||
|
add(:actor_type, :string, null: false, default: "Person")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -63,4 +63,84 @@ test "settings are migrated to file and deleted from db", %{temp_file: temp_file
|
||||||
assert file =~ "config :pleroma, :setting_first,"
|
assert file =~ "config :pleroma, :setting_first,"
|
||||||
assert file =~ "config :pleroma, :setting_second,"
|
assert file =~ "config :pleroma, :setting_second,"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "load a settings with large values and pass to file", %{temp_file: temp_file} do
|
||||||
|
Config.create(%{
|
||||||
|
group: "pleroma",
|
||||||
|
key: ":instance",
|
||||||
|
value: [
|
||||||
|
name: "Pleroma",
|
||||||
|
email: "example@example.com",
|
||||||
|
notify_email: "noreply@example.com",
|
||||||
|
description: "A Pleroma instance, an alternative fediverse server",
|
||||||
|
limit: 5_000,
|
||||||
|
chat_limit: 5_000,
|
||||||
|
remote_limit: 100_000,
|
||||||
|
upload_limit: 16_000_000,
|
||||||
|
avatar_upload_limit: 2_000_000,
|
||||||
|
background_upload_limit: 4_000_000,
|
||||||
|
banner_upload_limit: 4_000_000,
|
||||||
|
poll_limits: %{
|
||||||
|
max_options: 20,
|
||||||
|
max_option_chars: 200,
|
||||||
|
min_expiration: 0,
|
||||||
|
max_expiration: 365 * 24 * 60 * 60
|
||||||
|
},
|
||||||
|
registrations_open: true,
|
||||||
|
federating: true,
|
||||||
|
federation_incoming_replies_max_depth: 100,
|
||||||
|
federation_reachability_timeout_days: 7,
|
||||||
|
federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],
|
||||||
|
allow_relay: true,
|
||||||
|
rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,
|
||||||
|
public: true,
|
||||||
|
quarantined_instances: [],
|
||||||
|
managed_config: true,
|
||||||
|
static_dir: "instance/static/",
|
||||||
|
allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"],
|
||||||
|
mrf_transparency: true,
|
||||||
|
mrf_transparency_exclusions: [],
|
||||||
|
autofollowed_nicknames: [],
|
||||||
|
max_pinned_statuses: 1,
|
||||||
|
no_attachment_links: true,
|
||||||
|
welcome_user_nickname: nil,
|
||||||
|
welcome_message: nil,
|
||||||
|
max_report_comment_size: 1000,
|
||||||
|
safe_dm_mentions: false,
|
||||||
|
healthcheck: false,
|
||||||
|
remote_post_retention_days: 90,
|
||||||
|
skip_thread_containment: true,
|
||||||
|
limit_to_local_content: :unauthenticated,
|
||||||
|
dynamic_configuration: false,
|
||||||
|
user_bio_length: 5000,
|
||||||
|
user_name_length: 100,
|
||||||
|
max_account_fields: 10,
|
||||||
|
max_remote_account_fields: 20,
|
||||||
|
account_field_name_length: 512,
|
||||||
|
account_field_value_length: 2048,
|
||||||
|
external_user_synchronization: true,
|
||||||
|
extended_nickname_format: true,
|
||||||
|
multi_factor_authentication: [
|
||||||
|
totp: [
|
||||||
|
# digits 6 or 8
|
||||||
|
digits: 6,
|
||||||
|
period: 30
|
||||||
|
],
|
||||||
|
backup_codes: [
|
||||||
|
number: 2,
|
||||||
|
length: 6
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp", "true"])
|
||||||
|
|
||||||
|
assert Repo.all(Config) == []
|
||||||
|
assert File.exists?(temp_file)
|
||||||
|
{:ok, file} = File.read(temp_file)
|
||||||
|
|
||||||
|
assert file ==
|
||||||
|
"use Mix.Config\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n mrf_transparency: true,\n mrf_transparency_exclusions: [],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n no_attachment_links: true,\n welcome_user_nickname: nil,\n welcome_message: nil,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n dynamic_configuration: false,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -165,15 +165,20 @@ test "search", %{conn: conn} do
|
||||||
assert status["id"] == to_string(activity.id)
|
assert status["id"] == to_string(activity.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "search fetches remote statuses", %{conn: conn} do
|
test "search fetches remote statuses and prefers them over other results", %{conn: conn} do
|
||||||
capture_log(fn ->
|
capture_log(fn ->
|
||||||
|
{:ok, %{id: activity_id}} =
|
||||||
|
CommonAPI.post(insert(:user), %{
|
||||||
|
"status" => "check out https://shitposter.club/notice/2827873"
|
||||||
|
})
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
|
|> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
|
||||||
|
|
||||||
assert results = json_response(conn, 200)
|
assert results = json_response(conn, 200)
|
||||||
|
|
||||||
[status] = results["statuses"]
|
[status, %{"id" => ^activity_id}] = results["statuses"]
|
||||||
|
|
||||||
assert status["uri"] ==
|
assert status["uri"] ==
|
||||||
"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
|
"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
|
||||||
|
|
|
@ -66,6 +66,7 @@ test "Represent a user account" do
|
||||||
note: "valid html",
|
note: "valid html",
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
|
actor_type: "Person",
|
||||||
discoverable: false
|
discoverable: false
|
||||||
},
|
},
|
||||||
fields: []
|
fields: []
|
||||||
|
@ -106,7 +107,8 @@ test "Represent a Service(bot) account" do
|
||||||
insert(:user, %{
|
insert(:user, %{
|
||||||
follower_count: 3,
|
follower_count: 3,
|
||||||
note_count: 5,
|
note_count: 5,
|
||||||
source_data: %{"type" => "Service"},
|
source_data: %{},
|
||||||
|
actor_type: "Service",
|
||||||
nickname: "shp@shitposter.club",
|
nickname: "shp@shitposter.club",
|
||||||
inserted_at: ~N[2017-08-15 15:47:06.597036]
|
inserted_at: ~N[2017-08-15 15:47:06.597036]
|
||||||
})
|
})
|
||||||
|
@ -134,6 +136,7 @@ test "Represent a Service(bot) account" do
|
||||||
note: user.bio,
|
note: user.bio,
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
|
actor_type: "Service",
|
||||||
discoverable: false
|
discoverable: false
|
||||||
},
|
},
|
||||||
fields: []
|
fields: []
|
||||||
|
@ -278,7 +281,8 @@ test "represent an embedded relationship" do
|
||||||
insert(:user, %{
|
insert(:user, %{
|
||||||
follower_count: 0,
|
follower_count: 0,
|
||||||
note_count: 5,
|
note_count: 5,
|
||||||
source_data: %{"type" => "Service"},
|
source_data: %{},
|
||||||
|
actor_type: "Service",
|
||||||
nickname: "shp@shitposter.club",
|
nickname: "shp@shitposter.club",
|
||||||
inserted_at: ~N[2017-08-15 15:47:06.597036]
|
inserted_at: ~N[2017-08-15 15:47:06.597036]
|
||||||
})
|
})
|
||||||
|
@ -311,6 +315,7 @@ test "represent an embedded relationship" do
|
||||||
note: user.bio,
|
note: user.bio,
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
|
actor_type: "Service",
|
||||||
discoverable: false
|
discoverable: false
|
||||||
},
|
},
|
||||||
fields: []
|
fields: []
|
||||||
|
|
Loading…
Reference in New Issue