diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 04af8c186..0f8a0659b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -29,22 +29,6 @@ build:
- mix deps.get
- mix compile --force
-docs-build:
- stage: build
- only:
- - master@pleroma/pleroma
- - develop@pleroma/pleroma
- variables:
- MIX_ENV: dev
- PLEROMA_BUILD_ENV: prod
- script:
- - mix deps.get
- - mix compile
- - mix docs
- artifacts:
- paths:
- - priv/static/doc
-
benchmark:
stage: benchmark
variables:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77edf7bf0..b33d61819 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,9 +16,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add `rel="ugc"` to all links in statuses, to prevent SEO spam
- Extract RSS functionality from OStatus
- MRF (Simple Policy): Also use `:accept`/`:reject` on the actors rather than only their activities
+- OStatus: Extract RSS functionality
+- Deprecated `User.Info` embedded schema (fields moved to `User`)
+- Store status data inside Flag activity
API Changes
+- **Breaking** Admin API: `PATCH /api/pleroma/admin/users/:nickname/force_password_reset` is now `PATCH /api/pleroma/admin/users/force_password_reset` (accepts `nicknames` array in the request body)
- **Breaking:** Admin API: Return link alongside with token on password reset
- **Breaking:** `/api/pleroma/admin/users/invite_token` now uses `POST`, changed accepted params and returns full invite in json instead of only token string.
- Admin API: Return `total` when querying for reports
@@ -53,21 +57,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Admin API: Add `GET /api/pleroma/admin/relay` endpoint - lists all followed relays
- Pleroma API: `POST /api/v1/pleroma/conversations/read` to mark all conversations as read
- Mastodon API: Add `/api/v1/markers` for managing timeline read markers
-
-### Changed
-- **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
-- **Breaking:** Admin API: Return link alongside with token on password reset
-- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings)
-- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler
-- Admin API: Return `total` when querying for reports
-- Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`)
-- Admin API: Return link alongside with token on password reset
-- MRF (Simple Policy): Also use `:accept`/`:reject` on the actors rather than only their activities
-- OStatus: Extract RSS functionality
-- Mastodon API: Add `pleroma.direct_conversation_id` to the status endpoint (`GET /api/v1/statuses/:id`)
-- Mastodon API: Mark the direct conversation as read for the author when they send a new direct message
-- Deprecated `User.Info` embedded schema (fields moved to `User`)
-- Store status data inside Flag activity
+- Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations`
### Fixed
diff --git a/config/config.exs b/config/config.exs
index 81d50cdee..787809b27 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -603,7 +603,7 @@
activity_pub: nil,
activity_pub_question: 30_000
-config :swarm, node_blacklist: [~r/myhtmlex_.*$/]
+config :swarm, node_blacklist: [~r/myhtml_.*$/]
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md
index e64ae6429..c042b08ac 100644
--- a/docs/API/admin_api.md
+++ b/docs/API/admin_api.md
@@ -392,13 +392,13 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
}
```
-
-## `/api/pleroma/admin/users/:nickname/force_password_reset`
+## `/api/pleroma/admin/users/force_password_reset`
### Force passord reset for a user with a given nickname
- Methods: `PATCH`
-- Params: none
+- Params:
+ - `nicknames`
- Response: none (code `204`)
## `/api/pleroma/admin/reports`
diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md
index aca0f5e0e..7fbe17130 100644
--- a/docs/API/differences_in_mastoapi_responses.md
+++ b/docs/API/differences_in_mastoapi_responses.md
@@ -72,6 +72,12 @@ Has an additional field under the `pleroma` object:
- `recipients`: The list of the recipients of this Conversation. These will be addressed when replying to this conversation.
+## GET `/api/v1/conversations`
+
+Accepts additional parameters:
+
+- `recipients`: Only return conversations with the given recipients (a list of user ids). Usage example: `GET /api/v1/conversations?recipients[]=1&recipients[]=2`
+
## Account Search
Behavior has changed:
diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex
index 176b82a20..aafe57280 100644
--- a/lib/pleroma/conversation/participation.ex
+++ b/lib/pleroma/conversation/participation.ex
@@ -122,9 +122,37 @@ def for_user(user, params \\ %{}) do
order_by: [desc: p.updated_at],
preload: [conversation: [:users]]
)
+ |> restrict_recipients(user, params)
|> Pleroma.Pagination.fetch_paginated(params)
end
+ def restrict_recipients(query, user, %{"recipients" => user_ids}) do
+ user_ids =
+ [user.id | user_ids]
+ |> Enum.uniq()
+ |> Enum.reduce([], fn user_id, acc ->
+ case FlakeId.Ecto.CompatType.dump(user_id) do
+ {:ok, user_id} -> [user_id | acc]
+ _ -> acc
+ end
+ end)
+
+ conversation_subquery =
+ __MODULE__
+ |> group_by([p], p.conversation_id)
+ |> having(
+ [p],
+ count(p.user_id) == ^length(user_ids) and
+ fragment("array_agg(?) @> ?", p.user_id, ^user_ids)
+ )
+ |> select([p], %{id: p.conversation_id})
+
+ query
+ |> join(:inner, [p], c in subquery(conversation_subquery), on: p.conversation_id == c.id)
+ end
+
+ def restrict_recipients(query, _, _), do: query
+
def for_user_and_conversation(user, conversation) do
from(p in __MODULE__,
where: p.user_id == ^user.id,
diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex
index 9dc4a94c9..ffa5dc25d 100644
--- a/lib/pleroma/moderation_log.ex
+++ b/lib/pleroma/moderation_log.ex
@@ -616,6 +616,17 @@ def get_log_entry_message(%ModerationLog{
"@#{actor_nickname} deleted status ##{subject_id}"
end
+ @spec get_log_entry_message(ModerationLog) :: String.t()
+ def get_log_entry_message(%ModerationLog{
+ data: %{
+ "actor" => %{"nickname" => actor_nickname},
+ "action" => "force_password_reset",
+ "subject" => subjects
+ }
+ }) do
+ "@#{actor_nickname} force password reset for users: #{users_to_nicknames_string(subjects)}"
+ end
+
defp nicknames_to_string(nicknames) do
nicknames
|> Enum.map(&"@#{&1}")
diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex
index 68535c09e..a1f9c1250 100644
--- a/lib/pleroma/object/containment.ex
+++ b/lib/pleroma/object/containment.ex
@@ -64,15 +64,15 @@ def contain_origin(id, %{"actor" => _actor} = params) do
def contain_origin(id, %{"attributedTo" => actor} = params),
do: contain_origin(id, Map.put(params, "actor", actor))
- def contain_origin_from_id(_id, %{"id" => nil}), do: :error
-
- def contain_origin_from_id(id, %{"id" => other_id} = _params) do
+ def contain_origin_from_id(id, %{"id" => other_id} = _params) when is_binary(other_id) do
id_uri = URI.parse(id)
other_uri = URI.parse(other_id)
compare_uris(id_uri, other_uri)
end
+ def contain_origin_from_id(_id, _data), do: :error
+
def contain_child(%{"object" => %{"id" => id, "attributedTo" => _} = object}),
do: contain_origin(id, object)
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index 441ae8b65..9a9a46550 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -38,7 +38,8 @@ defp reinject_object(struct, data) do
data <- maybe_reinject_internal_fields(data, struct),
changeset <- Object.change(struct, %{data: data}),
changeset <- touch_changeset(changeset),
- {:ok, object} <- Repo.insert_or_update(changeset) do
+ {:ok, object} <- Repo.insert_or_update(changeset),
+ {:ok, object} <- Object.set_cache(object) do
{:ok, object}
else
e ->
@@ -53,7 +54,7 @@ def refetch_object(%Object{data: %{"id" => id}} = object) do
{:ok, object} <- reinject_object(object, data) do
{:ok, object}
else
- {:local, true} -> object
+ {:local, true} -> {:ok, object}
e -> {:error, e}
end
end
diff --git a/lib/pleroma/plugs/trailing_format_plug.ex b/lib/pleroma/plugs/trailing_format_plug.ex
index ce366b218..a4b8a406d 100644
--- a/lib/pleroma/plugs/trailing_format_plug.ex
+++ b/lib/pleroma/plugs/trailing_format_plug.ex
@@ -24,7 +24,8 @@ defmodule Pleroma.Plugs.TrailingFormatPlug do
"/api/help",
"/api/externalprofile",
"/notice",
- "/api/pleroma/emoji"
+ "/api/pleroma/emoji",
+ "/api/oauth_tokens"
]
def init(opts) do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index b47618bde..30fc01755 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -607,10 +607,16 @@ def get_password_reset(conn, %{"nickname" => nickname}) do
end
@doc "Force password reset for a given user"
- def force_password_reset(conn, %{"nickname" => nickname}) do
- (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
+ def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
+ users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
- User.force_password_reset_async(user)
+ Enum.map(users, &User.force_password_reset_async/1)
+
+ ModerationLog.insert_log(%{
+ actor: admin,
+ subject: users,
+ action: "force_password_reset"
+ })
json_response(conn, :no_content, "")
end
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index 2212e93f4..49735b5c2 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.Endpoint do
plug(Pleroma.Plugs.HTTPSecurityPlug)
plug(Pleroma.Plugs.UploadedMedia)
- @static_cache_control "public, no-cache"
+ @static_cache_control "public max-age=86400 must-revalidate"
# InstanceStatic needs to be before Plug.Static to be able to override shipped-static files
# If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index 192984242..d7ae503f6 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -58,6 +58,7 @@ def raw_nodeinfo do
"polls",
"pleroma_explicit_addressing",
"shareable_emoji_packs",
+ "multifetch",
if Config.get([:media_proxy, :enabled]) do
"media_proxy"
end,
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index f69c5c2bc..8fb4aec13 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -171,7 +171,7 @@ defmodule Pleroma.Web.Router do
post("/users/email_invite", AdminAPIController, :email_invite)
get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset)
- patch("/users/:nickname/force_password_reset", AdminAPIController, :force_password_reset)
+ patch("/users/force_password_reset", AdminAPIController, :force_password_reset)
get("/users", AdminAPIController, :list_users)
get("/users/:nickname", AdminAPIController, :user_show)
diff --git a/mix.exs b/mix.exs
index 41542eafd..c9aeeae66 100644
--- a/mix.exs
+++ b/mix.exs
@@ -63,7 +63,7 @@ def copy_nginx_config(%{path: target_path} = release) do
def application do
[
mod: {Pleroma.Application, []},
- extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :myhtmlex, :swarm],
+ extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :fast_sanitize, :swarm],
included_applications: [:ex_syslogger]
]
end
@@ -108,10 +108,8 @@ defp deps do
{:comeonin, "~> 4.1.1"},
{:pbkdf2_elixir, "~> 0.12.3"},
{:trailing_format_plug, "~> 0.0.7"},
- {:fast_sanitize,
- git: "https://git.pleroma.social/pleroma/fast_sanitize.git",
- ref: "1af67547a02a104e26c99d03012383e8643bc4c2"},
- {:html_entities, "~> 0.4"},
+ {:fast_sanitize, "~> 0.1"},
+ {:html_entities, "~> 0.5", override: true},
{:phoenix_html, "~> 2.10"},
{:calendar, "~> 0.17.4"},
{:cachex, "~> 3.0.2"},
diff --git a/mix.lock b/mix.lock
index cfc3b84a8..5b471fe3d 100644
--- a/mix.lock
+++ b/mix.lock
@@ -36,7 +36,8 @@
"ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},
"ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
"excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
- "fast_sanitize": {:git, "https://git.pleroma.social/pleroma/fast_sanitize.git", "1af67547a02a104e26c99d03012383e8643bc4c2", [ref: "1af67547a02a104e26c99d03012383e8643bc4c2"]},
+ "fast_html": {:hex, :fast_html, "0.99.3", "e7ce6245fed0635f4719a31cc409091ed17b2091165a4a1cffbf2ceac77abbf4", [:make, :mix], [], "hexpm"},
+ "fast_sanitize": {:hex, :fast_sanitize, "0.1.3", "e89a743b1679c344abdfcf79778d1499fbc599eca2d8a8cdfaf9ff520986fb72", [:mix], [{:fast_html, "~> 0.99", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm"},
@@ -44,7 +45,7 @@
"gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.17.1", "8baab33482df4907b3eae22f719da492cee3981a26e649b9c2be1c0192616962", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
- "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"},
+ "html_entities": {:hex, :html_entities, "0.5.0", "40f5c5b9cbe23073b48a4e69c67b6c11974f623a76165e2b92d098c0e88ccb1d", [:mix], [], "hexpm"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
"http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]},
"httpoison": {:hex, :httpoison, "1.6.1", "2ce5bf6e535cd0ab02e905ba8c276580bab80052c5c549f53ddea52d72e81f33", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
diff --git a/priv/static/index.html b/priv/static/index.html
index 2518808c4..e995a811b 100644
--- a/priv/static/index.html
+++ b/priv/static/index.html
@@ -1 +1 @@
-
Pleroma
\ No newline at end of file
+Pleroma
diff --git a/priv/static/static/js/2.73375b727cef616c59b4.js b/priv/static/static/js/2.73375b727cef616c59b4.js
new file mode 100644
index 000000000..ebfd9acbd
Binary files /dev/null and b/priv/static/static/js/2.73375b727cef616c59b4.js differ
diff --git a/priv/static/static/js/2.73375b727cef616c59b4.js.map b/priv/static/static/js/2.73375b727cef616c59b4.js.map
new file mode 100644
index 000000000..d2c864eb3
Binary files /dev/null and b/priv/static/static/js/2.73375b727cef616c59b4.js.map differ
diff --git a/priv/static/static/js/app.105d64a8fcdd6724ccde.js b/priv/static/static/js/app.105d64a8fcdd6724ccde.js
new file mode 100644
index 000000000..9cb129d22
Binary files /dev/null and b/priv/static/static/js/app.105d64a8fcdd6724ccde.js differ
diff --git a/priv/static/static/js/app.105d64a8fcdd6724ccde.js.map b/priv/static/static/js/app.105d64a8fcdd6724ccde.js.map
new file mode 100644
index 000000000..ab2588f48
Binary files /dev/null and b/priv/static/static/js/app.105d64a8fcdd6724ccde.js.map differ
diff --git a/priv/static/static/js/vendors~app.5c3fab032deb5f2793cb.js b/priv/static/static/js/vendors~app.5c3fab032deb5f2793cb.js
new file mode 100644
index 000000000..db0f6a9a3
Binary files /dev/null and b/priv/static/static/js/vendors~app.5c3fab032deb5f2793cb.js differ
diff --git a/priv/static/static/js/vendors~app.5c3fab032deb5f2793cb.js.map b/priv/static/static/js/vendors~app.5c3fab032deb5f2793cb.js.map
new file mode 100644
index 000000000..5e7b10459
Binary files /dev/null and b/priv/static/static/js/vendors~app.5c3fab032deb5f2793cb.js.map differ
diff --git a/priv/static/static/styles.json b/priv/static/static/styles.json
index 31a6e0f14..9ebc60eaa 100644
--- a/priv/static/static/styles.json
+++ b/priv/static/static/styles.json
@@ -5,12 +5,15 @@
"bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"],
"ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ],
"monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ],
- "mammal": [ "Mammal", "#272c37", "#444b5d", "#f8f8f8", "#9bacc8", "#7f3142", "#2bd850", "#2b90d9", "#ca8f04" ],
"redmond-xx": "/static/themes/redmond-xx.json",
"redmond-xx-se": "/static/themes/redmond-xx-se.json",
"redmond-xxi": "/static/themes/redmond-xxi.json",
"breezy-dark": "/static/themes/breezy-dark.json",
"breezy-light": "/static/themes/breezy-light.json",
+<<<<<<< HEAD
"ihatebeingalive": "/static/themes/ihatebeingalive.json"
+=======
+ "mammal": "/static/themes/mammal.json"
+>>>>>>> 8a03ce50ea30df3754f2d9856829b036c878e063
}
diff --git a/priv/static/static/themes/mammal.json b/priv/static/static/themes/mammal.json
new file mode 100644
index 000000000..50b8e2f00
--- /dev/null
+++ b/priv/static/static/themes/mammal.json
@@ -0,0 +1,57 @@
+{
+ "_pleroma_theme_version": 2,
+ "name": "Mammal",
+ "theme": {
+ "shadows": {
+ "button": [],
+ "buttonHover": [
+ {
+ "x": "0",
+ "y": "0",
+ "blur": "0",
+ "spread": 1024,
+ "color": "#56a7e1",
+ "alpha": "1",
+ "inset": true
+ }
+ ],
+ "buttonPressed": [
+ {
+ "x": "0",
+ "y": "0",
+ "blur": "0",
+ "spread": 1024,
+ "color": "#56a7e1",
+ "alpha": "1",
+ "inset": true
+ }
+ ],
+ "panel": [],
+ "panelHeader": [],
+ "topBar": []
+ },
+ "opacity": { "input": "1" },
+ "colors": {
+ "bg": "#282c37",
+ "text": "#f8f8f8",
+ "link": "#9bacc8",
+ "fg": "#444b5d",
+ "input": "#FFFFFF",
+ "inputText": "#282c37",
+ "btn": "#2b90d9",
+ "btnText": "#FFFFFF",
+ "cRed": "#7f3142",
+ "cBlue": "#2b90d9",
+ "cGreen": "#2bd850",
+ "cOrange": "#ca8f04"
+ },
+ "radii": {
+ "btn": 4,
+ "input": 4,
+ "panel": "0",
+ "avatar": "4",
+ "avatarAlt": "4",
+ "attachment": "4"
+ }
+ }
+}
diff --git a/priv/static/sw-pleroma.js b/priv/static/sw-pleroma.js
index add8466a9..6c1c99498 100644
Binary files a/priv/static/sw-pleroma.js and b/priv/static/sw-pleroma.js differ
diff --git a/test/object/containment_test.exs b/test/object/containment_test.exs
index 0dc2728b9..71fe5204c 100644
--- a/test/object/containment_test.exs
+++ b/test/object/containment_test.exs
@@ -67,6 +67,20 @@ test "users cannot be collided through fake direction spoofing attempts" do
end) =~
"[error] Could not decode user at fetch https://n1u.moe/users/rye"
end
+
+ test "contain_origin_from_id() gracefully handles cases where no ID is present" do
+ data = %{
+ "type" => "Create",
+ "object" => %{
+ "id" => "http://example.net/~alyssa/activities/1234",
+ "attributedTo" => "http://example.org/~alyssa"
+ },
+ "actor" => "http://example.com/~bob"
+ }
+
+ :error =
+ Containment.contain_origin_from_id("http://example.net/~alyssa/activities/1234", data)
+ end
end
describe "containment of children" do
diff --git a/test/object_test.exs b/test/object_test.exs
index dd228c32f..9247a6d84 100644
--- a/test/object_test.exs
+++ b/test/object_test.exs
@@ -124,6 +124,8 @@ test "refetches if the time since the last refetch is greater than the interval"
%Object{} =
object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ Object.set_cache(object)
+
assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
@@ -133,6 +135,8 @@ test "refetches if the time since the last refetch is greater than the interval"
})
updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
+ object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
+ assert updated_object == object_in_cache
assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8
assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3
end
@@ -141,6 +145,8 @@ test "returns the old object if refetch fails", %{mock_modified: mock_modified}
%Object{} =
object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ Object.set_cache(object)
+
assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
@@ -148,6 +154,8 @@ test "returns the old object if refetch fails", %{mock_modified: mock_modified}
mock_modified.(%Tesla.Env{status: 404, body: ""})
updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
+ object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
+ assert updated_object == object_in_cache
assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4
assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0
end) =~
@@ -160,6 +168,8 @@ test "does not refetch if the time since the last refetch is greater than the in
%Object{} =
object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ Object.set_cache(object)
+
assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
@@ -169,6 +179,8 @@ test "does not refetch if the time since the last refetch is greater than the in
})
updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100)
+ object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
+ assert updated_object == object_in_cache
assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4
assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0
end
@@ -177,6 +189,8 @@ test "preserves internal fields on refetch", %{mock_modified: mock_modified} do
%Object{} =
object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ Object.set_cache(object)
+
assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
@@ -192,6 +206,8 @@ test "preserves internal fields on refetch", %{mock_modified: mock_modified} do
})
updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
+ object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
+ assert updated_object == object_in_cache
assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8
assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3
diff --git a/test/plugs/cache_control_test.exs b/test/plugs/cache_control_test.exs
index 69ce6cc7d..be78b3e1e 100644
--- a/test/plugs/cache_control_test.exs
+++ b/test/plugs/cache_control_test.exs
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.CacheControlTest do
test "Verify Cache-Control header on static assets", %{conn: conn} do
conn = get(conn, "/index.html")
- assert Conn.get_resp_header(conn, "cache-control") == ["public, no-cache"]
+ assert Conn.get_resp_header(conn, "cache-control") == ["public max-age=86400 must-revalidate"]
end
test "Verify Cache-Control header on the API", %{conn: conn} do
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 045c87e95..2a9e4f5a0 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -2565,7 +2565,7 @@ test "sets password_reset_pending to true", %{admin: admin, user: user} do
conn =
build_conn()
|> assign(:user, admin)
- |> patch("/api/pleroma/admin/users/#{user.nickname}/force_password_reset")
+ |> patch("/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
assert json_response(conn, 204) == ""
diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/web/mastodon_api/controllers/conversation_controller_test.exs
index 542af4944..2a1223b18 100644
--- a/test/web/mastodon_api/controllers/conversation_controller_test.exs
+++ b/test/web/mastodon_api/controllers/conversation_controller_test.exs
@@ -59,6 +59,59 @@ test "returns a list of conversations", %{conn: conn} do
assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0
end
+ test "filters conversations by recipients", %{conn: conn} do
+ user_one = insert(:user)
+ user_two = insert(:user)
+ user_three = insert(:user)
+
+ {:ok, direct1} =
+ CommonAPI.post(user_one, %{
+ "status" => "Hi @#{user_two.nickname}!",
+ "visibility" => "direct"
+ })
+
+ {:ok, _direct2} =
+ CommonAPI.post(user_one, %{
+ "status" => "Hi @#{user_three.nickname}!",
+ "visibility" => "direct"
+ })
+
+ {:ok, direct3} =
+ CommonAPI.post(user_one, %{
+ "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
+ "visibility" => "direct"
+ })
+
+ {:ok, _direct4} =
+ CommonAPI.post(user_two, %{
+ "status" => "Hi @#{user_three.nickname}!",
+ "visibility" => "direct"
+ })
+
+ {:ok, direct5} =
+ CommonAPI.post(user_two, %{
+ "status" => "Hi @#{user_one.nickname}!",
+ "visibility" => "direct"
+ })
+
+ [conversation1, conversation2] =
+ conn
+ |> assign(:user, user_one)
+ |> get("/api/v1/conversations", %{"recipients" => [user_two.id]})
+ |> json_response(200)
+
+ assert conversation1["last_status"]["id"] == direct5.id
+ assert conversation2["last_status"]["id"] == direct1.id
+
+ [conversation1] =
+ conn
+ |> assign(:user, user_one)
+ |> get("/api/v1/conversations", %{"recipients" => [user_two.id, user_three.id]})
+ |> json_response(200)
+
+ assert conversation1["last_status"]["id"] == direct3.id
+ end
+
test "updates the last_status on reply", %{conn: conn} do
user_one = insert(:user)
user_two = insert(:user)