Merge branch 'develop' into feld-2168-media-preview-proxy
This commit is contained in:
commit
479578b148
54 changed files with 1095 additions and 254 deletions
|
@ -194,7 +194,7 @@ amd64:
|
||||||
variables: &release-variables
|
variables: &release-variables
|
||||||
MIX_ENV: prod
|
MIX_ENV: prod
|
||||||
before_script: &before-release
|
before_script: &before-release
|
||||||
- apt install cmake -y
|
- apt-get update && apt-get install -y cmake
|
||||||
- echo "import Mix.Config" > config/prod.secret.exs
|
- echo "import Mix.Config" > config/prod.secret.exs
|
||||||
- mix local.hex --force
|
- mix local.hex --force
|
||||||
- mix local.rebar --force
|
- mix local.rebar --force
|
||||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -6,18 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- **Breaking:** The default descriptions on uploads are now empty. The old behavior (filename as default) can be configured, see the cheat sheet.
|
||||||
- **Breaking:** Added the ObjectAgePolicy to the default set of MRFs. This will delist and strip the follower collection of any message received that is older than 7 days. This will stop users from seeing very old messages in the timelines. The messages can still be viewed on the user's page and in conversations. They also still trigger notifications.
|
- **Breaking:** Added the ObjectAgePolicy to the default set of MRFs. This will delist and strip the follower collection of any message received that is older than 7 days. This will stop users from seeing very old messages in the timelines. The messages can still be viewed on the user's page and in conversations. They also still trigger notifications.
|
||||||
- **Breaking:** Elixir >=1.9 is now required (was >= 1.8)
|
- **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.
|
- **Breaking:** Configuration: `:auto_linker, :opts` moved to `:pleroma, Pleroma.Formatter`. Old config namespace 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.
|
||||||
|
- **Breaking:** LDAP: Fallback to local database authentication has been removed for security reasons and lack of a mechanism to ensure the passwords are synchronized when LDAP passwords are updated.
|
||||||
|
- **Breaking** Changed defaults for `:restrict_unauthenticated` so that when `:instance, :public` is set to `false` then all `:restrict_unauthenticated` items be effectively set to `true`. If you'd like to allow unauthenticated access to specific API endpoints on a private instance, please explicitly set `:restrict_unauthenticated` to non-default value in `config/prod.secret.exs`.
|
||||||
- In Conversations, return only direct messages as `last_status`
|
- In Conversations, return only direct messages as `last_status`
|
||||||
- Using the `only_media` filter on timelines will now exclude reblog media
|
- Using the `only_media` filter on timelines will now exclude reblog media
|
||||||
- MFR policy to set global expiration for all local Create activities
|
- MFR policy to set global expiration for all local Create activities
|
||||||
- OGP rich media parser merged with TwitterCard
|
- 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: `: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.
|
- 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.
|
|
||||||
- **Breaking:** LDAP: Fallback to local database authentication has been removed for security reasons and lack of a mechanism to ensure the passwords are synchronized when LDAP passwords are updated.
|
|
||||||
- **Breaking** Changed defaults for `:restrict_unauthenticated` so that when `:instance, :public` is set to `false` then all `:restrict_unauthenticated` items be effectively set to `true`. If you'd like to allow unauthenticated access to specific API endpoints on a private instance, please explicitly set `:restrict_unauthenticated` to non-default value in `config/prod.secret.exs`.
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
|
@ -25,33 +27,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- **Breaking:** Pleroma API: The routes to update avatar, banner and background have been removed.
|
- **Breaking:** Pleroma API: The routes to update avatar, banner and background have been removed.
|
||||||
- **Breaking:** Image description length is limited now.
|
- **Breaking:** Image description length is limited now.
|
||||||
- **Breaking:** Emoji API: changed methods and renamed routes.
|
- **Breaking:** Emoji API: changed methods and renamed routes.
|
||||||
|
- **Breaking:** Notification Settings API for suppressing notifications has been simplified down to `block_from_strangers`.
|
||||||
|
- **Breaking:** Notification Settings API option for hiding push notification contents has been renamed to `hide_notification_contents`.
|
||||||
- MastodonAPI: Allow removal of avatar, banner and background.
|
- MastodonAPI: Allow removal of avatar, banner and background.
|
||||||
- Streaming: Repeats of a user's posts will no longer be pushed to the user's stream.
|
- Streaming: Repeats of a user's posts will no longer be pushed to the user's stream.
|
||||||
- Mastodon API: Added `pleroma.metadata.fields_limits` to /api/v1/instance
|
- Mastodon API: Added `pleroma.metadata.fields_limits` to /api/v1/instance
|
||||||
- Mastodon API: On deletion, returns the original post text.
|
- Mastodon API: On deletion, returns the original post text.
|
||||||
- Mastodon API: Add `pleroma.unread_count` to the Marker entity.
|
- Mastodon API: Add `pleroma.unread_count` to the Marker entity.
|
||||||
- **Breaking:** Notification Settings API for suppressing notifications
|
|
||||||
has been simplified down to `block_from_strangers`.
|
|
||||||
- **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: 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`
|
- 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.
|
- Pleroma API: `/api/pleroma/captcha` responses now include `seconds_valid` with an integer value.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Admin API Changes</summary>
|
<summary>Admin API Changes</summary>
|
||||||
|
|
||||||
|
- **Breaking** Changed relay `/api/pleroma/admin/relay` endpoints response format.
|
||||||
- Status visibility stats: now can return stats per instance.
|
- Status visibility stats: now can return stats per instance.
|
||||||
|
|
||||||
- Mix task to refresh counter cache (`mix pleroma.refresh_counter_cache`)
|
- Mix task to refresh counter cache (`mix pleroma.refresh_counter_cache`)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- **Breaking:** removed `with_move` parameter from notifications timeline.
|
- **Breaking:** removed `with_move` parameter from notifications timeline.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Frontends: Add mix task to install frontends.
|
||||||
|
- Frontends: Add configurable frontends for primary and admin fe.
|
||||||
- Configuration: Added a blacklist for email servers.
|
- Configuration: Added a blacklist for email servers.
|
||||||
- Chats: Added `accepts_chat_messages` field to user, exposed in APIs and federation.
|
- Chats: Added `accepts_chat_messages` field to user, exposed in APIs and federation.
|
||||||
- Chats: Added support for federated chats. For details, see the docs.
|
- Chats: Added support for federated chats. For details, see the docs.
|
||||||
|
@ -107,6 +112,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Emoji Packs could not be listed when instance was set to `public: false`
|
- Emoji Packs could not be listed when instance was set to `public: false`
|
||||||
- Fix whole_word always returning false on filter get requests
|
- Fix whole_word always returning false on filter get requests
|
||||||
- Migrations not working on OTP releases if the database was connected over ssl
|
- Migrations not working on OTP releases if the database was connected over ssl
|
||||||
|
- Fix relay following
|
||||||
|
|
||||||
## [Unreleased (patch)]
|
## [Unreleased (patch)]
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,8 @@ config :pleroma, Pleroma.Upload,
|
||||||
pool: :upload
|
pool: :upload
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
filename_display_max_length: 30
|
filename_display_max_length: 30,
|
||||||
|
default_description: nil
|
||||||
|
|
||||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads"
|
config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads"
|
||||||
|
|
||||||
|
@ -682,7 +683,50 @@ config :pleroma, :static_fe, enabled: false
|
||||||
# With no frontend configuration, the bundled files from the `static` directory will
|
# With no frontend configuration, the bundled files from the `static` directory will
|
||||||
# be used.
|
# be used.
|
||||||
#
|
#
|
||||||
# config :pleroma, :frontends, primary: %{"name" => "pleroma", "ref" => "develop"}
|
# config :pleroma, :frontends,
|
||||||
|
# primary: %{"name" => "pleroma-fe", "ref" => "develop"},
|
||||||
|
# admin: %{"name" => "admin-fe", "ref" => "stable"},
|
||||||
|
# available: %{...}
|
||||||
|
|
||||||
|
config :pleroma, :frontends,
|
||||||
|
available: %{
|
||||||
|
"kenoma" => %{
|
||||||
|
"name" => "kenoma",
|
||||||
|
"git" => "https://git.pleroma.social/lambadalambda/kenoma",
|
||||||
|
"build_url" =>
|
||||||
|
"https://git.pleroma.social/lambadalambda/kenoma/-/jobs/artifacts/${ref}/download?job=build",
|
||||||
|
"ref" => "master"
|
||||||
|
},
|
||||||
|
"pleroma-fe" => %{
|
||||||
|
"name" => "pleroma-fe",
|
||||||
|
"git" => "https://git.pleroma.social/pleroma/pleroma-fe",
|
||||||
|
"build_url" =>
|
||||||
|
"https://git.pleroma.social/pleroma/pleroma-fe/-/jobs/artifacts/${ref}/download?job=build",
|
||||||
|
"ref" => "develop"
|
||||||
|
},
|
||||||
|
"fedi-fe" => %{
|
||||||
|
"name" => "fedi-fe",
|
||||||
|
"git" => "https://git.pleroma.social/pleroma/fedi-fe",
|
||||||
|
"build_url" =>
|
||||||
|
"https://git.pleroma.social/pleroma/fedi-fe/-/jobs/artifacts/${ref}/download?job=build",
|
||||||
|
"ref" => "master"
|
||||||
|
},
|
||||||
|
"admin-fe" => %{
|
||||||
|
"name" => "admin-fe",
|
||||||
|
"git" => "https://git.pleroma.social/pleroma/admin-fe",
|
||||||
|
"build_url" =>
|
||||||
|
"https://git.pleroma.social/pleroma/admin-fe/-/jobs/artifacts/${ref}/download?job=build",
|
||||||
|
"ref" => "develop"
|
||||||
|
},
|
||||||
|
"soapbox-fe" => %{
|
||||||
|
"name" => "soapbox-fe",
|
||||||
|
"git" => "https://gitlab.com/soapbox-pub/soapbox-fe",
|
||||||
|
"build_url" =>
|
||||||
|
"https://gitlab.com/soapbox-pub/soapbox-fe/-/jobs/artifacts/${ref}/download?job=build-production",
|
||||||
|
"ref" => "v1.0.0",
|
||||||
|
"build_dir" => "static"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config :pleroma, :web_cache_ttl,
|
config :pleroma, :web_cache_ttl,
|
||||||
activity_pub: nil,
|
activity_pub: nil,
|
||||||
|
|
|
@ -12,6 +12,55 @@ websocket_config = [
|
||||||
compress: false
|
compress: false
|
||||||
]
|
]
|
||||||
|
|
||||||
|
installed_frontend_options = [
|
||||||
|
%{
|
||||||
|
key: "name",
|
||||||
|
label: "Name",
|
||||||
|
type: :string,
|
||||||
|
description:
|
||||||
|
"Name of the installed frontend. Valid config must include both `Name` and `Reference` values."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: "ref",
|
||||||
|
label: "Reference",
|
||||||
|
type: :string,
|
||||||
|
description:
|
||||||
|
"Reference of the installed frontend to be used. Valid config must include both `Name` and `Reference` values."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
frontend_options = [
|
||||||
|
%{
|
||||||
|
key: "name",
|
||||||
|
label: "Name",
|
||||||
|
type: :string,
|
||||||
|
description: "Name of the frontend."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: "ref",
|
||||||
|
label: "Reference",
|
||||||
|
type: :string,
|
||||||
|
description: "Reference of the frontend to be used."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: "git",
|
||||||
|
type: :string,
|
||||||
|
description: "URL of the git repository of the frontend"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: "build_url",
|
||||||
|
type: :string,
|
||||||
|
description:
|
||||||
|
"Either an url to a zip file containing the frontend or a template to build it by inserting the `ref`. The string `${ref}` will be replaced by the configured `ref`.",
|
||||||
|
example: "https://some.url/builds/${ref}.zip"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: "build_dir",
|
||||||
|
type: :string,
|
||||||
|
description: "The directory inside the zip file "
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
config :pleroma, :config_description, [
|
config :pleroma, :config_description, [
|
||||||
%{
|
%{
|
||||||
group: :pleroma,
|
group: :pleroma,
|
||||||
|
@ -3609,21 +3658,40 @@ config :pleroma, :config_description, [
|
||||||
key: :primary,
|
key: :primary,
|
||||||
type: :map,
|
type: :map,
|
||||||
description: "Primary frontend, the one that is served for all pages by default",
|
description: "Primary frontend, the one that is served for all pages by default",
|
||||||
|
children: installed_frontend_options
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :admin,
|
||||||
|
type: :map,
|
||||||
|
description: "Admin frontend",
|
||||||
|
children: installed_frontend_options
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :available,
|
||||||
|
type: :map,
|
||||||
|
description:
|
||||||
|
"A map containing available frontends and parameters for their installation.",
|
||||||
children: [
|
children: [
|
||||||
%{
|
frontend_options
|
||||||
key: "name",
|
]
|
||||||
label: "Name",
|
}
|
||||||
type: :string,
|
]
|
||||||
description:
|
},
|
||||||
"Name of the installed primary frontend. Valid config must include both `Name` and `Reference` values."
|
%{
|
||||||
},
|
group: :pleroma,
|
||||||
%{
|
key: Pleroma.Web.Preload,
|
||||||
key: "ref",
|
type: :group,
|
||||||
label: "Reference",
|
description: "Preload-related settings",
|
||||||
type: :string,
|
children: [
|
||||||
description:
|
%{
|
||||||
"Reference of the installed primary frontend to be used. Valid config must include both `Name` and `Reference` values."
|
key: :providers,
|
||||||
}
|
type: {:list, :module},
|
||||||
|
description: "List of preload providers to enable",
|
||||||
|
suggestions: [
|
||||||
|
Pleroma.Web.Preload.Providers.Instance,
|
||||||
|
Pleroma.Web.Preload.Providers.User,
|
||||||
|
Pleroma.Web.Preload.Providers.Timelines,
|
||||||
|
Pleroma.Web.Preload.Providers.StatusNet
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -21,7 +21,10 @@ config :logger, :console,
|
||||||
|
|
||||||
config :pleroma, :auth, oauth_consumer_strategies: []
|
config :pleroma, :auth, oauth_consumer_strategies: []
|
||||||
|
|
||||||
config :pleroma, Pleroma.Upload, filters: [], link_name: false
|
config :pleroma, Pleroma.Upload,
|
||||||
|
filters: [],
|
||||||
|
link_name: false,
|
||||||
|
default_description: :filename
|
||||||
|
|
||||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "test/uploads"
|
config :pleroma, Pleroma.Uploaders.Local, uploads: "test/uploads"
|
||||||
|
|
||||||
|
|
|
@ -313,31 +313,53 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
||||||
- On failure: `Not found`
|
- On failure: `Not found`
|
||||||
- On success: JSON array of user's latest statuses
|
- On success: JSON array of user's latest statuses
|
||||||
|
|
||||||
|
## `GET /api/pleroma/admin/relay`
|
||||||
|
|
||||||
|
### List Relays
|
||||||
|
|
||||||
|
Params: none
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* On success: JSON array of relays
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"actor": "https://example.com/relay", "followed_back": true},
|
||||||
|
{"actor": "https://example2.com/relay", "followed_back": false}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
## `POST /api/pleroma/admin/relay`
|
## `POST /api/pleroma/admin/relay`
|
||||||
|
|
||||||
### Follow a Relay
|
### Follow a Relay
|
||||||
|
|
||||||
- Params:
|
Params:
|
||||||
- `relay_url`
|
|
||||||
- Response:
|
* `relay_url`
|
||||||
- On success: URL of the followed relay
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* On success: relay json object
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"actor": "https://example.com/relay", "followed_back": true}
|
||||||
|
```
|
||||||
|
|
||||||
## `DELETE /api/pleroma/admin/relay`
|
## `DELETE /api/pleroma/admin/relay`
|
||||||
|
|
||||||
### Unfollow a Relay
|
### Unfollow a Relay
|
||||||
|
|
||||||
- Params:
|
Params:
|
||||||
- `relay_url`
|
|
||||||
- Response:
|
|
||||||
- On success: URL of the unfollowed relay
|
|
||||||
|
|
||||||
## `GET /api/pleroma/admin/relay`
|
* `relay_url`
|
||||||
|
|
||||||
### List Relays
|
Response:
|
||||||
|
|
||||||
- Params: none
|
* On success: URL of the unfollowed relay
|
||||||
- Response:
|
|
||||||
- On success: JSON array of relays
|
```json
|
||||||
|
{"https://example.com/relay"}
|
||||||
|
```
|
||||||
|
|
||||||
## `POST /api/pleroma/admin/users/invite_token`
|
## `POST /api/pleroma/admin/users/invite_token`
|
||||||
|
|
||||||
|
|
69
docs/administration/CLI_tasks/frontend.md
Normal file
69
docs/administration/CLI_tasks/frontend.md
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
# Managing frontends
|
||||||
|
|
||||||
|
`mix pleroma.frontend install <frontend> [--ref <ref>] [--file <file>] [--build-url <build-url>] [--path <path>] [--build-dir <build-dir>]`
|
||||||
|
|
||||||
|
Frontend can be installed either from local zip file, or automatically downloaded from the web.
|
||||||
|
|
||||||
|
You can give all the options directly on the command like, but missing information will be filled out by looking at the data configured under `frontends.available` in the config files.
|
||||||
|
|
||||||
|
Currently known `<frontend>` values are:
|
||||||
|
- [admin-fe](https://git.pleroma.social/pleroma/admin-fe)
|
||||||
|
- [kenoma](http://git.pleroma.social/lambadalambda/kenoma)
|
||||||
|
- [pleroma-fe](http://git.pleroma.social/pleroma/pleroma-fe)
|
||||||
|
- [fedi-fe](https://git.pleroma.social/pleroma/fedi-fe)
|
||||||
|
- [soapbox-fe](https://gitlab.com/soapbox-pub/soapbox-fe)
|
||||||
|
|
||||||
|
You can still install frontends that are not configured, see below.
|
||||||
|
|
||||||
|
## Example installations for a known frontend
|
||||||
|
|
||||||
|
For a frontend configured under the `available` key, it's enough to install it by name.
|
||||||
|
|
||||||
|
```sh tab="OTP"
|
||||||
|
./bin/pleroma_ctl frontend install pleroma
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh tab="From Source"
|
||||||
|
mix pleroma.frontend install pleroma
|
||||||
|
```
|
||||||
|
|
||||||
|
This will download the latest build for the the pre-configured `ref` and install it. It can then be configured as the one of the served frontends in the config file (see `primary` or `admin`).
|
||||||
|
|
||||||
|
You can override any of the details. To install a pleroma build from a different url, you could do this:
|
||||||
|
|
||||||
|
```sh tab="OPT"
|
||||||
|
./bin/pleroma_ctl frontend install pleroma --ref 2hu_edition --build-url https://example.org/raymoo.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh tab="From Source"
|
||||||
|
mix pleroma.frontend install pleroma --ref 2hu_edition --build-url https://example.org/raymoo.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly, you can also install from a local zip file.
|
||||||
|
|
||||||
|
```sh tab="OTP"
|
||||||
|
./bin/pleroma_ctl frontend install pleroma --ref mybuild --file ~/Downloads/doomfe.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh tab="From Source"
|
||||||
|
mix pleroma.frontend install pleroma --ref mybuild --file ~/Downloads/doomfe.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting frontend will always be installed into a folder of this template: `${instance_static}/frontends/${name}/${ref}`
|
||||||
|
|
||||||
|
Careful: This folder will be completely replaced on installation
|
||||||
|
|
||||||
|
## Example installation for an unknown frontend
|
||||||
|
|
||||||
|
The installation process is the same, but you will have to give all the needed options on the commond line. For example:
|
||||||
|
|
||||||
|
```sh tab="OTP"
|
||||||
|
./bin/pleroma_ctl frontend install gensokyo --ref master --build-url https://gensokyo.2hu/builds/marisa.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh tab="From Source"
|
||||||
|
mix pleroma.frontend install gensokyo --ref master --build-url https://gensokyo.2hu/builds/marisa.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't have a zip file but just want to install a frontend from a local path, you can simply copy the files over a folder of this template: `${instance_static}/frontends/${name}/${ref}`
|
||||||
|
|
|
@ -6,11 +6,11 @@ Feel free to contact us to be added to this list!
|
||||||
### Roma for Desktop
|
### Roma for Desktop
|
||||||
- Homepage: <https://www.pleroma.com/#desktopApp>
|
- Homepage: <https://www.pleroma.com/#desktopApp>
|
||||||
- Source Code: <https://github.com/roma-apps/roma-desktop>
|
- Source Code: <https://github.com/roma-apps/roma-desktop>
|
||||||
- Platforms: Windows, Mac, (Linux?)
|
- Platforms: Windows, Mac, Linux
|
||||||
- Features: Streaming Ready
|
- Features: Streaming Ready
|
||||||
|
|
||||||
### Social
|
### Social
|
||||||
- Source Code: <https://gitlab.gnome.org/BrainBlasted/Social>
|
- Source Code: <https://gitlab.gnome.org/World/Social>
|
||||||
- Contact: [@brainblasted@social.libre.fi](https://social.libre.fi/users/brainblasted)
|
- Contact: [@brainblasted@social.libre.fi](https://social.libre.fi/users/brainblasted)
|
||||||
- Platforms: Linux (GNOME)
|
- Platforms: Linux (GNOME)
|
||||||
- Note(2019-01-28): Not at a pre-alpha stage yet
|
- Note(2019-01-28): Not at a pre-alpha stage yet
|
||||||
|
@ -35,7 +35,7 @@ Feel free to contact us to be added to this list!
|
||||||
- Source Code: <https://framagit.org/tom79/fedilab/>
|
- Source Code: <https://framagit.org/tom79/fedilab/>
|
||||||
- Contact: [@fedilab@framapiaf.org](https://framapiaf.org/users/fedilab)
|
- Contact: [@fedilab@framapiaf.org](https://framapiaf.org/users/fedilab)
|
||||||
- Platforms: Android
|
- Platforms: Android
|
||||||
- Features: Streaming Ready, Moderation, Text Formatting
|
- Features: Streaming Ready, Moderation, Text Formatting
|
||||||
|
|
||||||
### Kyclos
|
### Kyclos
|
||||||
- Source Code: <https://git.pleroma.social/pleroma/harbour-kyclos>
|
- Source Code: <https://git.pleroma.social/pleroma/harbour-kyclos>
|
||||||
|
@ -48,16 +48,9 @@ Feel free to contact us to be added to this list!
|
||||||
- Platforms: Android
|
- Platforms: Android
|
||||||
- Features: No Streaming, Emoji Reactions, Text Formatting, FE Stickers
|
- Features: No Streaming, Emoji Reactions, Text Formatting, FE Stickers
|
||||||
|
|
||||||
### Nekonium
|
|
||||||
- Homepage: [F-Droid Repository](https://repo.gdgd.jp.net/), [Google Play](https://play.google.com/store/apps/details?id=com.apps.nekonium), [Amazon](https://www.amazon.co.jp/dp/B076FXPRBC/)
|
|
||||||
- Source: <https://gogs.gdgd.jp.net/lin/nekonium>
|
|
||||||
- Contact: [@lin@pleroma.gdgd.jp.net](https://pleroma.gdgd.jp.net/users/lin)
|
|
||||||
- Platforms: Android
|
|
||||||
- Features: Streaming Ready
|
|
||||||
|
|
||||||
### Fedi
|
### Fedi
|
||||||
- Homepage: <https://www.fediapp.com/>
|
- Homepage: <https://www.fediapp.com/>
|
||||||
- Source Code: Proprietary, but free
|
- Source Code: Proprietary, but gratis
|
||||||
- Platforms: iOS, Android
|
- Platforms: iOS, Android
|
||||||
- Features: Pleroma-specific features like Reactions
|
- Features: Pleroma-specific features like Reactions
|
||||||
|
|
||||||
|
@ -70,9 +63,9 @@ Feel free to contact us to be added to this list!
|
||||||
|
|
||||||
### Twidere
|
### Twidere
|
||||||
- Homepage: <https://twidere.mariotaku.org/>
|
- Homepage: <https://twidere.mariotaku.org/>
|
||||||
- Source Code: <https://github.com/TwidereProject/Twidere-Android/>, <https://github.com/TwidereProject/Twidere-iOS/>
|
- Source Code: <https://github.com/TwidereProject/Twidere-Android/>
|
||||||
- Contact: <me@mariotaku.org>
|
- Contact: <me@mariotaku.org>
|
||||||
- Platform: Android, iOS
|
- Platform: Android
|
||||||
- Features: No Streaming
|
- Features: No Streaming
|
||||||
|
|
||||||
### Indigenous
|
### Indigenous
|
||||||
|
@ -89,11 +82,6 @@ Feel free to contact us to be added to this list!
|
||||||
- Contact: [@gcupc@glitch.social](https://glitch.social/users/gcupc)
|
- Contact: [@gcupc@glitch.social](https://glitch.social/users/gcupc)
|
||||||
- Features: No Streaming
|
- Features: No Streaming
|
||||||
|
|
||||||
### Feather
|
|
||||||
- Source Code: <https://github.com/kaniini/feather>
|
|
||||||
- Contact: [@kaniini@pleroma.site](https://pleroma.site/kaniini)
|
|
||||||
- Features: No Streaming
|
|
||||||
|
|
||||||
### Halcyon
|
### Halcyon
|
||||||
- Source Code: <https://notabug.org/halcyon-suite/halcyon>
|
- Source Code: <https://notabug.org/halcyon-suite/halcyon>
|
||||||
- Contact: [@halcyon@social.csswg.org](https://social.csswg.org/users/halcyon)
|
- Contact: [@halcyon@social.csswg.org](https://social.csswg.org/users/halcyon)
|
||||||
|
@ -107,6 +95,15 @@ Feel free to contact us to be added to this list!
|
||||||
- Features: No Streaming
|
- Features: No Streaming
|
||||||
|
|
||||||
### Sengi
|
### Sengi
|
||||||
|
- Homepage: <https://nicolasconstant.github.io/sengi/>
|
||||||
- Source Code: <https://github.com/NicolasConstant/sengi>
|
- Source Code: <https://github.com/NicolasConstant/sengi>
|
||||||
- Contact: [@sengi_app@mastodon.social](https://mastodon.social/users/sengi_app)
|
- Contact: [@sengi_app@mastodon.social](https://mastodon.social/users/sengi_app)
|
||||||
- Note(2019-01-28): The development is currently in a early stage.
|
|
||||||
|
### DashFE
|
||||||
|
- Source Code: <https://notabug.org/daisuke/DashboardFE>
|
||||||
|
- Contact: [@dashfe@stereophonic.space](https://stereophonic.space/users/dashfe)
|
||||||
|
|
||||||
|
### BloatFE
|
||||||
|
- Source Code: <https://git.freesoftwareextremist.com/bloat/>
|
||||||
|
- Contact: [@r@freesoftwareextremist.com](https://freesoftwareextremist.com/users/r)
|
||||||
|
- Features: Does not requires JavaScript
|
||||||
|
|
|
@ -552,6 +552,7 @@ the source code is here: [kocaptcha](https://github.com/koto-bank/kocaptcha). Th
|
||||||
* `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it.
|
* `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it.
|
||||||
* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation.
|
* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation.
|
||||||
* `filename_display_max_length`: Set max length of a filename to display. 0 = no limit. Default: 30.
|
* `filename_display_max_length`: Set max length of a filename to display. 0 = no limit. Default: 30.
|
||||||
|
* `default_description`: Sets which default description an image has if none is set explicitly. Options: nil (default) - Don't set a default, :filename - use the filename of the file, a string (e.g. "attachment") - Use this string
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
`strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`.
|
`strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`.
|
||||||
|
@ -1069,11 +1070,11 @@ Control favicons for instances.
|
||||||
|
|
||||||
Frontends in Pleroma are swappable - you can specify which one to use here.
|
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.
|
You can set a frontends for the key `primary` and `admin` 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.
|
The key `primary` refers to the frontend that will be served by default for general requests. The key `admin` refers to the frontend that will be served at the `/pleroma/admin` path.
|
||||||
|
|
||||||
If you don't set anything here, the bundled frontend will be used.
|
If you don't set anything here, the bundled frontends will be used.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -1082,6 +1083,10 @@ config :pleroma, :frontends,
|
||||||
primary: %{
|
primary: %{
|
||||||
"name" => "pleroma",
|
"name" => "pleroma",
|
||||||
"ref" => "stable"
|
"ref" => "stable"
|
||||||
|
},
|
||||||
|
admin: %{
|
||||||
|
"name" => "admin",
|
||||||
|
"ref" => "develop"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,27 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# REQUIRE: DAEMON postgresql
|
# $FreeBSD$
|
||||||
# PROVIDE: pleroma
|
# PROVIDE: pleroma
|
||||||
|
# REQUIRE: DAEMON postgresql
|
||||||
|
# KEYWORD: shutdown
|
||||||
|
|
||||||
# sudo -u pleroma MIX_ENV=prod elixir --erl \"-detached\" -S mix phx.server
|
# sudo -u pleroma MIX_ENV=prod elixir --erl \"-detached\" -S mix phx.server
|
||||||
|
|
||||||
. /etc/rc.subr
|
. /etc/rc.subr
|
||||||
|
|
||||||
name="pleroma"
|
name=pleroma
|
||||||
|
rcvar=pleroma_enable
|
||||||
|
|
||||||
desc="Pleroma Social Media Platform"
|
desc="Pleroma Social Media Platform"
|
||||||
rcvar=${name}_enable
|
|
||||||
command="/usr/local/bin/elixir"
|
|
||||||
command_args="--erl \"-detached\" -S /usr/local/bin/mix phx.server"
|
|
||||||
pidfile="/dev/null"
|
|
||||||
|
|
||||||
pleroma_user="pleroma"
|
|
||||||
pleroma_home="/home/pleroma"
|
|
||||||
pleroma_chdir="${pleroma_home}/pleroma"
|
|
||||||
pleroma_env="HOME=${pleroma_home} MIX_ENV=prod"
|
|
||||||
|
|
||||||
check_pidfile()
|
|
||||||
{
|
|
||||||
pid=$(pgrep beam.smp$)
|
|
||||||
echo -n "${pid}"
|
|
||||||
}
|
|
||||||
|
|
||||||
load_rc_config ${name}
|
load_rc_config ${name}
|
||||||
|
|
||||||
|
: ${pleroma_user:=pleroma}
|
||||||
|
: ${pleroma_home:=$(getent passwd ${pleroma_user} | awk -F: '{print $6}')}
|
||||||
|
: ${pleroma_chdir:="${pleroma_home}/pleroma"}
|
||||||
|
: ${pleroma_env:="HOME=${pleroma_home} MIX_ENV=prod"}
|
||||||
|
|
||||||
|
command=/usr/local/bin/elixir
|
||||||
|
command_args="--erl \"-detached\" -S /usr/local/bin/mix phx.server"
|
||||||
|
procname="*beam.smp"
|
||||||
|
|
||||||
run_rc_command "$1"
|
run_rc_command "$1"
|
||||||
|
|
|
@ -14,7 +14,7 @@ defmodule Mix.Pleroma do
|
||||||
:swoosh,
|
:swoosh,
|
||||||
:timex
|
:timex
|
||||||
]
|
]
|
||||||
@cachex_children ["object", "user"]
|
@cachex_children ["object", "user", "scrubber"]
|
||||||
@doc "Common functions to be reused in mix tasks"
|
@doc "Common functions to be reused in mix tasks"
|
||||||
def start_pleroma do
|
def start_pleroma do
|
||||||
Pleroma.Config.Holder.save_default()
|
Pleroma.Config.Holder.save_default()
|
||||||
|
|
|
@ -15,7 +15,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
||||||
{options, [], []} = parse_global_opts(args)
|
{options, [], []} = parse_global_opts(args)
|
||||||
|
|
||||||
url_or_path = options[:manifest] || default_manifest()
|
url_or_path = options[:manifest] || default_manifest()
|
||||||
manifest = fetch_and_decode(url_or_path)
|
manifest = fetch_and_decode!(url_or_path)
|
||||||
|
|
||||||
Enum.each(manifest, fn {name, info} ->
|
Enum.each(manifest, fn {name, info} ->
|
||||||
to_print = [
|
to_print = [
|
||||||
|
@ -42,7 +42,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
||||||
|
|
||||||
url_or_path = options[:manifest] || default_manifest()
|
url_or_path = options[:manifest] || default_manifest()
|
||||||
|
|
||||||
manifest = fetch_and_decode(url_or_path)
|
manifest = fetch_and_decode!(url_or_path)
|
||||||
|
|
||||||
for pack_name <- pack_names do
|
for pack_name <- pack_names do
|
||||||
if Map.has_key?(manifest, pack_name) do
|
if Map.has_key?(manifest, pack_name) do
|
||||||
|
@ -92,7 +92,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
files = fetch_and_decode(files_loc)
|
files = fetch_and_decode!(files_loc)
|
||||||
|
|
||||||
IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
|
IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
|
||||||
|
|
||||||
|
@ -243,9 +243,11 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
||||||
IO.puts("Emoji packs have been reloaded.")
|
IO.puts("Emoji packs have been reloaded.")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp fetch_and_decode(from) do
|
defp fetch_and_decode!(from) do
|
||||||
with {:ok, json} <- fetch(from) do
|
with {:ok, json} <- fetch(from) do
|
||||||
Jason.decode!(json)
|
Jason.decode!(json)
|
||||||
|
else
|
||||||
|
{:error, error} -> raise "#{from} cannot be fetched. Error: #{error} occur."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
140
lib/mix/tasks/pleroma/frontend.ex
Normal file
140
lib/mix/tasks/pleroma/frontend.ex
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
# 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.Frontend do
|
||||||
|
use Mix.Task
|
||||||
|
|
||||||
|
import Mix.Pleroma
|
||||||
|
|
||||||
|
@shortdoc "Manages bundled Pleroma frontends"
|
||||||
|
|
||||||
|
@moduledoc File.read!("docs/administration/CLI_tasks/frontend.md")
|
||||||
|
|
||||||
|
def run(["install", "none" | _args]) do
|
||||||
|
shell_info("Skipping frontend installation because none was requested")
|
||||||
|
"none"
|
||||||
|
end
|
||||||
|
|
||||||
|
def run(["install", frontend | args]) do
|
||||||
|
log_level = Logger.level()
|
||||||
|
Logger.configure(level: :warn)
|
||||||
|
start_pleroma()
|
||||||
|
|
||||||
|
{options, [], []} =
|
||||||
|
OptionParser.parse(
|
||||||
|
args,
|
||||||
|
strict: [
|
||||||
|
ref: :string,
|
||||||
|
static_dir: :string,
|
||||||
|
build_url: :string,
|
||||||
|
build_dir: :string,
|
||||||
|
file: :string
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
instance_static_dir =
|
||||||
|
with nil <- options[:static_dir] do
|
||||||
|
Pleroma.Config.get!([:instance, :static_dir])
|
||||||
|
end
|
||||||
|
|
||||||
|
cmd_frontend_info = %{
|
||||||
|
"name" => frontend,
|
||||||
|
"ref" => options[:ref],
|
||||||
|
"build_url" => options[:build_url],
|
||||||
|
"build_dir" => options[:build_dir]
|
||||||
|
}
|
||||||
|
|
||||||
|
config_frontend_info = Pleroma.Config.get([:frontends, :available, frontend], %{})
|
||||||
|
|
||||||
|
frontend_info =
|
||||||
|
Map.merge(config_frontend_info, cmd_frontend_info, fn _key, config, cmd ->
|
||||||
|
# This only overrides things that are actually set
|
||||||
|
cmd || config
|
||||||
|
end)
|
||||||
|
|
||||||
|
ref = frontend_info["ref"]
|
||||||
|
|
||||||
|
unless ref do
|
||||||
|
raise "No ref given or configured"
|
||||||
|
end
|
||||||
|
|
||||||
|
dest =
|
||||||
|
Path.join([
|
||||||
|
instance_static_dir,
|
||||||
|
"frontends",
|
||||||
|
frontend,
|
||||||
|
ref
|
||||||
|
])
|
||||||
|
|
||||||
|
fe_label = "#{frontend} (#{ref})"
|
||||||
|
|
||||||
|
tmp_dir = Path.join(dest, "tmp")
|
||||||
|
|
||||||
|
with {_, :ok} <-
|
||||||
|
{:download_or_unzip, download_or_unzip(frontend_info, tmp_dir, options[:file])},
|
||||||
|
shell_info("Installing #{fe_label} to #{dest}"),
|
||||||
|
:ok <- install_frontend(frontend_info, tmp_dir, dest) do
|
||||||
|
File.rm_rf!(tmp_dir)
|
||||||
|
shell_info("Frontend #{fe_label} installed to #{dest}")
|
||||||
|
|
||||||
|
Logger.configure(level: log_level)
|
||||||
|
else
|
||||||
|
{:download_or_unzip, _} ->
|
||||||
|
shell_info("Could not download or unzip the frontend")
|
||||||
|
|
||||||
|
_e ->
|
||||||
|
shell_info("Could not install the frontend")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp download_or_unzip(frontend_info, temp_dir, file) do
|
||||||
|
if file do
|
||||||
|
with {:ok, zip} <- File.read(Path.expand(file)) do
|
||||||
|
unzip(zip, temp_dir)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
download_build(frontend_info, temp_dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def unzip(zip, dest) do
|
||||||
|
with {:ok, unzipped} <- :zip.unzip(zip, [:memory]) do
|
||||||
|
File.rm_rf!(dest)
|
||||||
|
File.mkdir_p!(dest)
|
||||||
|
|
||||||
|
Enum.each(unzipped, fn {filename, data} ->
|
||||||
|
path = filename
|
||||||
|
|
||||||
|
new_file_path = Path.join(dest, path)
|
||||||
|
|
||||||
|
new_file_path
|
||||||
|
|> Path.dirname()
|
||||||
|
|> File.mkdir_p!()
|
||||||
|
|
||||||
|
File.write!(new_file_path, data)
|
||||||
|
end)
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp download_build(frontend_info, dest) do
|
||||||
|
shell_info("Downloading pre-built bundle for #{frontend_info["name"]}")
|
||||||
|
url = String.replace(frontend_info["build_url"], "${ref}", frontend_info["ref"])
|
||||||
|
|
||||||
|
with {:ok, %{status: 200, body: zip_body}} <-
|
||||||
|
Pleroma.HTTP.get(url, [], timeout: 120_000, recv_timeout: 120_000) do
|
||||||
|
unzip(zip_body, dest)
|
||||||
|
else
|
||||||
|
e -> {:error, e}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp install_frontend(frontend_info, source, dest) do
|
||||||
|
from = frontend_info["build_dir"] || "dist"
|
||||||
|
File.mkdir_p!(dest)
|
||||||
|
File.cp_r!(Path.join([source, from]), dest)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
|
@ -35,10 +35,16 @@ defmodule Mix.Tasks.Pleroma.Relay do
|
||||||
def run(["list"]) do
|
def run(["list"]) do
|
||||||
start_pleroma()
|
start_pleroma()
|
||||||
|
|
||||||
with {:ok, list} <- Relay.list(true) do
|
with {:ok, list} <- Relay.list() do
|
||||||
list |> Enum.each(&shell_info(&1))
|
Enum.each(list, &print_relay_url/1)
|
||||||
else
|
else
|
||||||
{:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}")
|
{:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp print_relay_url(%{followed_back: false} = relay) do
|
||||||
|
shell_info("#{relay.actor} - no Accept received (relay didn't follow back)")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp print_relay_url(relay), do: shell_info(relay.actor)
|
||||||
end
|
end
|
||||||
|
|
|
@ -107,25 +107,34 @@ defmodule Pleroma.Emails.UserEmail do
|
||||||
|> Enum.filter(&(&1.activity.data["type"] == "Create"))
|
|> Enum.filter(&(&1.activity.data["type"] == "Create"))
|
||||||
|> Enum.map(fn notification ->
|
|> Enum.map(fn notification ->
|
||||||
object = Pleroma.Object.normalize(notification.activity)
|
object = Pleroma.Object.normalize(notification.activity)
|
||||||
object = update_in(object.data["content"], &format_links/1)
|
|
||||||
|
|
||||||
%{
|
if not is_nil(object) do
|
||||||
data: notification,
|
object = update_in(object.data["content"], &format_links/1)
|
||||||
object: object,
|
|
||||||
from: User.get_by_ap_id(notification.activity.actor)
|
%{
|
||||||
}
|
data: notification,
|
||||||
|
object: object,
|
||||||
|
from: User.get_by_ap_id(notification.activity.actor)
|
||||||
|
}
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|> Enum.filter(& &1)
|
||||||
|
|
||||||
followers =
|
followers =
|
||||||
notifications
|
notifications
|
||||||
|> Enum.filter(&(&1.activity.data["type"] == "Follow"))
|
|> Enum.filter(&(&1.activity.data["type"] == "Follow"))
|
||||||
|> Enum.map(fn notification ->
|
|> Enum.map(fn notification ->
|
||||||
%{
|
from = User.get_by_ap_id(notification.activity.actor)
|
||||||
data: notification,
|
|
||||||
object: Pleroma.Object.normalize(notification.activity),
|
if not is_nil(from) do
|
||||||
from: User.get_by_ap_id(notification.activity.actor)
|
%{
|
||||||
}
|
data: notification,
|
||||||
|
object: Pleroma.Object.normalize(notification.activity),
|
||||||
|
from: User.get_by_ap_id(notification.activity.actor)
|
||||||
|
}
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|> Enum.filter(& &1)
|
||||||
|
|
||||||
unless Enum.empty?(mentions) do
|
unless Enum.empty?(mentions) do
|
||||||
styling = Config.get([__MODULE__, :styling])
|
styling = Config.get([__MODULE__, :styling])
|
||||||
|
|
|
@ -264,4 +264,12 @@ defmodule Pleroma.FollowingRelationship do
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec following_ap_ids(User.t()) :: [String.t()]
|
||||||
|
def following_ap_ids(%User{} = user) do
|
||||||
|
user
|
||||||
|
|> following_query()
|
||||||
|
|> select([r, u], u.ap_id)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,6 +30,7 @@ defmodule Pleroma.Plugs.FrontendStatic do
|
||||||
opts
|
opts
|
||||||
|> Keyword.put(:from, "__unconfigured_frontend_static_plug")
|
|> Keyword.put(:from, "__unconfigured_frontend_static_plug")
|
||||||
|> Plug.Static.init()
|
|> Plug.Static.init()
|
||||||
|
|> Map.put(:frontend_type, opts[:frontend_type])
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(conn, opts) do
|
def call(conn, opts) do
|
||||||
|
|
|
@ -56,6 +56,15 @@ defmodule Pleroma.Upload do
|
||||||
}
|
}
|
||||||
defstruct [:id, :name, :tempfile, :content_type, :path]
|
defstruct [:id, :name, :tempfile, :content_type, :path]
|
||||||
|
|
||||||
|
defp get_description(opts, upload) do
|
||||||
|
case {opts[:description], Pleroma.Config.get([Pleroma.Upload, :default_description])} do
|
||||||
|
{description, _} when is_binary(description) -> description
|
||||||
|
{_, :filename} -> upload.name
|
||||||
|
{_, str} when is_binary(str) -> str
|
||||||
|
_ -> ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()}
|
@spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()}
|
||||||
def store(upload, opts \\ []) do
|
def store(upload, opts \\ []) do
|
||||||
opts = get_opts(opts)
|
opts = get_opts(opts)
|
||||||
|
@ -63,7 +72,7 @@ defmodule Pleroma.Upload do
|
||||||
with {:ok, upload} <- prepare_upload(upload, opts),
|
with {:ok, upload} <- prepare_upload(upload, opts),
|
||||||
upload = %__MODULE__{upload | path: upload.path || "#{upload.id}/#{upload.name}"},
|
upload = %__MODULE__{upload | path: upload.path || "#{upload.id}/#{upload.name}"},
|
||||||
{:ok, upload} <- Pleroma.Upload.Filter.filter(opts.filters, upload),
|
{:ok, upload} <- Pleroma.Upload.Filter.filter(opts.filters, upload),
|
||||||
description = Map.get(opts, :description) || upload.name,
|
description = get_description(opts, upload),
|
||||||
{_, true} <-
|
{_, true} <-
|
||||||
{:description_limit,
|
{:description_limit,
|
||||||
String.length(description) <= Pleroma.Config.get([:instance, :description_limit])},
|
String.length(description) <= Pleroma.Config.get([:instance, :description_limit])},
|
||||||
|
|
|
@ -247,6 +247,13 @@ defmodule Pleroma.User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defdelegate following_count(user), to: FollowingRelationship
|
||||||
|
defdelegate following(user), to: FollowingRelationship
|
||||||
|
defdelegate following?(follower, followed), to: FollowingRelationship
|
||||||
|
defdelegate following_ap_ids(user), to: FollowingRelationship
|
||||||
|
defdelegate get_follow_requests(user), to: FollowingRelationship
|
||||||
|
defdelegate search(query, opts \\ []), to: User.Search
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Dumps Flake Id to SQL-compatible format (16-byte UUID).
|
Dumps Flake Id to SQL-compatible format (16-byte UUID).
|
||||||
E.g. "9pQtDGXuq4p3VlcJEm" -> <<0, 0, 1, 110, 179, 218, 42, 92, 213, 41, 44, 227, 95, 213, 0, 0>>
|
E.g. "9pQtDGXuq4p3VlcJEm" -> <<0, 0, 1, 110, 179, 218, 42, 92, 213, 41, 44, 227, 95, 213, 0, 0>>
|
||||||
|
@ -372,8 +379,6 @@ defmodule Pleroma.User do
|
||||||
from(u in query, where: u.deactivated != ^true)
|
from(u in query, where: u.deactivated != ^true)
|
||||||
end
|
end
|
||||||
|
|
||||||
defdelegate following_count(user), to: FollowingRelationship
|
|
||||||
|
|
||||||
defp truncate_fields_param(params) do
|
defp truncate_fields_param(params) do
|
||||||
if Map.has_key?(params, :fields) do
|
if Map.has_key?(params, :fields) do
|
||||||
Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1))
|
Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1))
|
||||||
|
@ -868,8 +873,6 @@ defmodule Pleroma.User do
|
||||||
set_cache(follower)
|
set_cache(follower)
|
||||||
end
|
end
|
||||||
|
|
||||||
defdelegate following(user), to: FollowingRelationship
|
|
||||||
|
|
||||||
def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do
|
def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do
|
||||||
deny_follow_blocked = Config.get([:user, :deny_follow_blocked])
|
deny_follow_blocked = Config.get([:user, :deny_follow_blocked])
|
||||||
|
|
||||||
|
@ -923,8 +926,6 @@ defmodule Pleroma.User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defdelegate following?(follower, followed), to: FollowingRelationship
|
|
||||||
|
|
||||||
@doc "Returns follow state as Pleroma.FollowingRelationship.State value"
|
@doc "Returns follow state as Pleroma.FollowingRelationship.State value"
|
||||||
def get_follow_state(%User{} = follower, %User{} = following) do
|
def get_follow_state(%User{} = follower, %User{} = following) do
|
||||||
following_relationship = FollowingRelationship.get(follower, following)
|
following_relationship = FollowingRelationship.get(follower, following)
|
||||||
|
@ -1189,8 +1190,6 @@ defmodule Pleroma.User do
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
defdelegate get_follow_requests(user), to: FollowingRelationship
|
|
||||||
|
|
||||||
def increase_note_count(%User{} = user) do
|
def increase_note_count(%User{} = user) do
|
||||||
User
|
User
|
||||||
|> where(id: ^user.id)
|
|> where(id: ^user.id)
|
||||||
|
@ -2163,8 +2162,6 @@ defmodule Pleroma.User do
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
defdelegate search(query, opts \\ []), to: User.Search
|
|
||||||
|
|
||||||
defp put_password_hash(
|
defp put_password_hash(
|
||||||
%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset
|
%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset
|
||||||
) do
|
) do
|
||||||
|
|
|
@ -85,7 +85,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
|
|
||||||
defp increase_replies_count_if_reply(_create_data), do: :noop
|
defp increase_replies_count_if_reply(_create_data), do: :noop
|
||||||
|
|
||||||
@object_types ["ChatMessage", "Question", "Answer"]
|
@object_types ~w[ChatMessage Question Answer Audio Event]
|
||||||
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
|
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
|
||||||
def persist(%{"type" => type} = object, meta) when type in @object_types do
|
def persist(%{"type" => type} = object, meta) when type in @object_types do
|
||||||
with {:ok, object} <- Object.create(object) do
|
with {:ok, object} <- Object.create(object) do
|
||||||
|
@ -1344,9 +1344,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_handle_clashing_nickname(data) do
|
def maybe_handle_clashing_nickname(data) do
|
||||||
nickname = data[:nickname]
|
with nickname when is_binary(nickname) <- data[:nickname],
|
||||||
|
%User{} = old_user <- User.get_by_nickname(nickname),
|
||||||
with %User{} = old_user <- User.get_by_nickname(nickname),
|
|
||||||
{_, false} <- {:ap_id_comparison, data[:ap_id] == old_user.ap_id} do
|
{_, false} <- {:ap_id_comparison, data[:ap_id] == old_user.ap_id} do
|
||||||
Logger.info(
|
Logger.info(
|
||||||
"Found an old user for #{nickname}, the old ap id is #{old_user.ap_id}, new one is #{
|
"Found an old user for #{nickname}, the old ap id is #{old_user.ap_id}, new one is #{
|
||||||
|
@ -1360,7 +1359,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
else
|
else
|
||||||
{:ap_id_comparison, true} ->
|
{:ap_id_comparison, true} ->
|
||||||
Logger.info(
|
Logger.info(
|
||||||
"Found an old user for #{nickname}, but the ap id #{data[:ap_id]} is the same as the new user. Race condition? Not changing anything."
|
"Found an old user for #{data[:nickname]}, but the ap id #{data[:ap_id]} is the same as the new user. Race condition? Not changing anything."
|
||||||
)
|
)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
|
|
@ -215,7 +215,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||||
|
|
||||||
to =
|
to =
|
||||||
cond do
|
cond do
|
||||||
actor.ap_id == Relay.relay_ap_id() ->
|
actor.ap_id == Relay.ap_id() ->
|
||||||
[actor.follower_address]
|
[actor.follower_address]
|
||||||
|
|
||||||
public? ->
|
public? ->
|
||||||
|
|
|
@ -23,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.EventValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator
|
||||||
|
@ -43,6 +44,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate(%{"type" => "Event"} = object, meta) do
|
||||||
|
with {:ok, object} <-
|
||||||
|
object
|
||||||
|
|> EventValidator.cast_and_validate()
|
||||||
|
|> Ecto.Changeset.apply_action(:insert) do
|
||||||
|
object = stringify_keys(object)
|
||||||
|
{:ok, object, meta}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def validate(%{"type" => "Follow"} = object, meta) do
|
def validate(%{"type" => "Follow"} = object, meta) do
|
||||||
with {:ok, object} <-
|
with {:ok, object} <-
|
||||||
object
|
object
|
||||||
|
@ -187,7 +198,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
|
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
|
||||||
meta
|
meta
|
||||||
)
|
)
|
||||||
when objtype in ~w[Question Answer Audio] do
|
when objtype in ~w[Question Answer Audio Event] do
|
||||||
with {:ok, object_data} <- cast_and_apply(object),
|
with {:ok, object_data} <- cast_and_apply(object),
|
||||||
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
|
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
|
||||||
{:ok, create_activity} <-
|
{:ok, create_activity} <-
|
||||||
|
@ -225,6 +236,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
AudioValidator.cast_and_apply(object)
|
AudioValidator.cast_and_apply(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cast_and_apply(%{"type" => "Event"} = object) do
|
||||||
|
EventValidator.cast_and_apply(object)
|
||||||
|
end
|
||||||
|
|
||||||
def cast_and_apply(o), do: {:error, {:validator_not_set, o}}
|
def cast_and_apply(o), do: {:error, {:validator_not_set, o}}
|
||||||
|
|
||||||
# is_struct/1 isn't present in Elixir 1.8.x
|
# is_struct/1 isn't present in Elixir 1.8.x
|
||||||
|
|
|
@ -41,34 +41,34 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_media_type(data) do
|
def fix_media_type(data) do
|
||||||
data =
|
data = Map.put_new(data, "mediaType", data["mimeType"])
|
||||||
data
|
|
||||||
|> Map.put_new("mediaType", data["mimeType"])
|
|
||||||
|
|
||||||
if MIME.valid?(data["mediaType"]) do
|
if MIME.valid?(data["mediaType"]) do
|
||||||
data
|
data
|
||||||
else
|
else
|
||||||
data
|
Map.put(data, "mediaType", "application/octet-stream")
|
||||||
|> Map.put("mediaType", "application/octet-stream")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_url(data) do
|
defp handle_href(href, mediaType) do
|
||||||
case data["url"] do
|
[
|
||||||
url when is_binary(url) ->
|
%{
|
||||||
data
|
"href" => href,
|
||||||
|> Map.put(
|
"type" => "Link",
|
||||||
"url",
|
"mediaType" => mediaType
|
||||||
[
|
}
|
||||||
%{
|
]
|
||||||
"href" => url,
|
end
|
||||||
"type" => "Link",
|
|
||||||
"mediaType" => data["mediaType"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
_ ->
|
defp fix_url(data) do
|
||||||
|
cond do
|
||||||
|
is_binary(data["url"]) ->
|
||||||
|
Map.put(data, "url", handle_href(data["url"], data["mediaType"]))
|
||||||
|
|
||||||
|
is_binary(data["href"]) and data["url"] == nil ->
|
||||||
|
Map.put(data, "url", handle_href(data["href"], data["mediaType"]))
|
||||||
|
|
||||||
|
true ->
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,7 +41,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioValidator do
|
||||||
field(:like_count, :integer, default: 0)
|
field(:like_count, :integer, default: 0)
|
||||||
field(:announcement_count, :integer, default: 0)
|
field(:announcement_count, :integer, default: 0)
|
||||||
field(:inReplyTo, :string)
|
field(:inReplyTo, :string)
|
||||||
field(:uri, ObjectValidators.Uri)
|
field(:url, ObjectValidators.Uri)
|
||||||
# short identifier for PleromaFE to group statuses by context
|
# short identifier for PleromaFE to group statuses by context
|
||||||
field(:context_id, :integer)
|
field(:context_id, :integer)
|
||||||
|
|
||||||
|
@ -66,10 +66,24 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioValidator do
|
||||||
|> changeset(data)
|
|> changeset(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp fix_url(%{"url" => url} = data) when is_list(url) do
|
||||||
|
attachment =
|
||||||
|
Enum.find(url, fn x -> is_map(x) and String.starts_with?(x["mimeType"], "audio/") end)
|
||||||
|
|
||||||
|
link_element = Enum.find(url, fn x -> is_map(x) and x["mimeType"] == "text/html" end)
|
||||||
|
|
||||||
|
data
|
||||||
|
|> Map.put("attachment", [attachment])
|
||||||
|
|> Map.put("url", link_element["href"])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fix_url(data), do: data
|
||||||
|
|
||||||
defp fix(data) do
|
defp fix(data) do
|
||||||
data
|
data
|
||||||
|> CommonFixes.fix_defaults()
|
|> CommonFixes.fix_defaults()
|
||||||
|> CommonFixes.fix_attribution()
|
|> CommonFixes.fix_attribution()
|
||||||
|
|> fix_url()
|
||||||
end
|
end
|
||||||
|
|
||||||
def changeset(struct, data) do
|
def changeset(struct, data) do
|
||||||
|
@ -83,7 +97,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioValidator do
|
||||||
def validate_data(data_cng) do
|
def validate_data(data_cng) do
|
||||||
data_cng
|
data_cng
|
||||||
|> validate_inclusion(:type, ["Audio"])
|
|> validate_inclusion(:type, ["Audio"])
|
||||||
|> validate_required([:id, :actor, :attributedTo, :type, :context])
|
|> validate_required([:id, :actor, :attributedTo, :type, :context, :attachment])
|
||||||
|> CommonValidations.validate_any_presence([:cc, :to])
|
|> CommonValidations.validate_any_presence([:cc, :to])
|
||||||
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
|
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
|
||||||
|> CommonValidations.validate_actor_presence()
|
|> CommonValidations.validate_actor_presence()
|
||||||
|
|
|
@ -61,9 +61,20 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp fix_addressing(data, meta) do
|
||||||
|
if object = meta[:object_data] do
|
||||||
|
data
|
||||||
|
|> Map.put_new("to", object["to"] || [])
|
||||||
|
|> Map.put_new("cc", object["cc"] || [])
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp fix(data, meta) do
|
defp fix(data, meta) do
|
||||||
data
|
data
|
||||||
|> fix_context(meta)
|
|> fix_context(meta)
|
||||||
|
|> fix_addressing(meta)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_data(cng, meta \\ []) do
|
def validate_data(cng, meta \\ []) do
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@primary_key false
|
||||||
|
@derive Jason.Encoder
|
||||||
|
|
||||||
|
# Extends from NoteValidator
|
||||||
|
embedded_schema do
|
||||||
|
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
||||||
|
field(:to, ObjectValidators.Recipients, default: [])
|
||||||
|
field(:cc, ObjectValidators.Recipients, default: [])
|
||||||
|
field(:bto, ObjectValidators.Recipients, default: [])
|
||||||
|
field(:bcc, ObjectValidators.Recipients, default: [])
|
||||||
|
# TODO: Write type
|
||||||
|
field(:tag, {:array, :map}, default: [])
|
||||||
|
field(:type, :string)
|
||||||
|
|
||||||
|
field(:name, :string)
|
||||||
|
field(:summary, :string)
|
||||||
|
field(:content, :string)
|
||||||
|
|
||||||
|
field(:context, :string)
|
||||||
|
# short identifier for PleromaFE to group statuses by context
|
||||||
|
field(:context_id, :integer)
|
||||||
|
|
||||||
|
# TODO: Remove actor on objects
|
||||||
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
|
|
||||||
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
|
field(:published, ObjectValidators.DateTime)
|
||||||
|
# TODO: Write type
|
||||||
|
field(:emoji, :map, default: %{})
|
||||||
|
field(:sensitive, :boolean, default: false)
|
||||||
|
embeds_many(:attachment, AttachmentValidator)
|
||||||
|
field(:replies_count, :integer, default: 0)
|
||||||
|
field(:like_count, :integer, default: 0)
|
||||||
|
field(:announcement_count, :integer, default: 0)
|
||||||
|
field(:inReplyTo, ObjectValidators.ObjectID)
|
||||||
|
field(:url, ObjectValidators.Uri)
|
||||||
|
|
||||||
|
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
|
||||||
|
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast_and_apply(data) do
|
||||||
|
data
|
||||||
|
|> cast_data
|
||||||
|
|> apply_action(:insert)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast_and_validate(data) do
|
||||||
|
data
|
||||||
|
|> cast_data()
|
||||||
|
|> validate_data()
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast_data(data) do
|
||||||
|
%__MODULE__{}
|
||||||
|
|> changeset(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fix(data) do
|
||||||
|
data
|
||||||
|
|> CommonFixes.fix_defaults()
|
||||||
|
|> CommonFixes.fix_attribution()
|
||||||
|
end
|
||||||
|
|
||||||
|
def changeset(struct, data) do
|
||||||
|
data = fix(data)
|
||||||
|
|
||||||
|
struct
|
||||||
|
|> cast(data, __schema__(:fields) -- [:attachment])
|
||||||
|
|> cast_embed(:attachment)
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_data(data_cng) do
|
||||||
|
data_cng
|
||||||
|
|> validate_inclusion(:type, ["Event"])
|
||||||
|
|> validate_required([:id, :actor, :attributedTo, :type, :context, :context_id])
|
||||||
|
|> CommonValidations.validate_any_presence([:cc, :to])
|
||||||
|
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
|
||||||
|
|> CommonValidations.validate_actor_presence()
|
||||||
|
|> CommonValidations.validate_host_match()
|
||||||
|
end
|
||||||
|
end
|
|
@ -20,11 +20,17 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
|
||||||
# TODO: Write type
|
# TODO: Write type
|
||||||
field(:tag, {:array, :map}, default: [])
|
field(:tag, {:array, :map}, default: [])
|
||||||
field(:type, :string)
|
field(:type, :string)
|
||||||
|
|
||||||
|
field(:name, :string)
|
||||||
|
field(:summary, :string)
|
||||||
field(:content, :string)
|
field(:content, :string)
|
||||||
|
|
||||||
field(:context, :string)
|
field(:context, :string)
|
||||||
|
# short identifier for PleromaFE to group statuses by context
|
||||||
|
field(:context_id, :integer)
|
||||||
|
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
field(:summary, :string)
|
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
# TODO: Write type
|
# TODO: Write type
|
||||||
field(:emoji, :map, default: %{})
|
field(:emoji, :map, default: %{})
|
||||||
|
@ -35,13 +41,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
|
||||||
field(:like_count, :integer, default: 0)
|
field(:like_count, :integer, default: 0)
|
||||||
field(:announcement_count, :integer, default: 0)
|
field(:announcement_count, :integer, default: 0)
|
||||||
field(:inReplyTo, ObjectValidators.ObjectID)
|
field(:inReplyTo, ObjectValidators.ObjectID)
|
||||||
field(:uri, ObjectValidators.Uri)
|
field(:url, ObjectValidators.Uri)
|
||||||
|
|
||||||
field(:likes, {:array, :string}, default: [])
|
field(:likes, {:array, :string}, default: [])
|
||||||
field(:announcements, {:array, :string}, default: [])
|
field(:announcements, {:array, :string}, default: [])
|
||||||
|
|
||||||
# see if needed
|
|
||||||
field(:context_id, :string)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data) do
|
def cast_and_validate(data) do
|
||||||
|
|
|
@ -43,7 +43,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
field(:like_count, :integer, default: 0)
|
field(:like_count, :integer, default: 0)
|
||||||
field(:announcement_count, :integer, default: 0)
|
field(:announcement_count, :integer, default: 0)
|
||||||
field(:inReplyTo, ObjectValidators.ObjectID)
|
field(:inReplyTo, ObjectValidators.ObjectID)
|
||||||
field(:uri, ObjectValidators.Uri)
|
field(:url, ObjectValidators.Uri)
|
||||||
# short identifier for PleromaFE to group statuses by context
|
# short identifier for PleromaFE to group statuses by context
|
||||||
field(:context_id, :integer)
|
field(:context_id, :integer)
|
||||||
|
|
||||||
|
|
|
@ -10,19 +10,13 @@ defmodule Pleroma.Web.ActivityPub.Relay do
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@relay_nickname "relay"
|
@nickname "relay"
|
||||||
|
|
||||||
def get_actor do
|
@spec ap_id() :: String.t()
|
||||||
actor =
|
def ap_id, do: "#{Pleroma.Web.Endpoint.url()}/#{@nickname}"
|
||||||
relay_ap_id()
|
|
||||||
|> User.get_or_create_service_actor_by_ap_id(@relay_nickname)
|
|
||||||
|
|
||||||
actor
|
@spec get_actor() :: User.t() | nil
|
||||||
end
|
def get_actor, do: User.get_or_create_service_actor_by_ap_id(ap_id(), @nickname)
|
||||||
|
|
||||||
def relay_ap_id do
|
|
||||||
"#{Pleroma.Web.Endpoint.url()}/relay"
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()}
|
@spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()}
|
||||||
def follow(target_instance) do
|
def follow(target_instance) do
|
||||||
|
@ -61,34 +55,38 @@ defmodule Pleroma.Web.ActivityPub.Relay do
|
||||||
|
|
||||||
def publish(_), do: {:error, "Not implemented"}
|
def publish(_), do: {:error, "Not implemented"}
|
||||||
|
|
||||||
@spec list(boolean()) :: {:ok, [String.t()]} | {:error, any()}
|
@spec list() :: {:ok, [%{actor: String.t(), followed_back: boolean()}]} | {:error, any()}
|
||||||
def list(with_not_accepted \\ false) do
|
def list do
|
||||||
with %User{} = user <- get_actor() do
|
with %User{} = user <- get_actor() do
|
||||||
accepted =
|
accepted =
|
||||||
user
|
user
|
||||||
|> User.following()
|
|> following()
|
||||||
|> Enum.map(fn entry -> URI.parse(entry).host end)
|
|> Enum.map(fn actor -> %{actor: actor, followed_back: true} end)
|
||||||
|
|
||||||
|
without_accept =
|
||||||
|
user
|
||||||
|
|> Pleroma.Activity.following_requests_for_actor()
|
||||||
|
|> Enum.map(fn activity -> %{actor: activity.data["object"], followed_back: false} end)
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
|
|
||||||
list =
|
{:ok, accepted ++ without_accept}
|
||||||
if with_not_accepted do
|
|
||||||
without_accept =
|
|
||||||
user
|
|
||||||
|> Pleroma.Activity.following_requests_for_actor()
|
|
||||||
|> Enum.map(fn a -> URI.parse(a.data["object"]).host <> " (no Accept received)" end)
|
|
||||||
|> Enum.uniq()
|
|
||||||
|
|
||||||
accepted ++ without_accept
|
|
||||||
else
|
|
||||||
accepted
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, list}
|
|
||||||
else
|
else
|
||||||
error -> format_error(error)
|
error -> format_error(error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec following() :: [String.t()]
|
||||||
|
def following do
|
||||||
|
get_actor()
|
||||||
|
|> following()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp following(user) do
|
||||||
|
user
|
||||||
|
|> User.following_ap_ids()
|
||||||
|
|> Enum.uniq()
|
||||||
|
end
|
||||||
|
|
||||||
defp format_error({:error, error}), do: format_error(error)
|
defp format_error({:error, error}), do: format_error(error)
|
||||||
|
|
||||||
defp format_error(error) do
|
defp format_error(error) do
|
||||||
|
|
|
@ -341,7 +341,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_object_creation(%{"type" => objtype} = object, meta)
|
def handle_object_creation(%{"type" => objtype} = object, meta)
|
||||||
when objtype in ~w[Audio Question] do
|
when objtype in ~w[Audio Question Event] do
|
||||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
|
|
|
@ -276,13 +276,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
Map.put(object, "url", url["href"])
|
Map.put(object, "url", url["href"])
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_url(%{"type" => object_type, "url" => url} = object)
|
def fix_url(%{"type" => "Video", "url" => url} = object) when is_list(url) do
|
||||||
when object_type in ["Video", "Audio"] and is_list(url) do
|
|
||||||
attachment =
|
attachment =
|
||||||
Enum.find(url, fn x ->
|
Enum.find(url, fn x ->
|
||||||
media_type = x["mediaType"] || x["mimeType"] || ""
|
media_type = x["mediaType"] || x["mimeType"] || ""
|
||||||
|
|
||||||
is_map(x) and String.starts_with?(media_type, ["audio/", "video/"])
|
is_map(x) and String.starts_with?(media_type, "video/")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
link_element =
|
link_element =
|
||||||
|
@ -461,7 +460,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
%{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
|
%{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
when objtype in ~w{Article Event Note Video Page} do
|
when objtype in ~w{Article Note Video Page} do
|
||||||
actor = Containment.get_actor(data)
|
actor = Containment.get_actor(data)
|
||||||
|
|
||||||
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
|
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
|
||||||
|
@ -555,7 +554,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
||||||
%{"type" => "Create", "object" => %{"type" => objtype}} = data,
|
%{"type" => "Create", "object" => %{"type" => objtype}} = data,
|
||||||
_options
|
_options
|
||||||
)
|
)
|
||||||
when objtype in ~w{Question Answer ChatMessage Audio} do
|
when objtype in ~w{Question Answer ChatMessage Audio Event} do
|
||||||
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
|
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
|
||||||
{:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
|
{:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
|
|
|
@ -39,7 +39,7 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
|
||||||
target: target
|
target: target
|
||||||
})
|
})
|
||||||
|
|
||||||
json(conn, target)
|
json(conn, %{actor: target, followed_back: target in Relay.following()})
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -79,7 +79,8 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
|
||||||
"confirmation_pending" => user.confirmation_pending,
|
"confirmation_pending" => user.confirmation_pending,
|
||||||
"approval_pending" => user.approval_pending,
|
"approval_pending" => user.approval_pending,
|
||||||
"url" => user.uri || user.ap_id,
|
"url" => user.uri || user.ap_id,
|
||||||
"registration_reason" => user.registration_reason
|
"registration_reason" => user.registration_reason,
|
||||||
|
"actor_type" => user.actor_type
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RelayOperation do
|
||||||
properties: %{
|
properties: %{
|
||||||
relays: %Schema{
|
relays: %Schema{
|
||||||
type: :array,
|
type: :array,
|
||||||
items: %Schema{type: :string},
|
items: relay()
|
||||||
example: ["lain.com", "mstdn.io"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -43,19 +42,9 @@ defmodule Pleroma.Web.ApiSpec.Admin.RelayOperation do
|
||||||
operationId: "AdminAPI.RelayController.follow",
|
operationId: "AdminAPI.RelayController.follow",
|
||||||
security: [%{"oAuth" => ["write:follows"]}],
|
security: [%{"oAuth" => ["write:follows"]}],
|
||||||
parameters: admin_api_params(),
|
parameters: admin_api_params(),
|
||||||
requestBody:
|
requestBody: request_body("Parameters", relay_url()),
|
||||||
request_body("Parameters", %Schema{
|
|
||||||
type: :object,
|
|
||||||
properties: %{
|
|
||||||
relay_url: %Schema{type: :string, format: :uri}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
responses: %{
|
responses: %{
|
||||||
200 =>
|
200 => Operation.response("Status", "application/json", relay())
|
||||||
Operation.response("Status", "application/json", %Schema{
|
|
||||||
type: :string,
|
|
||||||
example: "http://mastodon.example.org/users/admin"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -67,13 +56,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RelayOperation do
|
||||||
operationId: "AdminAPI.RelayController.unfollow",
|
operationId: "AdminAPI.RelayController.unfollow",
|
||||||
security: [%{"oAuth" => ["write:follows"]}],
|
security: [%{"oAuth" => ["write:follows"]}],
|
||||||
parameters: admin_api_params(),
|
parameters: admin_api_params(),
|
||||||
requestBody:
|
requestBody: request_body("Parameters", relay_url()),
|
||||||
request_body("Parameters", %Schema{
|
|
||||||
type: :object,
|
|
||||||
properties: %{
|
|
||||||
relay_url: %Schema{type: :string, format: :uri}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
responses: %{
|
responses: %{
|
||||||
200 =>
|
200 =>
|
||||||
Operation.response("Status", "application/json", %Schema{
|
Operation.response("Status", "application/json", %Schema{
|
||||||
|
@ -83,4 +66,29 @@ defmodule Pleroma.Web.ApiSpec.Admin.RelayOperation do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp relay do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
actor: %Schema{
|
||||||
|
type: :string,
|
||||||
|
example: "https://example.com/relay"
|
||||||
|
},
|
||||||
|
followed_back: %Schema{
|
||||||
|
type: :boolean,
|
||||||
|
description: "Is relay followed back by this actor?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp relay_url do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
relay_url: %Schema{type: :string, format: :uri}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,6 +39,18 @@ defmodule Pleroma.Web.Endpoint do
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
plug(Plug.Static.IndexHtml, at: "/pleroma/admin/")
|
||||||
|
|
||||||
|
plug(Pleroma.Plugs.FrontendStatic,
|
||||||
|
at: "/pleroma/admin",
|
||||||
|
frontend_type: :admin,
|
||||||
|
gzip: true,
|
||||||
|
cache_control_for_etags: @static_cache_control,
|
||||||
|
headers: %{
|
||||||
|
"cache-control" => @static_cache_control
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# Serve at "/" the static files from "priv/static" directory.
|
# Serve at "/" the static files from "priv/static" directory.
|
||||||
#
|
#
|
||||||
# You should set gzip to true if you are running phoenix.digest
|
# You should set gzip to true if you are running phoenix.digest
|
||||||
|
@ -56,8 +68,6 @@ defmodule Pleroma.Web.Endpoint do
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(Plug.Static.IndexHtml, at: "/pleroma/admin/")
|
|
||||||
|
|
||||||
plug(Plug.Static,
|
plug(Plug.Static,
|
||||||
at: "/pleroma/admin/",
|
at: "/pleroma/admin/",
|
||||||
from: {:pleroma, "priv/static/adminfe/"}
|
from: {:pleroma, "priv/static/adminfe/"}
|
||||||
|
|
|
@ -474,23 +474,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_content(%{data: %{"type" => object_type}} = object)
|
def render_content(%{data: %{"name" => name}} = object) when not is_nil(name) and name != "" do
|
||||||
when object_type in ["Video", "Event", "Audio"] do
|
url = object.data["url"] || object.data["id"]
|
||||||
with name when not is_nil(name) and name != "" <- object.data["name"] do
|
|
||||||
"<p><a href=\"#{object.data["id"]}\">#{name}</a></p>#{object.data["content"]}"
|
|
||||||
else
|
|
||||||
_ -> object.data["content"] || ""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_content(%{data: %{"type" => object_type}} = object)
|
"<p><a href=\"#{url}\">#{name}</a></p>#{object.data["content"]}"
|
||||||
when object_type in ["Article", "Page"] do
|
|
||||||
with summary when not is_nil(summary) and summary != "" <- object.data["name"],
|
|
||||||
url when is_bitstring(url) <- object.data["url"] do
|
|
||||||
"<p><a href=\"#{url}\">#{summary}</a></p>#{object.data["content"]}"
|
|
||||||
else
|
|
||||||
_ -> object.data["content"] || ""
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_content(object), do: object.data["content"] || ""
|
def render_content(object), do: object.data["content"] || ""
|
||||||
|
|
|
@ -14,10 +14,10 @@ defmodule Pleroma.Emails.MailerTest do
|
||||||
subject: "Pleroma test email",
|
subject: "Pleroma test email",
|
||||||
to: [{"Test User", "user1@example.com"}]
|
to: [{"Test User", "user1@example.com"}]
|
||||||
}
|
}
|
||||||
setup do: clear_config([Pleroma.Emails.Mailer, :enabled])
|
setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true)
|
||||||
|
|
||||||
test "not send email when mailer is disabled" do
|
test "not send email when mailer is disabled" do
|
||||||
Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
|
clear_config([Pleroma.Emails.Mailer, :enabled], false)
|
||||||
Mailer.deliver(@email)
|
Mailer.deliver(@email)
|
||||||
:timer.sleep(100)
|
:timer.sleep(100)
|
||||||
|
|
||||||
|
|
1
test/fixtures/tesla_mock/dist/test.txt
vendored
Normal file
1
test/fixtures/tesla_mock/dist/test.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
this is a text file
|
BIN
test/fixtures/tesla_mock/frontend.zip
vendored
Normal file
BIN
test/fixtures/tesla_mock/frontend.zip
vendored
Normal file
Binary file not shown.
BIN
test/fixtures/tesla_mock/frontend_dist.zip
vendored
Normal file
BIN
test/fixtures/tesla_mock/frontend_dist.zip
vendored
Normal file
Binary file not shown.
58
test/fixtures/tesla_mock/funkwhale_create_audio.json
vendored
Normal file
58
test/fixtures/tesla_mock/funkwhale_create_audio.json
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
"https://funkwhale.audio/ns",
|
||||||
|
{
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||||
|
"Hashtag": "as:Hashtag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Create",
|
||||||
|
"id": "https://channels.tests.funkwhale.audio/federation/music/uploads/42342395-0208-4fee-a38d-259a6dae0871/activity",
|
||||||
|
"actor": "https://channels.tests.funkwhale.audio/federation/actors/compositions",
|
||||||
|
"object": {
|
||||||
|
"id": "https://channels.tests.funkwhale.audio/federation/music/uploads/42342395-0208-4fee-a38d-259a6dae0871",
|
||||||
|
"type": "Audio",
|
||||||
|
"name": "Compositions - Test Audio for Pleroma",
|
||||||
|
"attributedTo": "https://channels.tests.funkwhale.audio/federation/actors/compositions",
|
||||||
|
"published": "2020-03-11T10:01:52.714918+00:00",
|
||||||
|
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"url": [
|
||||||
|
{
|
||||||
|
"type": "Link",
|
||||||
|
"mimeType": "audio/ogg",
|
||||||
|
"href": "https://channels.tests.funkwhale.audio/api/v1/listen/3901e5d8-0445-49d5-9711-e096cf32e515/?upload=42342395-0208-4fee-a38d-259a6dae0871&download=false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Link",
|
||||||
|
"mimeType": "text/html",
|
||||||
|
"href": "https://channels.tests.funkwhale.audio/library/tracks/74"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"content": "<p>This is a test Audio for Pleroma.</p>",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"tag": [
|
||||||
|
{
|
||||||
|
"type": "Hashtag",
|
||||||
|
"name": "#funkwhale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Hashtag",
|
||||||
|
"name": "#test"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Hashtag",
|
||||||
|
"name": "#tests"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "#funkwhale #test #tests",
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.FrontendStaticPlugTest do
|
defmodule Pleroma.Web.FrontendStaticPlugTest do
|
||||||
|
alias Pleroma.Plugs.FrontendStatic
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
@dir "test/tmp/instance_static"
|
@dir "test/tmp/instance_static"
|
||||||
|
@ -14,6 +15,18 @@ defmodule Pleroma.Web.FrontendStaticPlugTest do
|
||||||
|
|
||||||
setup do: clear_config([:instance, :static_dir], @dir)
|
setup do: clear_config([:instance, :static_dir], @dir)
|
||||||
|
|
||||||
|
test "init will give a static plug config + the frontend type" do
|
||||||
|
opts =
|
||||||
|
[
|
||||||
|
at: "/admin",
|
||||||
|
frontend_type: :admin
|
||||||
|
]
|
||||||
|
|> FrontendStatic.init()
|
||||||
|
|
||||||
|
assert opts[:at] == ["admin"]
|
||||||
|
assert opts[:frontend_type] == :admin
|
||||||
|
end
|
||||||
|
|
||||||
test "overrides existing static files", %{conn: conn} do
|
test "overrides existing static files", %{conn: conn} do
|
||||||
name = "pelmora"
|
name = "pelmora"
|
||||||
ref = "uguu"
|
ref = "uguu"
|
||||||
|
@ -27,4 +40,18 @@ defmodule Pleroma.Web.FrontendStaticPlugTest do
|
||||||
index = get(conn, "/")
|
index = get(conn, "/")
|
||||||
assert html_response(index, 200) == "from frontend plug"
|
assert html_response(index, 200) == "from frontend plug"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "overrides existing static files for the `pleroma/admin` path", %{conn: conn} do
|
||||||
|
name = "pelmora"
|
||||||
|
ref = "uguu"
|
||||||
|
|
||||||
|
clear_config([:frontends, :admin], %{"name" => name, "ref" => ref})
|
||||||
|
path = "#{@dir}/frontends/#{name}/#{ref}"
|
||||||
|
|
||||||
|
File.mkdir_p!(path)
|
||||||
|
File.write!("#{path}/index.html", "from frontend plug")
|
||||||
|
|
||||||
|
index = get(conn, "/pleroma/admin/")
|
||||||
|
assert html_response(index, 200) == "from frontend plug"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,8 @@ defmodule Mix.Tasks.Pleroma.DigestTest do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true)
|
||||||
|
|
||||||
describe "pleroma.digest test" do
|
describe "pleroma.digest test" do
|
||||||
test "Sends digest to the given user" do
|
test "Sends digest to the given user" do
|
||||||
user1 = insert(:user)
|
user1 = insert(:user)
|
||||||
|
|
|
@ -16,6 +16,8 @@ defmodule Mix.Tasks.Pleroma.EmailTest do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true)
|
||||||
|
|
||||||
describe "pleroma.email test" do
|
describe "pleroma.email test" do
|
||||||
test "Sends test email with no given address" do
|
test "Sends test email with no given address" do
|
||||||
mail_to = Config.get([:instance, :email])
|
mail_to = Config.get([:instance, :email])
|
||||||
|
|
78
test/tasks/frontend_test.exs
Normal file
78
test/tasks/frontend_test.exs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.FrontendTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
alias Mix.Tasks.Pleroma.Frontend
|
||||||
|
|
||||||
|
import ExUnit.CaptureIO, only: [capture_io: 1]
|
||||||
|
|
||||||
|
@dir "test/frontend_static_test"
|
||||||
|
|
||||||
|
setup do
|
||||||
|
File.mkdir_p!(@dir)
|
||||||
|
clear_config([:instance, :static_dir], @dir)
|
||||||
|
|
||||||
|
on_exit(fn ->
|
||||||
|
File.rm_rf(@dir)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it downloads and unzips a known frontend" do
|
||||||
|
clear_config([:frontends, :available], %{
|
||||||
|
"pleroma" => %{
|
||||||
|
"ref" => "fantasy",
|
||||||
|
"name" => "pleroma",
|
||||||
|
"build_url" => "http://gensokyo.2hu/builds/${ref}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/builds/fantasy"} ->
|
||||||
|
%Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend_dist.zip")}
|
||||||
|
end)
|
||||||
|
|
||||||
|
capture_io(fn ->
|
||||||
|
Frontend.run(["install", "pleroma"])
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"]))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it also works given a file" do
|
||||||
|
clear_config([:frontends, :available], %{
|
||||||
|
"pleroma" => %{
|
||||||
|
"ref" => "fantasy",
|
||||||
|
"name" => "pleroma",
|
||||||
|
"build_dir" => ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
capture_io(fn ->
|
||||||
|
Frontend.run(["install", "pleroma", "--file", "test/fixtures/tesla_mock/frontend.zip"])
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"]))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it downloads and unzips unknown frontends" do
|
||||||
|
Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} ->
|
||||||
|
%Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend.zip")}
|
||||||
|
end)
|
||||||
|
|
||||||
|
capture_io(fn ->
|
||||||
|
Frontend.run([
|
||||||
|
"install",
|
||||||
|
"unknown",
|
||||||
|
"--ref",
|
||||||
|
"baka",
|
||||||
|
"--build-url",
|
||||||
|
"http://gensokyo.2hu/madeup.zip",
|
||||||
|
"--build-dir",
|
||||||
|
""
|
||||||
|
])
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert File.exists?(Path.join([@dir, "frontends", "unknown", "baka", "test.txt"]))
|
||||||
|
end
|
||||||
|
end
|
|
@ -42,7 +42,11 @@ defmodule Mix.Tasks.Pleroma.RelayTest do
|
||||||
assert activity.data["object"] == target_user.ap_id
|
assert activity.data["object"] == target_user.ap_id
|
||||||
|
|
||||||
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
||||||
assert_receive {:mix_shell, :info, ["mastodon.example.org (no Accept received)"]}
|
|
||||||
|
assert_receive {:mix_shell, :info,
|
||||||
|
[
|
||||||
|
"http://mastodon.example.org/users/admin - no Accept received (relay didn't follow back)"
|
||||||
|
]}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -95,8 +99,8 @@ defmodule Mix.Tasks.Pleroma.RelayTest do
|
||||||
|
|
||||||
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
||||||
|
|
||||||
assert_receive {:mix_shell, :info, ["mstdn.io"]}
|
assert_receive {:mix_shell, :info, ["https://mstdn.io/users/mayuutann"]}
|
||||||
assert_receive {:mix_shell, :info, ["mastodon.example.org"]}
|
assert_receive {:mix_shell, :info, ["http://mastodon.example.org/users/admin"]}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -533,7 +533,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
||||||
assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}
|
assert_receive {:mix_shell, :info, ["https://relay.mastodon.host/actor"]}
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
@tag capture_log: true
|
||||||
|
|
|
@ -990,13 +990,39 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "uploading files" do
|
describe "uploading files" do
|
||||||
test "copies the file to the configured folder" do
|
setup do
|
||||||
file = %Plug.Upload{
|
test_file = %Plug.Upload{
|
||||||
content_type: "image/jpg",
|
content_type: "image/jpg",
|
||||||
path: Path.absname("test/fixtures/image.jpg"),
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
filename: "an_image.jpg"
|
filename: "an_image.jpg"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%{test_file: test_file}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "sets a description if given", %{test_file: file} do
|
||||||
|
{:ok, %Object{} = object} = ActivityPub.upload(file, description: "a cool file")
|
||||||
|
assert object.data["name"] == "a cool file"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it sets the default description depending on the configuration", %{test_file: file} do
|
||||||
|
clear_config([Pleroma.Upload, :default_description])
|
||||||
|
|
||||||
|
Pleroma.Config.put([Pleroma.Upload, :default_description], nil)
|
||||||
|
{:ok, %Object{} = object} = ActivityPub.upload(file)
|
||||||
|
assert object.data["name"] == ""
|
||||||
|
|
||||||
|
Pleroma.Config.put([Pleroma.Upload, :default_description], :filename)
|
||||||
|
{:ok, %Object{} = object} = ActivityPub.upload(file)
|
||||||
|
assert object.data["name"] == "an_image.jpg"
|
||||||
|
|
||||||
|
Pleroma.Config.put([Pleroma.Upload, :default_description], "unnamed attachment")
|
||||||
|
{:ok, %Object{} = object} = ActivityPub.upload(file)
|
||||||
|
assert object.data["name"] == "unnamed attachment"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "copies the file to the configured folder", %{test_file: file} do
|
||||||
|
clear_config([Pleroma.Upload, :default_description], :filename)
|
||||||
{:ok, %Object{} = object} = ActivityPub.upload(file)
|
{:ok, %Object{} = object} = ActivityPub.upload(file)
|
||||||
assert object.data["name"] == "an_image.jpg"
|
assert object.data["name"] == "an_image.jpg"
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,4 +42,42 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
|
||||||
assert object.data["album"] == "lain radio"
|
assert object.data["album"] == "lain radio"
|
||||||
assert object.data["length"] == 180_000
|
assert object.data["length"] == 180_000
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Funkwhale Audio object" do
|
||||||
|
Tesla.Mock.mock(fn
|
||||||
|
%{url: "https://channels.tests.funkwhale.audio/federation/actors/compositions"} ->
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json")
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
data = File.read!("test/fixtures/tesla_mock/funkwhale_create_audio.json") |> Poison.decode!()
|
||||||
|
|
||||||
|
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
|
assert object = Object.normalize(activity, false)
|
||||||
|
|
||||||
|
assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
|
||||||
|
assert object.data["cc"] == []
|
||||||
|
|
||||||
|
assert object.data["url"] == "https://channels.tests.funkwhale.audio/library/tracks/74"
|
||||||
|
|
||||||
|
assert object.data["attachment"] == [
|
||||||
|
%{
|
||||||
|
"mediaType" => "audio/ogg",
|
||||||
|
"type" => "Link",
|
||||||
|
"name" => nil,
|
||||||
|
"url" => [
|
||||||
|
%{
|
||||||
|
"href" =>
|
||||||
|
"https://channels.tests.funkwhale.audio/api/v1/listen/3901e5d8-0445-49d5-9711-e096cf32e515/?upload=42342395-0208-4fee-a38d-259a6dae0871&download=false",
|
||||||
|
"mediaType" => "audio/ogg",
|
||||||
|
"type" => "Link"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
40
test/web/activity_pub/transmogrifier/event_handling_test.exs
Normal file
40
test/web/activity_pub/transmogrifier/event_handling_test.exs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do
|
||||||
|
use Oban.Testing, repo: Pleroma.Repo
|
||||||
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Object.Fetcher
|
||||||
|
|
||||||
|
test "Mobilizon Event object" do
|
||||||
|
Tesla.Mock.mock(fn
|
||||||
|
%{url: "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"} ->
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
%{url: "https://mobilizon.org/@tcit"} ->
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json")
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert {:ok, object} =
|
||||||
|
Fetcher.fetch_object_from_id(
|
||||||
|
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
assert object.data["cc"] == []
|
||||||
|
|
||||||
|
assert object.data["url"] ==
|
||||||
|
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
|
||||||
|
|
||||||
|
assert object.data["published"] == "2019-12-17T11:33:56Z"
|
||||||
|
assert object.data["name"] == "Mobilizon Launching Party"
|
||||||
|
end
|
||||||
|
end
|
|
@ -24,6 +24,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
|
||||||
|
|
||||||
object = Object.normalize(activity, false)
|
object = Object.normalize(activity, false)
|
||||||
|
|
||||||
|
assert object.data["url"] == "https://mastodon.sdf.org/@rinpatch/102070944809637304"
|
||||||
|
|
||||||
assert object.data["closed"] == "2019-05-11T09:03:36Z"
|
assert object.data["closed"] == "2019-05-11T09:03:36Z"
|
||||||
|
|
||||||
assert object.data["context"] == activity.data["context"]
|
assert object.data["context"] == activity.data["context"]
|
||||||
|
|
|
@ -381,7 +381,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert expected == json_response(conn, 200)
|
assert expected == json_response(conn, 200)
|
||||||
|
@ -663,7 +664,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => admin.ap_id,
|
"url" => admin.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"deactivated" => user.deactivated,
|
"deactivated" => user.deactivated,
|
||||||
|
@ -677,7 +679,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"deactivated" => user2.deactivated,
|
"deactivated" => user2.deactivated,
|
||||||
|
@ -691,7 +694,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => true,
|
"approval_pending" => true,
|
||||||
"url" => user2.ap_id,
|
"url" => user2.ap_id,
|
||||||
"registration_reason" => "I'm a chill dude"
|
"registration_reason" => "I'm a chill dude",
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Enum.sort_by(& &1["nickname"])
|
|> Enum.sort_by(& &1["nickname"])
|
||||||
|
@ -766,7 +770,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -794,7 +799,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -822,7 +828,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -850,7 +857,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -878,7 +886,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -906,7 +915,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -929,7 +939,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user2.ap_id,
|
"url" => user2.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -964,7 +975,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -992,7 +1004,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"deactivated" => admin.deactivated,
|
"deactivated" => admin.deactivated,
|
||||||
|
@ -1006,7 +1019,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => admin.ap_id,
|
"url" => admin.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"deactivated" => false,
|
"deactivated" => false,
|
||||||
|
@ -1020,7 +1034,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => old_admin.ap_id,
|
"url" => old_admin.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Enum.sort_by(& &1["nickname"])
|
|> Enum.sort_by(& &1["nickname"])
|
||||||
|
@ -1058,7 +1073,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => true,
|
"approval_pending" => true,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => "Plz let me in!"
|
"registration_reason" => "Plz let me in!",
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Enum.sort_by(& &1["nickname"])
|
|> Enum.sort_by(& &1["nickname"])
|
||||||
|
@ -1091,7 +1107,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => admin.ap_id,
|
"url" => admin.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"deactivated" => false,
|
"deactivated" => false,
|
||||||
|
@ -1105,7 +1122,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => second_admin.ap_id,
|
"url" => second_admin.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Enum.sort_by(& &1["nickname"])
|
|> Enum.sort_by(& &1["nickname"])
|
||||||
|
@ -1140,7 +1158,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => moderator.ap_id,
|
"url" => moderator.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1168,7 +1187,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user1.ap_id,
|
"url" => user1.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"deactivated" => false,
|
"deactivated" => false,
|
||||||
|
@ -1182,7 +1202,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user2.ap_id,
|
"url" => user2.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Enum.sort_by(& &1["nickname"])
|
|> Enum.sort_by(& &1["nickname"])
|
||||||
|
@ -1245,7 +1266,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1272,7 +1294,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => admin.ap_id,
|
"url" => admin.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1357,7 +1380,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||||
"confirmation_pending" => false,
|
"confirmation_pending" => false,
|
||||||
"approval_pending" => false,
|
"approval_pending" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil
|
"registration_reason" => nil,
|
||||||
|
"actor_type" => "Person"
|
||||||
}
|
}
|
||||||
|
|
||||||
log_entry = Repo.one(ModerationLog)
|
log_entry = Repo.one(ModerationLog)
|
||||||
|
|
|
@ -39,8 +39,10 @@ defmodule Pleroma.Web.AdminAPI.RelayControllerTest do
|
||||||
relay_url: "http://mastodon.example.org/users/admin"
|
relay_url: "http://mastodon.example.org/users/admin"
|
||||||
})
|
})
|
||||||
|
|
||||||
assert json_response_and_validate_schema(conn, 200) ==
|
assert json_response_and_validate_schema(conn, 200) == %{
|
||||||
"http://mastodon.example.org/users/admin"
|
"actor" => "http://mastodon.example.org/users/admin",
|
||||||
|
"followed_back" => false
|
||||||
|
}
|
||||||
|
|
||||||
log_entry = Repo.one(ModerationLog)
|
log_entry = Repo.one(ModerationLog)
|
||||||
|
|
||||||
|
@ -59,8 +61,13 @@ defmodule Pleroma.Web.AdminAPI.RelayControllerTest do
|
||||||
|
|
||||||
conn = get(conn, "/api/pleroma/admin/relay")
|
conn = get(conn, "/api/pleroma/admin/relay")
|
||||||
|
|
||||||
assert json_response_and_validate_schema(conn, 200)["relays"] --
|
assert json_response_and_validate_schema(conn, 200)["relays"] == [
|
||||||
["mastodon.example.org", "mstdn.io"] == []
|
%{
|
||||||
|
"actor" => "http://mastodon.example.org/users/admin",
|
||||||
|
"followed_back" => true
|
||||||
|
},
|
||||||
|
%{"actor" => "https://mstdn.io/users/mayuutann", "followed_back" => true}
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "DELETE /relay", %{conn: conn, admin: admin} do
|
test "DELETE /relay", %{conn: conn, admin: admin} do
|
||||||
|
|
|
@ -517,6 +517,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|
||||||
represented = StatusView.render("show.json", %{for: user, activity: activity})
|
represented = StatusView.render("show.json", %{for: user, activity: activity})
|
||||||
|
|
||||||
assert represented[:id] == to_string(activity.id)
|
assert represented[:id] == to_string(activity.id)
|
||||||
|
|
||||||
|
assert represented[:url] ==
|
||||||
|
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
|
||||||
|
|
||||||
|
assert represented[:content] ==
|
||||||
|
"<p><a href=\"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39\">Mobilizon Launching Party</a></p><p>Mobilizon is now federated! 🎉</p><p></p><p>You can view this event from other instances if they are subscribed to mobilizon.org, and soon directly from Mastodon and Pleroma. It is possible that you may see some comments from other instances, including Mastodon ones, just below.</p><p></p><p>With a Mobilizon account on an instance, you may <strong>participate</strong> at events from other instances and <strong>add comments</strong> on events.</p><p></p><p>Of course, it's still <u>a work in progress</u>: if reports made from an instance on events and comments can be federated, you can't block people right now, and moderators actions are rather limited, but this <strong>will definitely get fixed over time</strong> until first stable version next year.</p><p></p><p>Anyway, if you want to come up with some feedback, head over to our forum or - if you feel you have technical skills and are familiar with it - on our Gitlab repository.</p><p></p><p>Also, to people that want to set Mobilizon themselves even though we really don't advise to do that for now, we have a little documentation but it's quite the early days and you'll probably need some help. No worries, you can chat with us on our Forum or though our Matrix channel.</p><p></p><p>Check our website for more informations and follow us on Twitter or Mastodon.</p>"
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "build_tags/1" do
|
describe "build_tags/1" do
|
||||||
|
|
Loading…
Reference in a new issue