diff --git a/CHANGELOG.md b/CHANGELOG.md index 56b6371d5..c133cd9ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - **Breaking:** Admin API: Return link alongside with token on password reset - **Breaking:** Admin API: `PUT /api/pleroma/admin/reports/:id` is now `PATCH /api/pleroma/admin/reports`, see admin_api.md for details - **Breaking:** `/api/pleroma/admin/users/invite_token` now uses `POST`, changed accepted params and returns full invite in json instead of only token string. +- **Breaking** replying to reports is now "report notes", enpoint changed from `POST /api/pleroma/admin/reports/:id/respond` to `POST /api/pleroma/admin/reports/:id/notes` - 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 @@ -83,6 +84,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - ActivityPub: Configurable `type` field of the actors. - Mastodon API: `/api/v1/accounts/:id` has `source/pleroma/actor_type` field. - Mastodon API: `/api/v1/update_credentials` accepts `actor_type` field. +- Captcha: Support native provider +- Captcha: Enable by default ### Fixed @@ -91,6 +94,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MRF: `Delete` activities being exempt from MRF policies - OTP releases: Not being able to configure OAuth expired token cleanup interval - OTP releases: Not being able to configure HTML sanitization policy +- Favorites timeline now ordered by favorite date instead of post date
API Changes diff --git a/config/config.exs b/config/config.exs index 6ed800056..47098858b 100644 --- a/config/config.exs +++ b/config/config.exs @@ -66,9 +66,11 @@ jobs: scheduled_jobs config :pleroma, Pleroma.Captcha, - enabled: false, + enabled: true, seconds_valid: 60, - method: Pleroma.Captcha.Kocaptcha + method: Pleroma.Captcha.Native + +config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch" config :pleroma, :hackney_pools, federation: [ @@ -84,8 +86,6 @@ timeout: 300_000 ] -config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch" - # Upload configuration config :pleroma, Pleroma.Upload, uploader: Pleroma.Uploaders.Local, diff --git a/config/test.exs b/config/test.exs index 9b737d4d7..d52ced612 100644 --- a/config/test.exs +++ b/config/test.exs @@ -68,7 +68,9 @@ queues: false, prune: :disabled -config :pleroma, Pleroma.Scheduler, jobs: [] +config :pleroma, Pleroma.Scheduler, + jobs: [], + global: false config :pleroma, Pleroma.ScheduledActivity, daily_user_limit: 2, diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md index b19793150..d98a78af0 100644 --- a/docs/API/admin_api.md +++ b/docs/API/admin_api.md @@ -614,78 +614,29 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - On success: `204`, empty response -## `POST /api/pleroma/admin/reports/:id/respond` +## `POST /api/pleroma/admin/reports/:id/notes` -### Respond to a report +### Create report note - Params: - - `id` - - `status`: required, the message + - `id`: required, report id + - `content`: required, the message - Response: - On failure: - 400 Bad Request `"Invalid parameters"` when `status` is missing - - 403 Forbidden `{"error": "error_msg"}` - - 404 Not Found `"Not found"` - - On success: JSON, created Mastodon Status entity + - On success: `204`, empty response -```json -{ - "account": { ... }, - "application": { - "name": "Web", - "website": null - }, - "bookmarked": false, - "card": null, - "content": "Your claim is going to be closed", - "created_at": "2019-05-11T17:13:03.000Z", - "emojis": [], - "favourited": false, - "favourites_count": 0, - "id": "9ihuiSL1405I65TmEq", - "in_reply_to_account_id": null, - "in_reply_to_id": null, - "language": null, - "media_attachments": [], - "mentions": [ - { - "acct": "user", - "id": "9i6dAJqSGSKMzLG2Lo", - "url": "https://pleroma.example.org/users/user", - "username": "user" - }, - { - "acct": "admin", - "id": "9hEkA5JsvAdlSrocam", - "url": "https://pleroma.example.org/users/admin", - "username": "admin" - } - ], - "muted": false, - "pinned": false, - "pleroma": { - "content": { - "text/plain": "Your claim is going to be closed" - }, - "conversation_id": 35, - "in_reply_to_account_acct": null, - "local": true, - "spoiler_text": { - "text/plain": "" - } - }, - "reblog": null, - "reblogged": false, - "reblogs_count": 0, - "replies_count": 0, - "sensitive": false, - "spoiler_text": "", - "tags": [], - "uri": "https://pleroma.example.org/objects/cab0836d-9814-46cd-a0ea-529da9db5fcb", - "url": "https://pleroma.example.org/notice/9ihuiSL1405I65TmEq", - "visibility": "direct" -} -``` +## `POST /api/pleroma/admin/reports/:report_id/notes/:id` + +### Delete report note + +- Params: + - `report_id`: required, report id + - `id`: required, note id +- Response: + - On failure: + - 400 Bad Request `"Invalid parameters"` when `status` is missing + - On success: `204`, empty response ## `PUT /api/pleroma/admin/statuses/:id` diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index ef2711e3c..ce2a14210 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -379,13 +379,19 @@ For each pool, the options are: ## Captcha ### Pleroma.Captcha + * `enabled`: Whether the captcha should be shown on registration. * `method`: The method/service to use for captcha. * `seconds_valid`: The time in seconds for which the captcha is valid. ### Captcha providers +#### Pleroma.Captcha.Native + +A built-in captcha provider. Enabled by default. + #### Pleroma.Captcha.Kocaptcha + Kocaptcha is a very simple captcha service with a single API endpoint, the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint `https://captcha.kotobank.ch` is hosted by the developer. diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 480b261cf..510d3273c 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Activity do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.ReportNote alias Pleroma.ThreadMute alias Pleroma.User @@ -48,6 +49,8 @@ defmodule Pleroma.Activity do has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id) # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark has_one(:bookmark, Bookmark) + # This is a fake relation, do not use outside of with_preloaded_report_notes + has_many(:report_notes, ReportNote) has_many(:notifications, Notification, on_delete: :delete_all) # Attention: this is a fake relation, don't try to preload it blindly and expect it to work! @@ -114,6 +117,16 @@ def with_preloaded_bookmark(query, %User{} = user) do def with_preloaded_bookmark(query, _), do: query + def with_preloaded_report_notes(query) do + from([a] in query, + left_join: r in ReportNote, + on: a.id == r.activity_id, + preload: [report_notes: r] + ) + end + + def with_preloaded_report_notes(query, _), do: query + def with_set_thread_muted_field(query, %User{} = user) do from([a] in query, left_join: tm in ThreadMute, diff --git a/lib/pleroma/captcha/native.ex b/lib/pleroma/captcha/native.ex new file mode 100644 index 000000000..5306fe1aa --- /dev/null +++ b/lib/pleroma/captcha/native.ex @@ -0,0 +1,35 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Captcha.Native do + import Pleroma.Web.Gettext + alias Pleroma.Captcha.Service + @behaviour Service + + @impl Service + def new do + case Captcha.get() do + {:timeout} -> + %{error: dgettext("errors", "Captcha timeout")} + + {:ok, answer_data, img_binary} -> + %{ + type: :native, + token: token(), + url: "data:image/png;base64," <> Base.encode64(img_binary), + answer_data: answer_data + } + end + end + + @impl Service + def validate(_token, captcha, captcha) when not is_nil(captcha), do: :ok + def validate(_token, _captcha, _answer), do: {:error, dgettext("errors", "Invalid CAPTCHA")} + + defp token do + 10 + |> :crypto.strong_rand_bytes() + |> Base.url_encode64(padding: false) + end +end diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 706f089dc..c81477f48 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -128,17 +128,35 @@ def insert_log(%{ {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, - action: "report_response", + action: "report_note", subject: %Activity{} = subject, text: text }) do %ModerationLog{ data: %{ "actor" => user_to_map(actor), - "action" => "report_response", + "action" => "report_note", "subject" => report_to_map(subject), - "text" => text, - "message" => "" + "text" => text + } + } + |> insert_log_entry_with_message() + end + + @spec insert_log(%{actor: User, subject: Activity, action: String.t(), text: String.t()}) :: + {:ok, ModerationLog} | {:error, any} + def insert_log(%{ + actor: %User{} = actor, + action: "report_note_delete", + subject: %Activity{} = subject, + text: text + }) do + %ModerationLog{ + data: %{ + "actor" => user_to_map(actor), + "action" => "report_note_delete", + "subject" => report_to_map(subject), + "text" => text } } |> insert_log_entry_with_message() @@ -556,12 +574,24 @@ def get_log_entry_message(%ModerationLog{ def get_log_entry_message(%ModerationLog{ data: %{ "actor" => %{"nickname" => actor_nickname}, - "action" => "report_response", + "action" => "report_note", "subject" => %{"id" => subject_id, "type" => "report"}, "text" => text } }) do - "@#{actor_nickname} responded with '#{text}' to report ##{subject_id}" + "@#{actor_nickname} added note '#{text}' to report ##{subject_id}" + end + + @spec get_log_entry_message(ModerationLog) :: String.t() + def get_log_entry_message(%ModerationLog{ + data: %{ + "actor" => %{"nickname" => actor_nickname}, + "action" => "report_note_delete", + "subject" => %{"id" => subject_id, "type" => "report"}, + "text" => text + } + }) do + "@#{actor_nickname} deleted note '#{text}' from report ##{subject_id}" end @spec get_log_entry_message(ModerationLog) :: String.t() diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index ff0e59241..eb37b95a6 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -23,6 +23,23 @@ defmodule Pleroma.Object do timestamps() end + def with_joined_activity(query, activity_type \\ "Create", join_type \\ :inner) do + object_position = Map.get(query.aliases, :object, 0) + + join(query, join_type, [{object, object_position}], a in Activity, + on: + fragment( + "COALESCE(?->'object'->>'id', ?->>'object') = (? ->> 'id') AND (?->>'type' = ?) ", + a.data, + a.data, + object.data, + a.data, + ^activity_type + ), + as: :object_activity + ) + end + def create(data) do Object.change(%Object{}, %{data: data}) |> Repo.insert() diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex index 9d279fba7..4535ca7c5 100644 --- a/lib/pleroma/pagination.ex +++ b/lib/pleroma/pagination.ex @@ -13,60 +13,66 @@ defmodule Pleroma.Pagination do alias Pleroma.Repo @default_limit 20 + @page_keys ["max_id", "min_id", "limit", "since_id", "order"] - def fetch_paginated(query, params, type \\ :keyset) + def page_keys, do: @page_keys - def fetch_paginated(query, %{"total" => true} = params, :keyset) do + def fetch_paginated(query, params, type \\ :keyset, table_binding \\ nil) + + def fetch_paginated(query, %{"total" => true} = params, :keyset, table_binding) do total = Repo.aggregate(query, :count, :id) %{ total: total, - items: fetch_paginated(query, Map.drop(params, ["total"]), :keyset) + items: fetch_paginated(query, Map.drop(params, ["total"]), :keyset, table_binding) } end - def fetch_paginated(query, params, :keyset) do + def fetch_paginated(query, params, :keyset, table_binding) do options = cast_params(params) query - |> paginate(options, :keyset) + |> paginate(options, :keyset, table_binding) |> Repo.all() |> enforce_order(options) end - def fetch_paginated(query, %{"total" => true} = params, :offset) do - total = Repo.aggregate(query, :count, :id) + def fetch_paginated(query, %{"total" => true} = params, :offset, table_binding) do + total = + query + |> Ecto.Query.exclude(:left_join) + |> Repo.aggregate(:count, :id) %{ total: total, - items: fetch_paginated(query, Map.drop(params, ["total"]), :offset) + items: fetch_paginated(query, Map.drop(params, ["total"]), :offset, table_binding) } end - def fetch_paginated(query, params, :offset) do + def fetch_paginated(query, params, :offset, table_binding) do options = cast_params(params) query - |> paginate(options, :offset) + |> paginate(options, :offset, table_binding) |> Repo.all() end - def paginate(query, options, method \\ :keyset) + def paginate(query, options, method \\ :keyset, table_binding \\ nil) - def paginate(query, options, :keyset) do + def paginate(query, options, :keyset, table_binding) do query - |> restrict(:min_id, options) - |> restrict(:since_id, options) - |> restrict(:max_id, options) - |> restrict(:order, options) - |> restrict(:limit, options) + |> restrict(:min_id, options, table_binding) + |> restrict(:since_id, options, table_binding) + |> restrict(:max_id, options, table_binding) + |> restrict(:order, options, table_binding) + |> restrict(:limit, options, table_binding) end - def paginate(query, options, :offset) do + def paginate(query, options, :offset, table_binding) do query - |> restrict(:order, options) - |> restrict(:offset, options) - |> restrict(:limit, options) + |> restrict(:order, options, table_binding) + |> restrict(:offset, options, table_binding) + |> restrict(:limit, options, table_binding) end defp cast_params(params) do @@ -75,7 +81,8 @@ defp cast_params(params) do since_id: :string, max_id: :string, offset: :integer, - limit: :integer + limit: :integer, + skip_order: :boolean } params = @@ -88,38 +95,48 @@ defp cast_params(params) do changeset.changes end - defp restrict(query, :min_id, %{min_id: min_id}) do - where(query, [q], q.id > ^min_id) + defp restrict(query, :min_id, %{min_id: min_id}, table_binding) do + where(query, [{q, table_position(query, table_binding)}], q.id > ^min_id) end - defp restrict(query, :since_id, %{since_id: since_id}) do - where(query, [q], q.id > ^since_id) + defp restrict(query, :since_id, %{since_id: since_id}, table_binding) do + where(query, [{q, table_position(query, table_binding)}], q.id > ^since_id) end - defp restrict(query, :max_id, %{max_id: max_id}) do - where(query, [q], q.id < ^max_id) + defp restrict(query, :max_id, %{max_id: max_id}, table_binding) do + where(query, [{q, table_position(query, table_binding)}], q.id < ^max_id) end - defp restrict(query, :order, %{min_id: _}) do - order_by(query, [u], fragment("? asc nulls last", u.id)) + defp restrict(query, :order, %{skip_order: true}, _), do: query + + defp restrict(query, :order, %{min_id: _}, table_binding) do + order_by( + query, + [{u, table_position(query, table_binding)}], + fragment("? asc nulls last", u.id) + ) end - defp restrict(query, :order, _options) do - order_by(query, [u], fragment("? desc nulls last", u.id)) + defp restrict(query, :order, _options, table_binding) do + order_by( + query, + [{u, table_position(query, table_binding)}], + fragment("? desc nulls last", u.id) + ) end - defp restrict(query, :offset, %{offset: offset}) do + defp restrict(query, :offset, %{offset: offset}, _table_binding) do offset(query, ^offset) end - defp restrict(query, :limit, options) do + defp restrict(query, :limit, options, _table_binding) do limit = Map.get(options, :limit, @default_limit) query |> limit(^limit) end - defp restrict(query, _, _), do: query + defp restrict(query, _, _, _), do: query defp enforce_order(result, %{min_id: _}) do result @@ -127,4 +144,10 @@ defp enforce_order(result, %{min_id: _}) do end defp enforce_order(result, _), do: result + + defp table_position(%Ecto.Query{} = query, binding_name) do + Map.get(query.aliases, binding_name, 0) + end + + defp table_position(_, _), do: 0 end diff --git a/lib/pleroma/report_note.ex b/lib/pleroma/report_note.ex new file mode 100644 index 000000000..0db86d1a1 --- /dev/null +++ b/lib/pleroma/report_note.ex @@ -0,0 +1,48 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ReportNote do + use Ecto.Schema + + import Ecto.Changeset + import Ecto.Query + + alias Pleroma.Activity + alias Pleroma.Repo + alias Pleroma.ReportNote + alias Pleroma.User + + @type t :: %__MODULE__{} + + schema "report_notes" do + field(:content, :string) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType) + + timestamps() + end + + @spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t(), String.t()) :: + {:ok, ReportNote.t()} | {:error, Changeset.t()} + def create(user_id, activity_id, content) do + attrs = %{ + user_id: user_id, + activity_id: activity_id, + content: content + } + + %ReportNote{} + |> cast(attrs, [:user_id, :activity_id, :content]) + |> validate_required([:user_id, :activity_id, :content]) + |> Repo.insert() + end + + @spec destroy(FlakeId.Ecto.CompatType.t()) :: + {:ok, ReportNote.t()} | {:error, Changeset.t()} + def destroy(id) do + from(r in ReportNote, where: r.id == ^id) + |> Repo.one() + |> Repo.delete() + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 2bb3ad635..16e6b0057 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1068,6 +1068,13 @@ defp maybe_preload_bookmarks(query, opts) do |> Activity.with_preloaded_bookmark(opts["user"]) end + defp maybe_preload_report_notes(query, %{"preload_report_notes" => true}) do + query + |> Activity.with_preloaded_report_notes() + end + + defp maybe_preload_report_notes(query, _), do: query + defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query defp maybe_set_thread_muted_field(query, opts) do @@ -1121,6 +1128,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do Activity |> maybe_preload_objects(opts) |> maybe_preload_bookmarks(opts) + |> maybe_preload_report_notes(opts) |> maybe_set_thread_muted_field(opts) |> maybe_order(opts) |> restrict_recipients(recipients, opts["user"]) @@ -1157,6 +1165,25 @@ def fetch_activities(recipients, opts \\ %{}, pagination \\ :keyset) do |> maybe_update_cc(list_memberships, opts["user"]) end + @doc """ + Fetch favorites activities of user with order by sort adds to favorites + """ + @spec fetch_favourites(User.t(), map(), atom()) :: list(Activity.t()) + def fetch_favourites(user, params \\ %{}, pagination \\ :keyset) do + user.ap_id + |> Activity.Queries.by_actor() + |> Activity.Queries.by_type("Like") + |> Activity.with_joined_object() + |> Object.with_joined_activity() + |> select([_like, object, activity], %{activity | object: object}) + |> order_by([like, _, _], desc: like.id) + |> Pagination.fetch_paginated( + Map.merge(params, %{"skip_order" => true}), + pagination, + :object_activity + ) + end + defp maybe_update_cc(activities, list_memberships, %User{ap_id: user_ap_id}) when is_list(list_memberships) and length(list_memberships) > 0 do Enum.map(activities, fn diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 4ea37fc7b..4073d3d63 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.Object + alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier @@ -188,31 +189,35 @@ def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity) recipients = recipients(actor, activity) - recipients - |> Enum.filter(&User.ap_enabled?/1) - |> Enum.map(fn %{source_data: data} -> data["inbox"] end) - |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) - |> Instances.filter_reachable() - |> Enum.each(fn {inbox, unreachable_since} -> - %User{ap_id: ap_id} = - Enum.find(recipients, fn %{source_data: data} -> data["inbox"] == inbox end) + inboxes = + recipients + |> Enum.filter(&User.ap_enabled?/1) + |> Enum.map(fn %{source_data: data} -> data["inbox"] end) + |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) + |> Instances.filter_reachable() - # Get all the recipients on the same host and add them to cc. Otherwise, a remote - # instance would only accept a first message for the first recipient and ignore the rest. - cc = get_cc_ap_ids(ap_id, recipients) + Repo.checkout(fn -> + Enum.each(inboxes, fn {inbox, unreachable_since} -> + %User{ap_id: ap_id} = + Enum.find(recipients, fn %{source_data: data} -> data["inbox"] == inbox end) - json = - data - |> Map.put("cc", cc) - |> Jason.encode!() + # Get all the recipients on the same host and add them to cc. Otherwise, a remote + # instance would only accept a first message for the first recipient and ignore the rest. + cc = get_cc_ap_ids(ap_id, recipients) - Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{ - inbox: inbox, - json: json, - actor_id: actor.id, - id: activity.data["id"], - unreachable_since: unreachable_since - }) + json = + data + |> Map.put("cc", cc) + |> Jason.encode!() + + Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{ + inbox: inbox, + json: json, + actor_id: actor.id, + id: activity.data["id"], + unreachable_since: unreachable_since + }) + end) end) end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2ca805c09..e87d09134 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -787,6 +787,7 @@ def get_reports(params, page, page_size) do params |> Map.put("type", "Flag") |> Map.put("skip_preload", true) + |> Map.put("preload_report_notes", true) |> Map.put("total", true) |> Map.put("limit", page_size) |> Map.put("offset", (page - 1) * page_size) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 9059aa634..350c4391d 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -201,7 +201,6 @@ def render("followers.json", %{user: user} = opts) do %{ "id" => "#{user.ap_id}/followers", "type" => "OrderedCollection", - "totalItems" => total, "first" => if showing_items do collection(followers, "#{user.ap_id}/followers", 1, showing_items, total) @@ -209,6 +208,7 @@ def render("followers.json", %{user: user} = opts) do "#{user.ap_id}/followers?page=1" end } + |> maybe_put_total_items(showing_count, total) |> Map.merge(Utils.make_json_ld_header()) end @@ -251,6 +251,12 @@ def render("activity_collection_page.json", %{activities: activities, iri: iri}) |> Map.merge(Utils.make_json_ld_header()) end + defp maybe_put_total_items(map, false, _total), do: map + + defp maybe_put_total_items(map, true, total) do + Map.put(map, "totalItems", total) + end + def collection(collection, iri, page, show_items \\ true, total \\ nil) do offset = (page - 1) * 10 items = Enum.slice(collection, offset, 10) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 0a8a56cd8..c8abeff06 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Activity alias Pleroma.ModerationLog alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.ReportNote alias Pleroma.User alias Pleroma.UserInviteToken alias Pleroma.Web.ActivityPub.ActivityPub @@ -240,7 +241,7 @@ def list_instance_statuses(conn, %{"instance" => instance} = params) do }) conn - |> put_view(StatusView) + |> put_view(Pleroma.Web.AdminAPI.StatusView) |> render("index.json", %{activities: activities, as: :activity}) end @@ -643,9 +644,11 @@ def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nic def list_reports(conn, params) do {page, page_size} = page_params(params) + reports = Utils.get_reports(params, page, page_size) + conn |> put_view(ReportView) - |> render("index.json", %{reports: Utils.get_reports(params, page, page_size)}) + |> render("index.json", %{reports: reports}) end def list_grouped_reports(conn, _params) do @@ -689,32 +692,39 @@ def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) d end end - def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do - with false <- is_nil(params["status"]), - %Activity{} <- Activity.get_by_id(id) do - params = - params - |> Map.put("in_reply_to_status_id", id) - |> Map.put("visibility", "direct") - - {:ok, activity} = CommonAPI.post(user, params) - + def report_notes_create(%{assigns: %{user: user}} = conn, %{ + "id" => report_id, + "content" => content + }) do + with {:ok, _} <- ReportNote.create(user.id, report_id, content) do ModerationLog.insert_log(%{ - action: "report_response", + action: "report_note", actor: user, - subject: activity, - text: params["status"] + subject: Activity.get_by_id(report_id), + text: content }) - conn - |> put_view(StatusView) - |> render("show.json", %{activity: activity}) + json_response(conn, :no_content, "") else - true -> - {:param_cast, nil} + _ -> json_response(conn, :bad_request, "") + end + end - nil -> - {:error, :not_found} + def report_notes_delete(%{assigns: %{user: user}} = conn, %{ + "id" => note_id, + "report_id" => report_id + }) do + with {:ok, note} <- ReportNote.destroy(note_id) do + ModerationLog.insert_log(%{ + action: "report_note_delete", + actor: user, + subject: Activity.get_by_id(report_id), + text: note.content + }) + + json_response(conn, :no_content, "") + else + _ -> json_response(conn, :bad_request, "") end end diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index 13602efd9..4880d2992 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -39,7 +39,8 @@ def render("show.json", %{report: report, user: user, account: account, statuses content: content, created_at: created_at, statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}), - state: report.data["state"] + state: report.data["state"], + notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes}) } end @@ -69,6 +70,28 @@ def render("index_grouped.json", %{groups: groups}) do } end + def render("index_notes.json", %{notes: notes}) when is_list(notes) do + Enum.map(notes, &render(__MODULE__, "show_note.json", &1)) + end + + def render("index_notes.json", _), do: [] + + def render("show_note.json", %{ + id: id, + content: content, + user_id: user_id, + inserted_at: inserted_at + }) do + user = User.get_by_id(user_id) + + %{ + id: id, + content: content, + user: merge_account_views(user), + created_at: Utils.to_masto_date(inserted_at) + } + end + defp merge_account_views(%User{} = user) do Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user}) |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) diff --git a/lib/pleroma/web/admin_api/views/status_view.ex b/lib/pleroma/web/admin_api/views/status_view.ex new file mode 100644 index 000000000..6f2b2b09c --- /dev/null +++ b/lib/pleroma/web/admin_api/views/status_view.ex @@ -0,0 +1,42 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.StatusView do + use Pleroma.Web, :view + + require Pleroma.Constants + + alias Pleroma.User + + def render("index.json", opts) do + render_many(opts.activities, __MODULE__, "show.json", opts) + end + + def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do + user = get_user(activity.data["actor"]) + + Pleroma.Web.MastodonAPI.StatusView.render("show.json", opts) + |> Map.merge(%{account: merge_account_views(user)}) + end + + defp merge_account_views(%User{} = user) do + Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user}) + |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) + end + + defp merge_account_views(_), do: %{} + + defp get_user(ap_id) do + cond do + user = User.get_cached_by_ap_id(ap_id) -> + user + + user = User.get_by_guessed_nickname(ap_id) -> + user + + true -> + User.error_user(ap_id) + end + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 74b223cf4..1149fb469 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -346,15 +346,11 @@ def context(%{assigns: %{user: user}} = conn, %{"id" => id}) do @doc "GET /api/v1/favourites" def favourites(%{assigns: %{user: user}} = conn, params) do - params = - params - |> Map.put("type", "Create") - |> Map.put("favorited_by", user.ap_id) - |> Map.put("blocking_user", user) - activities = - ActivityPub.fetch_activities([], params) - |> Enum.reverse() + ActivityPub.fetch_favourites( + user, + Map.take(params, Pleroma.Pagination.page_keys()) + ) conn |> add_link_headers(activities) diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex index 5e04652c2..00da225b9 100644 --- a/lib/pleroma/web/oauth/scopes.ex +++ b/lib/pleroma/web/oauth/scopes.ex @@ -79,7 +79,9 @@ defp authorize_admin_scopes(scopes, app_scopes, %User{} = user) do if user.is_admin || !contains_admin_scopes?(scopes) || !contains_admin_scopes?(app_scopes) do {:ok, scopes} else - {:error, :unsupported_scopes} + # Gracefully dropping admin scopes from requested scopes if user isn't an admin (not raising) + scopes = scopes -- OAuthScopesPlug.filter_descendants(scopes, ["admin"]) + validate(scopes, app_scopes, user) end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 78cb703a9..f6c128283 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -187,7 +187,8 @@ defmodule Pleroma.Web.Router do get("/grouped_reports", AdminAPIController, :list_grouped_reports) get("/reports/:id", AdminAPIController, :report_show) patch("/reports", AdminAPIController, :reports_update) - post("/reports/:id/respond", AdminAPIController, :report_respond) + post("/reports/:id/notes", AdminAPIController, :report_notes_create) + delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete) put("/statuses/:id", AdminAPIController, :status_update) delete("/statuses/:id", AdminAPIController, :status_delete) diff --git a/mix.exs b/mix.exs index 7c8e52a67..f1a62f6e3 100644 --- a/mix.exs +++ b/mix.exs @@ -163,6 +163,9 @@ defp deps do {:remote_ip, git: "https://git.pleroma.social/pleroma/remote_ip.git", ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"}, + {:captcha, + git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", + ref: "c3c795c55f6b49d79d6ac70a0f91e525099fc3e2"}, {:mox, "~> 0.5", only: :test} ] ++ oauth_deps() end diff --git a/mix.lock b/mix.lock index b22918156..401bcdb6e 100644 --- a/mix.lock +++ b/mix.lock @@ -8,6 +8,7 @@ "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, "cachex": {:hex, :cachex, "3.0.3", "4e2d3e05814a5738f5ff3903151d5c25636d72a3527251b753f501ad9c657967", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm"}, "calendar": {:hex, :calendar, "0.17.6", "ec291cb2e4ba499c2e8c0ef5f4ace974e2f9d02ae9e807e711a9b0c7850b9aee", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, + "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "c3c795c55f6b49d79d6ac70a0f91e525099fc3e2", [ref: "c3c795c55f6b49d79d6ac70a0f91e525099fc3e2"]}, "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"}, "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"}, diff --git a/priv/repo/migrations/20191203043610_create_report_notes.exs b/priv/repo/migrations/20191203043610_create_report_notes.exs new file mode 100644 index 000000000..a4f8c096d --- /dev/null +++ b/priv/repo/migrations/20191203043610_create_report_notes.exs @@ -0,0 +1,13 @@ +defmodule Pleroma.Repo.Migrations.CreateReportNotes do + use Ecto.Migration + + def change do + create_if_not_exists table(:report_notes) do + add(:user_id, references(:users, type: :uuid)) + add(:activity_id, references(:activities, type: :uuid)) + add(:content, :string) + + timestamps() + end + end +end diff --git a/priv/static/adminfe/app.2d7d6c47.css b/priv/static/adminfe/app.8589ec81.css similarity index 82% rename from priv/static/adminfe/app.2d7d6c47.css rename to priv/static/adminfe/app.8589ec81.css index 7b8d12926..b82fcc39e 100644 Binary files a/priv/static/adminfe/app.2d7d6c47.css and b/priv/static/adminfe/app.8589ec81.css differ diff --git a/priv/static/adminfe/chunk-0cb6.8d811a09.css b/priv/static/adminfe/chunk-0cb6.8d811a09.css new file mode 100644 index 000000000..cbf59cfb5 Binary files /dev/null and b/priv/static/adminfe/chunk-0cb6.8d811a09.css differ diff --git a/priv/static/adminfe/chunk-15fa.2eb0ac2e.css b/priv/static/adminfe/chunk-15fa.6e185c68.css similarity index 100% rename from priv/static/adminfe/chunk-15fa.2eb0ac2e.css rename to priv/static/adminfe/chunk-15fa.6e185c68.css diff --git a/priv/static/adminfe/chunk-18e1.452c3dba.css b/priv/static/adminfe/chunk-18e1.5bd2ca85.css similarity index 100% rename from priv/static/adminfe/chunk-18e1.452c3dba.css rename to priv/static/adminfe/chunk-18e1.5bd2ca85.css diff --git a/priv/static/adminfe/chunk-48d9.fec5687d.css b/priv/static/adminfe/chunk-23b2.723b6cc5.css similarity index 86% rename from priv/static/adminfe/chunk-48d9.fec5687d.css rename to priv/static/adminfe/chunk-23b2.723b6cc5.css index f0b3bf144..172bce317 100644 Binary files a/priv/static/adminfe/chunk-48d9.fec5687d.css and b/priv/static/adminfe/chunk-23b2.723b6cc5.css differ diff --git a/priv/static/adminfe/chunk-2943.1b6fd9a7.css b/priv/static/adminfe/chunk-2943.1b6fd9a7.css new file mode 100644 index 000000000..0c9284744 Binary files /dev/null and b/priv/static/adminfe/chunk-2943.1b6fd9a7.css differ diff --git a/priv/static/adminfe/chunk-3d1c.b2eb7234.css b/priv/static/adminfe/chunk-3d1c.b2eb7234.css new file mode 100644 index 000000000..ba85e77d5 Binary files /dev/null and b/priv/static/adminfe/chunk-3d1c.b2eb7234.css differ diff --git a/priv/static/adminfe/chunk-4bb1.1fa93c2f.css b/priv/static/adminfe/chunk-4bb1.1fa93c2f.css deleted file mode 100644 index 8ef69fa6d..000000000 Binary files a/priv/static/adminfe/chunk-4bb1.1fa93c2f.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-4df4.e217dea0.css b/priv/static/adminfe/chunk-4df4.e217dea0.css new file mode 100644 index 000000000..4672a9f75 Binary files /dev/null and b/priv/static/adminfe/chunk-4df4.e217dea0.css differ diff --git a/priv/static/adminfe/chunk-63d0.d72c906c.css b/priv/static/adminfe/chunk-538a.062aa087.css similarity index 62% rename from priv/static/adminfe/chunk-63d0.d72c906c.css rename to priv/static/adminfe/chunk-538a.062aa087.css index c0074e6f7..9e23d0fdb 100644 Binary files a/priv/static/adminfe/chunk-63d0.d72c906c.css and b/priv/static/adminfe/chunk-538a.062aa087.css differ diff --git a/priv/static/adminfe/chunk-5668.fef62a66.css b/priv/static/adminfe/chunk-5668.fef62a66.css deleted file mode 100644 index ea5c1fbe3..000000000 Binary files a/priv/static/adminfe/chunk-5668.fef62a66.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-73af.cc4041dc.css b/priv/static/adminfe/chunk-73af.cc4041dc.css deleted file mode 100644 index 1cb3e5949..000000000 Binary files a/priv/static/adminfe/chunk-73af.cc4041dc.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-18dc.bf660489.css b/priv/static/adminfe/chunk-7c6b.c7882778.css similarity index 100% rename from priv/static/adminfe/chunk-18dc.bf660489.css rename to priv/static/adminfe/chunk-7c6b.c7882778.css diff --git a/priv/static/adminfe/chunk-7f8e.2aadcb70.css b/priv/static/adminfe/chunk-7f8e.b6944d38.css similarity index 100% rename from priv/static/adminfe/chunk-7f8e.2aadcb70.css rename to priv/static/adminfe/chunk-7f8e.b6944d38.css diff --git a/priv/static/adminfe/chunk-ce58.e5b0a61d.css b/priv/static/adminfe/chunk-ce58.e5b0a61d.css deleted file mode 100644 index 983f54715..000000000 Binary files a/priv/static/adminfe/chunk-ce58.e5b0a61d.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-elementUI.fbcb853d.css b/priv/static/adminfe/chunk-elementUI.a842fb0a.css similarity index 100% rename from priv/static/adminfe/chunk-elementUI.fbcb853d.css rename to priv/static/adminfe/chunk-elementUI.a842fb0a.css diff --git a/priv/static/adminfe/chunk-libs.74279b9a.css b/priv/static/adminfe/chunk-libs.57fe98a3.css similarity index 100% rename from priv/static/adminfe/chunk-libs.74279b9a.css rename to priv/static/adminfe/chunk-libs.57fe98a3.css diff --git a/priv/static/adminfe/index.html b/priv/static/adminfe/index.html index af2fda4fc..70bb8bd3b 100644 --- a/priv/static/adminfe/index.html +++ b/priv/static/adminfe/index.html @@ -1 +1 @@ -Admin FE
\ No newline at end of file +Admin FE
\ No newline at end of file diff --git a/priv/static/adminfe/static/js/ZhIB.861df339.js b/priv/static/adminfe/static/js/ZhIB.861df339.js deleted file mode 100644 index aeec873c8..000000000 Binary files a/priv/static/adminfe/static/js/ZhIB.861df339.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/ZhIB.861df339.js.map b/priv/static/adminfe/static/js/ZhIB.861df339.js.map deleted file mode 100644 index ff11a2e71..000000000 Binary files a/priv/static/adminfe/static/js/ZhIB.861df339.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/app.9abe83aa.js b/priv/static/adminfe/static/js/app.9abe83aa.js deleted file mode 100644 index c5cd1e386..000000000 Binary files a/priv/static/adminfe/static/js/app.9abe83aa.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/app.9abe83aa.js.map b/priv/static/adminfe/static/js/app.9abe83aa.js.map deleted file mode 100644 index fb99b7519..000000000 Binary files a/priv/static/adminfe/static/js/app.9abe83aa.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/app.9c4316f1.js b/priv/static/adminfe/static/js/app.9c4316f1.js new file mode 100644 index 000000000..6af94c36b Binary files /dev/null and b/priv/static/adminfe/static/js/app.9c4316f1.js differ diff --git a/priv/static/adminfe/static/js/app.9c4316f1.js.map b/priv/static/adminfe/static/js/app.9c4316f1.js.map new file mode 100644 index 000000000..4b729c61a Binary files /dev/null and b/priv/static/adminfe/static/js/app.9c4316f1.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-0620.c765c190.js b/priv/static/adminfe/static/js/chunk-0620.c765c190.js new file mode 100644 index 000000000..72077a5ac Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0620.c765c190.js differ diff --git a/priv/static/adminfe/static/js/chunk-0620.c765c190.js.map b/priv/static/adminfe/static/js/chunk-0620.c765c190.js.map new file mode 100644 index 000000000..f39b8237f Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0620.c765c190.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-0cb6.b9f32e0c.js b/priv/static/adminfe/static/js/chunk-0cb6.b9f32e0c.js new file mode 100644 index 000000000..967eefab2 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0cb6.b9f32e0c.js differ diff --git a/priv/static/adminfe/static/js/chunk-0cb6.b9f32e0c.js.map b/priv/static/adminfe/static/js/chunk-0cb6.b9f32e0c.js.map new file mode 100644 index 000000000..c8ade8253 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0cb6.b9f32e0c.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-15fa.bea28a69.js b/priv/static/adminfe/static/js/chunk-15fa.34dcb9d8.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-15fa.bea28a69.js rename to priv/static/adminfe/static/js/chunk-15fa.34dcb9d8.js index d8b0379b2..b0819b138 100644 Binary files a/priv/static/adminfe/static/js/chunk-15fa.bea28a69.js and b/priv/static/adminfe/static/js/chunk-15fa.34dcb9d8.js differ diff --git a/priv/static/adminfe/static/js/chunk-15fa.bea28a69.js.map b/priv/static/adminfe/static/js/chunk-15fa.34dcb9d8.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-15fa.bea28a69.js.map rename to priv/static/adminfe/static/js/chunk-15fa.34dcb9d8.js.map index ba6f58b57..2ec54c8aa 100644 Binary files a/priv/static/adminfe/static/js/chunk-15fa.bea28a69.js.map and b/priv/static/adminfe/static/js/chunk-15fa.34dcb9d8.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-18dc.2eb81268.js b/priv/static/adminfe/static/js/chunk-18dc.2eb81268.js deleted file mode 100644 index e2f5b6089..000000000 Binary files a/priv/static/adminfe/static/js/chunk-18dc.2eb81268.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-18dc.2eb81268.js.map b/priv/static/adminfe/static/js/chunk-18dc.2eb81268.js.map deleted file mode 100644 index 1103fb1ac..000000000 Binary files a/priv/static/adminfe/static/js/chunk-18dc.2eb81268.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-18e1.5907d2f1.js b/priv/static/adminfe/static/js/chunk-18e1.f8bb78f3.js similarity index 97% rename from priv/static/adminfe/static/js/chunk-18e1.5907d2f1.js rename to priv/static/adminfe/static/js/chunk-18e1.f8bb78f3.js index eafc28fda..4ddfe2bc2 100644 Binary files a/priv/static/adminfe/static/js/chunk-18e1.5907d2f1.js and b/priv/static/adminfe/static/js/chunk-18e1.f8bb78f3.js differ diff --git a/priv/static/adminfe/static/js/chunk-18e1.5907d2f1.js.map b/priv/static/adminfe/static/js/chunk-18e1.f8bb78f3.js.map similarity index 98% rename from priv/static/adminfe/static/js/chunk-18e1.5907d2f1.js.map rename to priv/static/adminfe/static/js/chunk-18e1.f8bb78f3.js.map index f8c886009..b61e3bc20 100644 Binary files a/priv/static/adminfe/static/js/chunk-18e1.5907d2f1.js.map and b/priv/static/adminfe/static/js/chunk-18e1.f8bb78f3.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-23b2.442bb8df.js b/priv/static/adminfe/static/js/chunk-23b2.442bb8df.js new file mode 100644 index 000000000..61cfc7826 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-23b2.442bb8df.js differ diff --git a/priv/static/adminfe/static/js/chunk-23b2.442bb8df.js.map b/priv/static/adminfe/static/js/chunk-23b2.442bb8df.js.map new file mode 100644 index 000000000..474d1086e Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-23b2.442bb8df.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-2943.8ab5d0d9.js b/priv/static/adminfe/static/js/chunk-2943.8ab5d0d9.js new file mode 100644 index 000000000..85b40b995 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-2943.8ab5d0d9.js differ diff --git a/priv/static/adminfe/static/js/chunk-2943.8ab5d0d9.js.map b/priv/static/adminfe/static/js/chunk-2943.8ab5d0d9.js.map new file mode 100644 index 000000000..0ecc45de4 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-2943.8ab5d0d9.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-3d1c.3334d3f1.js b/priv/static/adminfe/static/js/chunk-3d1c.3334d3f1.js new file mode 100644 index 000000000..9a9c3b049 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-3d1c.3334d3f1.js differ diff --git a/priv/static/adminfe/static/js/chunk-3d1c.3334d3f1.js.map b/priv/static/adminfe/static/js/chunk-3d1c.3334d3f1.js.map new file mode 100644 index 000000000..3dd0d77a9 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-3d1c.3334d3f1.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-48d9.5e74b256.js b/priv/static/adminfe/static/js/chunk-48d9.5e74b256.js deleted file mode 100644 index ed27be290..000000000 Binary files a/priv/static/adminfe/static/js/chunk-48d9.5e74b256.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-48d9.5e74b256.js.map b/priv/static/adminfe/static/js/chunk-48d9.5e74b256.js.map deleted file mode 100644 index 0434b2dd2..000000000 Binary files a/priv/static/adminfe/static/js/chunk-48d9.5e74b256.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-4bb1.296363c0.js b/priv/static/adminfe/static/js/chunk-4bb1.296363c0.js deleted file mode 100644 index f71148096..000000000 Binary files a/priv/static/adminfe/static/js/chunk-4bb1.296363c0.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-4bb1.296363c0.js.map b/priv/static/adminfe/static/js/chunk-4bb1.296363c0.js.map deleted file mode 100644 index 539f0092b..000000000 Binary files a/priv/static/adminfe/static/js/chunk-4bb1.296363c0.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-4df4.9655f394.js b/priv/static/adminfe/static/js/chunk-4df4.9655f394.js new file mode 100644 index 000000000..afed4bab6 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-4df4.9655f394.js differ diff --git a/priv/static/adminfe/static/js/chunk-4df4.9655f394.js.map b/priv/static/adminfe/static/js/chunk-4df4.9655f394.js.map new file mode 100644 index 000000000..a1e9bca7a Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-4df4.9655f394.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-538a.04530055.js b/priv/static/adminfe/static/js/chunk-538a.04530055.js new file mode 100644 index 000000000..2455b9a9a Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-538a.04530055.js differ diff --git a/priv/static/adminfe/static/js/chunk-538a.04530055.js.map b/priv/static/adminfe/static/js/chunk-538a.04530055.js.map new file mode 100644 index 000000000..d3741c30a Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-538a.04530055.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-5668.d7d15598.js b/priv/static/adminfe/static/js/chunk-5668.d7d15598.js deleted file mode 100644 index 4cee06146..000000000 Binary files a/priv/static/adminfe/static/js/chunk-5668.d7d15598.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-5668.d7d15598.js.map b/priv/static/adminfe/static/js/chunk-5668.d7d15598.js.map deleted file mode 100644 index 559960c10..000000000 Binary files a/priv/static/adminfe/static/js/chunk-5668.d7d15598.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-63d0.298e8ca8.js b/priv/static/adminfe/static/js/chunk-63d0.298e8ca8.js deleted file mode 100644 index 6a1e0060e..000000000 Binary files a/priv/static/adminfe/static/js/chunk-63d0.298e8ca8.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-63d0.298e8ca8.js.map b/priv/static/adminfe/static/js/chunk-63d0.298e8ca8.js.map deleted file mode 100644 index c7ab8321c..000000000 Binary files a/priv/static/adminfe/static/js/chunk-63d0.298e8ca8.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-73af.31c5a652.js b/priv/static/adminfe/static/js/chunk-73af.31c5a652.js deleted file mode 100644 index 0336d5fbc..000000000 Binary files a/priv/static/adminfe/static/js/chunk-73af.31c5a652.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-73af.31c5a652.js.map b/priv/static/adminfe/static/js/chunk-73af.31c5a652.js.map deleted file mode 100644 index c055614d7..000000000 Binary files a/priv/static/adminfe/static/js/chunk-73af.31c5a652.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-7c6b.5240e052.js b/priv/static/adminfe/static/js/chunk-7c6b.5240e052.js new file mode 100644 index 000000000..12eb54a32 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-7c6b.5240e052.js differ diff --git a/priv/static/adminfe/static/js/chunk-7c6b.5240e052.js.map b/priv/static/adminfe/static/js/chunk-7c6b.5240e052.js.map new file mode 100644 index 000000000..1463b8ba4 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-7c6b.5240e052.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-7f8e.e63a7023.js b/priv/static/adminfe/static/js/chunk-7f8e.c1eb619d.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-7f8e.e63a7023.js rename to priv/static/adminfe/static/js/chunk-7f8e.c1eb619d.js index af0300833..56ce1d5ef 100644 Binary files a/priv/static/adminfe/static/js/chunk-7f8e.e63a7023.js and b/priv/static/adminfe/static/js/chunk-7f8e.c1eb619d.js differ diff --git a/priv/static/adminfe/static/js/chunk-7f8e.e63a7023.js.map b/priv/static/adminfe/static/js/chunk-7f8e.c1eb619d.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-7f8e.e63a7023.js.map rename to priv/static/adminfe/static/js/chunk-7f8e.c1eb619d.js.map index 5925cfd2e..459e7f785 100644 Binary files a/priv/static/adminfe/static/js/chunk-7f8e.e63a7023.js.map and b/priv/static/adminfe/static/js/chunk-7f8e.c1eb619d.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-ce58.20269345.js b/priv/static/adminfe/static/js/chunk-ce58.20269345.js deleted file mode 100644 index 430de04ff..000000000 Binary files a/priv/static/adminfe/static/js/chunk-ce58.20269345.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-ce58.20269345.js.map b/priv/static/adminfe/static/js/chunk-ce58.20269345.js.map deleted file mode 100644 index 107e05744..000000000 Binary files a/priv/static/adminfe/static/js/chunk-ce58.20269345.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-elementUI.adb56751.js b/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-elementUI.adb56751.js rename to priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js index 3ae3eefc7..90ae35a35 100644 Binary files a/priv/static/adminfe/static/js/chunk-elementUI.adb56751.js and b/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js differ diff --git a/priv/static/adminfe/static/js/chunk-elementUI.adb56751.js.map b/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-elementUI.adb56751.js.map rename to priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js.map index 841b540b8..678122a98 100644 Binary files a/priv/static/adminfe/static/js/chunk-elementUI.adb56751.js.map and b/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-libs.16bdd178.js b/priv/static/adminfe/static/js/chunk-libs.35c18287.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-libs.16bdd178.js rename to priv/static/adminfe/static/js/chunk-libs.35c18287.js index 8541a42a7..4b76d98e6 100644 Binary files a/priv/static/adminfe/static/js/chunk-libs.16bdd178.js and b/priv/static/adminfe/static/js/chunk-libs.35c18287.js differ diff --git a/priv/static/adminfe/static/js/chunk-libs.16bdd178.js.map b/priv/static/adminfe/static/js/chunk-libs.35c18287.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-libs.16bdd178.js.map rename to priv/static/adminfe/static/js/chunk-libs.35c18287.js.map index 1dfa38d82..0a3580834 100644 Binary files a/priv/static/adminfe/static/js/chunk-libs.16bdd178.js.map and b/priv/static/adminfe/static/js/chunk-libs.35c18287.js.map differ diff --git a/priv/static/adminfe/static/js/runtime.46db235c.js b/priv/static/adminfe/static/js/runtime.46db235c.js new file mode 100644 index 000000000..898c5b505 Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.46db235c.js differ diff --git a/priv/static/adminfe/static/js/runtime.46db235c.js.map b/priv/static/adminfe/static/js/runtime.46db235c.js.map new file mode 100644 index 000000000..33791c005 Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.46db235c.js.map differ diff --git a/priv/static/adminfe/static/js/runtime.5485cb1b.js b/priv/static/adminfe/static/js/runtime.5485cb1b.js deleted file mode 100644 index c89e0b563..000000000 Binary files a/priv/static/adminfe/static/js/runtime.5485cb1b.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/runtime.5485cb1b.js.map b/priv/static/adminfe/static/js/runtime.5485cb1b.js.map deleted file mode 100644 index e1f0c8771..000000000 Binary files a/priv/static/adminfe/static/js/runtime.5485cb1b.js.map and /dev/null differ diff --git a/priv/static/index.html b/priv/static/index.html index cd186d3d8..2467aa22a 100644 --- a/priv/static/index.html +++ b/priv/static/index.html @@ -1 +1 @@ -Pleroma
\ No newline at end of file +Pleroma
\ No newline at end of file diff --git a/priv/static/static/font/LICENSE.txt b/priv/static/static/font/LICENSE.txt deleted file mode 100755 index 95966f00e..000000000 --- a/priv/static/static/font/LICENSE.txt +++ /dev/null @@ -1,39 +0,0 @@ -Font license info - - -## Font Awesome - - Copyright (C) 2016 by Dave Gandy - - Author: Dave Gandy - License: SIL () - Homepage: http://fortawesome.github.com/Font-Awesome/ - - -## Entypo - - Copyright (C) 2012 by Daniel Bruce - - Author: Daniel Bruce - License: SIL (http://scripts.sil.org/OFL) - Homepage: http://www.entypo.com - - -## Iconic - - Copyright (C) 2012 by P.J. Onori - - Author: P.J. Onori - License: SIL (http://scripts.sil.org/OFL) - Homepage: http://somerandomdude.com/work/iconic/ - - -## Fontelico - - Copyright (C) 2012 by Fontello project - - Author: Crowdsourced, for Fontello project - License: SIL (http://scripts.sil.org/OFL) - Homepage: http://fontello.com - - diff --git a/priv/static/static/font/README.txt b/priv/static/static/font/README.txt deleted file mode 100755 index beaab3366..000000000 --- a/priv/static/static/font/README.txt +++ /dev/null @@ -1,75 +0,0 @@ -This webfont is generated by http://fontello.com open source project. - - -================================================================================ -Please, note, that you should obey original font licenses, used to make this -webfont pack. Details available in LICENSE.txt file. - -- Usually, it's enough to publish content of LICENSE.txt file somewhere on your - site in "About" section. - -- If your project is open-source, usually, it will be ok to make LICENSE.txt - file publicly available in your repository. - -- Fonts, used in Fontello, don't require a clickable link on your site. - But any kind of additional authors crediting is welcome. -================================================================================ - - -Comments on archive content ---------------------------- - -- /font/* - fonts in different formats - -- /css/* - different kinds of css, for all situations. Should be ok with - twitter bootstrap. Also, you can skip style and assign icon classes - directly to text elements, if you don't mind about IE7. - -- demo.html - demo file, to show your webfont content - -- LICENSE.txt - license info about source fonts, used to build your one. - -- config.json - keeps your settings. You can import it back into fontello - anytime, to continue your work - - -Why so many CSS files ? ------------------------ - -Because we like to fit all your needs :) - -- basic file, .css - is usually enough, it contains @font-face - and character code definitions - -- *-ie7.css - if you need IE7 support, but still don't wish to put char codes - directly into html - -- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face - rules, but still wish to benefit from css generation. That can be very - convenient for automated asset build systems. When you need to update font - - no need to manually edit files, just override old version with archive - content. See fontello source code for examples. - -- *-embedded.css - basic css file, but with embedded WOFF font, to avoid - CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. - We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` - server headers. But if you ok with dirty hack - this file is for you. Note, - that data url moved to separate @font-face to avoid problems with - - - - - - - -
-

fontello font demo

- -
-
-
-
icon-cancel0xe800
-
icon-upload0xe801
-
icon-star0xe802
-
icon-star-empty0xe803
-
-
-
icon-retweet0xe804
-
icon-eye-off0xe805
-
icon-search0xe806
-
icon-cog0xe807
-
-
-
icon-logout0xe808
-
icon-down-open0xe809
-
icon-attach0xe80a
-
icon-picture0xe80b
-
-
-
icon-video0xe80c
-
icon-right-open0xe80d
-
icon-left-open0xe80e
-
icon-up-open0xe80f
-
-
-
icon-bell-ringing-o0xe810
-
icon-lock0xe811
-
icon-globe0xe812
-
icon-brush0xe813
-
-
-
icon-attention0xe814
-
icon-plus0xe815
-
icon-adjust0xe816
-
icon-edit0xe817
-
-
-
icon-pencil0xe818
-
icon-pin0xe819
-
icon-wrench0xe81a
-
icon-chart-bar0xe81b
-
-
-
icon-zoom-in0xe81c
-
icon-spin30xe832
-
icon-spin40xe834
-
icon-link-ext0xf08e
-
-
-
icon-link-ext-alt0xf08f
-
icon-menu0xf0c9
-
icon-mail-alt0xf0e0
-
icon-gauge0xf0e4
-
-
-
icon-comment-empty0xf0e5
-
icon-bell-alt0xf0f3
-
icon-plus-squared0xf0fe
-
icon-reply0xf112
-
-
-
icon-smile0xf118
-
icon-lock-open-alt0xf13e
-
icon-ellipsis0xf141
-
icon-play-circled0xf144
-
-
-
icon-thumbs-up-alt0xf164
-
icon-binoculars0xf1e5
-
icon-user-plus0xf234
-
-
- - - \ No newline at end of file diff --git a/priv/static/static/font/font/fontello.eot b/priv/static/static/font/font/fontello.eot deleted file mode 100755 index 1703fd97f..000000000 Binary files a/priv/static/static/font/font/fontello.eot and /dev/null differ diff --git a/priv/static/static/font/font/fontello.woff2 b/priv/static/static/font/font/fontello.woff2 deleted file mode 100755 index 078991eb8..000000000 Binary files a/priv/static/static/font/font/fontello.woff2 and /dev/null differ diff --git a/priv/static/static/font/fontello.1576078371855.svg b/priv/static/static/font/fontello.1576078371855.svg deleted file mode 100644 index f5e497ce4..000000000 --- a/priv/static/static/font/fontello.1576078371855.svg +++ /dev/null @@ -1,104 +0,0 @@ - - - -Copyright (C) 2019 by original authors @ fontello.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/priv/static/static/font/fontello.1576078371855.ttf b/priv/static/static/font/fontello.1576078371855.ttf deleted file mode 100644 index 310bce50b..000000000 Binary files a/priv/static/static/font/fontello.1576078371855.ttf and /dev/null differ diff --git a/priv/static/static/font/fontello.1576078371855.woff b/priv/static/static/font/fontello.1576078371855.woff deleted file mode 100644 index 89f06fb57..000000000 Binary files a/priv/static/static/font/fontello.1576078371855.woff and /dev/null differ diff --git a/priv/static/static/font/fontello.1576078371855.woff2 b/priv/static/static/font/fontello.1576078371855.woff2 deleted file mode 100644 index c8adc1fe0..000000000 Binary files a/priv/static/static/font/fontello.1576078371855.woff2 and /dev/null differ diff --git a/priv/static/static/font/fontello.1576078371855.eot b/priv/static/static/font/fontello.1576166651574.eot similarity index 98% rename from priv/static/static/font/fontello.1576078371855.eot rename to priv/static/static/font/fontello.1576166651574.eot index 6ecbde0e7..fb27d4037 100644 Binary files a/priv/static/static/font/fontello.1576078371855.eot and b/priv/static/static/font/fontello.1576166651574.eot differ diff --git a/priv/static/static/font/font/fontello.svg b/priv/static/static/font/fontello.1576166651574.svg similarity index 100% rename from priv/static/static/font/font/fontello.svg rename to priv/static/static/font/fontello.1576166651574.svg diff --git a/priv/static/static/font/font/fontello.ttf b/priv/static/static/font/fontello.1576166651574.ttf old mode 100755 new mode 100644 similarity index 99% rename from priv/static/static/font/font/fontello.ttf rename to priv/static/static/font/fontello.1576166651574.ttf index e9ed78031..c49743ec6 Binary files a/priv/static/static/font/font/fontello.ttf and b/priv/static/static/font/fontello.1576166651574.ttf differ diff --git a/priv/static/static/font/font/fontello.woff b/priv/static/static/font/fontello.1576166651574.woff old mode 100755 new mode 100644 similarity index 98% rename from priv/static/static/font/font/fontello.woff rename to priv/static/static/font/fontello.1576166651574.woff index 1d5025d3c..bbffd6413 Binary files a/priv/static/static/font/font/fontello.woff and b/priv/static/static/font/fontello.1576166651574.woff differ diff --git a/priv/static/static/font/fontello.1576166651574.woff2 b/priv/static/static/font/fontello.1576166651574.woff2 new file mode 100644 index 000000000..d35dce862 Binary files /dev/null and b/priv/static/static/font/fontello.1576166651574.woff2 differ diff --git a/priv/static/static/fontello.1576078371855.css b/priv/static/static/fontello.1576166651574.css similarity index 88% rename from priv/static/static/fontello.1576078371855.css rename to priv/static/static/fontello.1576166651574.css index 7947a89d7..54f9fe05f 100644 Binary files a/priv/static/static/fontello.1576078371855.css and b/priv/static/static/fontello.1576166651574.css differ diff --git a/priv/static/static/js/app.5879b8f3d0565ed4735f.js b/priv/static/static/js/app.5879b8f3d0565ed4735f.js deleted file mode 100644 index d324a8ae4..000000000 Binary files a/priv/static/static/js/app.5879b8f3d0565ed4735f.js and /dev/null differ diff --git a/priv/static/static/js/app.5879b8f3d0565ed4735f.js.map b/priv/static/static/js/app.5879b8f3d0565ed4735f.js.map deleted file mode 100644 index f668b7a50..000000000 Binary files a/priv/static/static/js/app.5879b8f3d0565ed4735f.js.map and /dev/null differ diff --git a/priv/static/static/js/app.a9b3f4c3e79baf3fa8b7.js b/priv/static/static/js/app.a9b3f4c3e79baf3fa8b7.js new file mode 100644 index 000000000..124f284be Binary files /dev/null and b/priv/static/static/js/app.a9b3f4c3e79baf3fa8b7.js differ diff --git a/priv/static/static/js/app.a9b3f4c3e79baf3fa8b7.js.map b/priv/static/static/js/app.a9b3f4c3e79baf3fa8b7.js.map new file mode 100644 index 000000000..7c369185e Binary files /dev/null and b/priv/static/static/js/app.a9b3f4c3e79baf3fa8b7.js.map differ diff --git a/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js b/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js index 9fe9e5eb7..a64eee9a9 100644 Binary files a/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js and b/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js differ diff --git a/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js.map b/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js.map index cbcbb50c1..2e88b3ce2 100644 Binary files a/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js.map and b/priv/static/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js.map differ diff --git a/priv/static/sw-pleroma.js b/priv/static/sw-pleroma.js index 94268126a..4738f3391 100644 Binary files a/priv/static/sw-pleroma.js and b/priv/static/sw-pleroma.js differ diff --git a/priv/static/sw.js b/priv/static/sw.js index c2de0cfe0..5605bb05e 100644 Binary files a/priv/static/sw.js and b/priv/static/sw.js differ diff --git a/test/captcha_test.exs b/test/captcha_test.exs index 9f395d6b4..393c8219e 100644 --- a/test/captcha_test.exs +++ b/test/captcha_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.CaptchaTest do import Tesla.Mock alias Pleroma.Captcha.Kocaptcha + alias Pleroma.Captcha.Native @ets_options [:ordered_set, :private, :named_table, {:read_concurrency, true}] @@ -43,4 +44,21 @@ test "new and validate" do ) == :ok end end + + describe "Native" do + test "new and validate" do + new = Native.new() + + assert %{ + answer_data: answer, + token: token, + type: :native, + url: "data:image/png;base64," <> _ + } = new + + assert is_binary(answer) + assert :ok = Native.validate(token, answer, answer) + assert {:error, "Invalid CAPTCHA"} == Native.validate(token, answer, answer <> "foobar") + end + end end diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 9b2c97963..ba81c0d4b 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -5,7 +5,9 @@ defmodule Pleroma.Conversation.ParticipationTest do use Pleroma.DataCase import Pleroma.Factory + alias Pleroma.Conversation alias Pleroma.Conversation.Participation + alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -98,7 +100,9 @@ test "it creates a participation for a conversation and a user" do assert participation.user_id == user.id assert participation.conversation_id == conversation.id + # Needed because updated_at is accurate down to a second :timer.sleep(1000) + # Creating again returns the same participation {:ok, %Participation{} = participation_two} = Participation.create_for_user_and_conversation(user, conversation) @@ -150,9 +154,7 @@ test "it marks all the user's participations as read" do test "gets all the participations for a user, ordered by updated at descending" do user = insert(:user) {:ok, activity_one} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"}) - :timer.sleep(1000) {:ok, activity_two} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"}) - :timer.sleep(1000) {:ok, activity_three} = CommonAPI.post(user, %{ @@ -161,6 +163,17 @@ test "gets all the participations for a user, ordered by updated at descending" "in_reply_to_status_id" => activity_one.id }) + # Offset participations because the accuracy of updated_at is down to a second + + for {activity, offset} <- [{activity_two, 1}, {activity_three, 2}] do + conversation = Conversation.get_for_ap_id(activity.data["context"]) + participation = Participation.for_user_and_conversation(user, conversation) + updated_at = NaiveDateTime.add(Map.get(participation, :updated_at), offset) + + Ecto.Changeset.change(participation, %{updated_at: updated_at}) + |> Repo.update!() + end + assert [participation_one, participation_two] = Participation.for_user(user) object2 = Pleroma.Object.normalize(activity_two) diff --git a/test/moderation_log_test.exs b/test/moderation_log_test.exs index 4240f6a65..f2168b735 100644 --- a/test/moderation_log_test.exs +++ b/test/moderation_log_test.exs @@ -214,7 +214,7 @@ test "logging report response", %{moderator: moderator} do {:ok, _} = ModerationLog.insert_log(%{ actor: moderator, - action: "report_response", + action: "report_note", subject: report, text: "look at this" }) @@ -222,7 +222,7 @@ test "logging report response", %{moderator: moderator} do log = Repo.one(ModerationLog) assert log.data["message"] == - "@#{moderator.nickname} responded with 'look at this' to report ##{report.id}" + "@#{moderator.nickname} added note 'look at this' to report ##{report.id}" end test "logging status sensitivity update", %{moderator: moderator} do diff --git a/test/plugs/rate_limiter_test.exs b/test/plugs/rate_limiter_test.exs index 49f63c424..78f1ea9e4 100644 --- a/test/plugs/rate_limiter_test.exs +++ b/test/plugs/rate_limiter_test.exs @@ -145,9 +145,9 @@ test "are restricted based on remote IP" do test "can have limits seperate from unauthenticated connections" do limiter_name = :test_authenticated - scale = 1000 + scale = 50 limit = 5 - Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {scale, limit}]) + Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}]) opts = RateLimiter.init(name: limiter_name) @@ -164,16 +164,6 @@ test "can have limits seperate from unauthenticated connections" do assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) assert conn.halted - - Process.sleep(1550) - - conn = conn(:get, "/") |> assign(:user, user) - conn = RateLimiter.call(conn, opts) - assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts) - - refute conn.status == Plug.Conn.Status.code(:too_many_requests) - refute conn.resp_body - refute conn.halted end test "diffrerent users are counted independently" do diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 8ae0f45d0..1520c8a9b 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1625,6 +1625,35 @@ test "detects hidden follows/followers for friendica" do end end + describe "fetch_favourites/3" do + test "returns a favourite activities sorted by adds to favorite" do + user = insert(:user) + other_user = insert(:user) + user1 = insert(:user) + user2 = insert(:user) + {:ok, a1} = CommonAPI.post(user1, %{"status" => "bla"}) + {:ok, _a2} = CommonAPI.post(user2, %{"status" => "traps are happy"}) + {:ok, a3} = CommonAPI.post(user2, %{"status" => "Trees Are "}) + {:ok, a4} = CommonAPI.post(user2, %{"status" => "Agent Smith "}) + {:ok, a5} = CommonAPI.post(user1, %{"status" => "Red or Blue "}) + + {:ok, _, _} = CommonAPI.favorite(a4.id, user) + {:ok, _, _} = CommonAPI.favorite(a3.id, other_user) + {:ok, _, _} = CommonAPI.favorite(a3.id, user) + {:ok, _, _} = CommonAPI.favorite(a5.id, other_user) + {:ok, _, _} = CommonAPI.favorite(a5.id, user) + {:ok, _, _} = CommonAPI.favorite(a4.id, other_user) + {:ok, _, _} = CommonAPI.favorite(a1.id, user) + {:ok, _, _} = CommonAPI.favorite(a1.id, other_user) + result = ActivityPub.fetch_favourites(user) + + assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id] + + result = ActivityPub.fetch_favourites(user, %{"limit" => 2}) + assert Enum.map(result, & &1.id) == [a1.id, a5.id] + end + end + describe "Move activity" do test "create" do %{ap_id: old_ap_id} = old_user = insert(:user) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 3299be2d5..8374b8d23 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -126,7 +126,7 @@ test "sets totalItems to zero when followers are hidden" do {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) user = Map.merge(user, %{hide_followers_count: true, hide_followers: true}) - assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user}) + refute UserView.render("followers.json", %{user: user}) |> Map.has_key?("totalItems") end test "sets correct totalItems when followers are hidden but the follower counter is not" do diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 23ca7f110..49ff005b6 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -10,6 +10,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do alias Pleroma.HTML alias Pleroma.ModerationLog alias Pleroma.Repo + alias Pleroma.ReportNote alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.UserInviteToken @@ -1831,61 +1832,6 @@ test "account not empty if status was deleted", %{ end end - describe "POST /api/pleroma/admin/reports/:id/respond" do - setup %{conn: conn} do - admin = insert(:user, is_admin: true) - - %{conn: assign(conn, :user, admin), admin: admin} - end - - test "returns created dm", %{conn: conn, admin: admin} do - [reporter, target_user] = insert_pair(:user) - activity = insert(:note_activity, user: target_user) - - {:ok, %{id: report_id}} = - CommonAPI.report(reporter, %{ - "account_id" => target_user.id, - "comment" => "I feel offended", - "status_ids" => [activity.id] - }) - - response = - conn - |> post("/api/pleroma/admin/reports/#{report_id}/respond", %{ - "status" => "I will check it out" - }) - |> json_response(:ok) - - recipients = Enum.map(response["mentions"], & &1["username"]) - - assert reporter.nickname in recipients - assert response["content"] == "I will check it out" - assert response["visibility"] == "direct" - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} responded with 'I will check it out' to report ##{ - response["id"] - }" - end - - test "returns 400 when status is missing", %{conn: conn} do - conn = post(conn, "/api/pleroma/admin/reports/test/respond") - - assert json_response(conn, :bad_request) == "Invalid parameters" - end - - test "returns 404 when report id is invalid", %{conn: conn} do - conn = - post(conn, "/api/pleroma/admin/reports/test/respond", %{ - "status" => "foo" - }) - - assert json_response(conn, :not_found) == "Not found" - end - end - describe "PUT /api/pleroma/admin/statuses/:id" do setup %{conn: conn} do admin = insert(:user, is_admin: true) @@ -3082,6 +3028,77 @@ test "it resend emails for two users", %{admin: admin} do }" end end + + describe "POST /reports/:id/notes" do + setup do + admin = insert(:user, is_admin: true) + [reporter, target_user] = insert_pair(:user) + activity = insert(:note_activity, user: target_user) + + {:ok, %{id: report_id}} = + CommonAPI.report(reporter, %{ + "account_id" => target_user.id, + "comment" => "I feel offended", + "status_ids" => [activity.id] + }) + + build_conn() + |> assign(:user, admin) + |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ + content: "this is disgusting!" + }) + + build_conn() + |> assign(:user, admin) + |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ + content: "this is disgusting2!" + }) + + %{ + admin_id: admin.id, + report_id: report_id, + admin: admin + } + end + + test "it creates report note", %{admin_id: admin_id, report_id: report_id} do + [note, _] = Repo.all(ReportNote) + + assert %{ + activity_id: ^report_id, + content: "this is disgusting!", + user_id: ^admin_id + } = note + end + + test "it returns reports with notes", %{admin: admin} do + conn = + build_conn() + |> assign(:user, admin) + |> get("/api/pleroma/admin/reports") + + response = json_response(conn, 200) + notes = hd(response["reports"])["notes"] + [note, _] = notes + + assert note["user"]["nickname"] == admin.nickname + assert note["content"] == "this is disgusting!" + assert note["created_at"] + assert response["total"] == 1 + end + + test "it deletes the note", %{admin: admin, report_id: report_id} do + assert ReportNote |> Repo.all() |> length() == 2 + + [note, _] = Repo.all(ReportNote) + + build_conn() + |> assign(:user, admin) + |> delete("/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}") + + assert ReportNote |> Repo.all() |> length() == 1 + end + end end # Needed for testing diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs index ef4a806e4..a0c6eab3c 100644 --- a/test/web/admin_api/views/report_view_test.exs +++ b/test/web/admin_api/views/report_view_test.exs @@ -30,6 +30,7 @@ test "renders a report" do Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user}) ), statuses: [], + notes: [], state: "open", id: activity.id } @@ -65,6 +66,7 @@ test "includes reported statuses" do ), statuses: [StatusView.render("show.json", %{activity: activity})], state: "open", + notes: [], id: report_activity.id } diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index beb995cd8..901f2ae41 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -567,33 +567,41 @@ test "with existing authentication and OOB `redirect_uri`, redirects to app with end describe "POST /oauth/authorize" do - test "redirects with oauth authorization" do - user = insert(:user) - app = insert(:oauth_app, scopes: ["read", "write", "follow"]) + test "redirects with oauth authorization, " <> + "keeping only non-admin scopes for non-admin user" do + app = insert(:oauth_app, scopes: ["read", "write", "admin"]) redirect_uri = OAuthController.default_redirect_uri(app) - conn = - build_conn() - |> post("/oauth/authorize", %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "test", - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "scope" => "read:subscope write", - "state" => "statepassed" - } - }) + non_admin = insert(:user, is_admin: false) + admin = insert(:user, is_admin: true) - target = redirected_to(conn) - assert target =~ redirect_uri + for {user, expected_scopes} <- %{ + non_admin => ["read:subscope", "write"], + admin => ["read:subscope", "write", "admin"] + } do + conn = + build_conn() + |> post("/oauth/authorize", %{ + "authorization" => %{ + "name" => user.nickname, + "password" => "test", + "client_id" => app.client_id, + "redirect_uri" => redirect_uri, + "scope" => "read:subscope write admin", + "state" => "statepassed" + } + }) - query = URI.parse(target).query |> URI.query_decoder() |> Map.new() + target = redirected_to(conn) + assert target =~ redirect_uri - assert %{"state" => "statepassed", "code" => code} = query - auth = Repo.get_by(Authorization, token: code) - assert auth - assert auth.scopes == ["read:subscope", "write"] + query = URI.parse(target).query |> URI.query_decoder() |> Map.new() + + assert %{"state" => "statepassed", "code" => code} = query + auth = Repo.get_by(Authorization, token: code) + assert auth + assert auth.scopes == expected_scopes + end end test "returns 401 for wrong credentials", %{conn: conn} do @@ -623,31 +631,34 @@ test "returns 401 for wrong credentials", %{conn: conn} do assert result =~ "Invalid Username/Password" end - test "returns 401 for missing scopes", %{conn: conn} do - user = insert(:user) - app = insert(:oauth_app) + test "returns 401 for missing scopes " <> + "(including all admin-only scopes for non-admin user)" do + user = insert(:user, is_admin: false) + app = insert(:oauth_app, scopes: ["read", "write", "admin"]) redirect_uri = OAuthController.default_redirect_uri(app) - result = - conn - |> post("/oauth/authorize", %{ - "authorization" => %{ - "name" => user.nickname, - "password" => "test", - "client_id" => app.client_id, - "redirect_uri" => redirect_uri, - "state" => "statepassed", - "scope" => "" - } - }) - |> html_response(:unauthorized) + for scope_param <- ["", "admin:read admin:write"] do + result = + build_conn() + |> post("/oauth/authorize", %{ + "authorization" => %{ + "name" => user.nickname, + "password" => "test", + "client_id" => app.client_id, + "redirect_uri" => redirect_uri, + "state" => "statepassed", + "scope" => scope_param + } + }) + |> html_response(:unauthorized) - # Keep the details - assert result =~ app.client_id - assert result =~ redirect_uri + # Keep the details + assert result =~ app.client_id + assert result =~ redirect_uri - # Error message - assert result =~ "This action is outside the authorized scopes" + # Error message + assert result =~ "This action is outside the authorized scopes" + end end test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index 8911c46b1..7166d6f0b 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -16,6 +16,10 @@ defmodule Pleroma.Web.StreamerTest do alias Pleroma.Web.Streamer.Worker @moduletag needs_streamer: true, capture_log: true + + @streamer_timeout 150 + @streamer_start_wait 10 + clear_config_all([:instance, :skip_thread_containment]) describe "user streams" do @@ -28,7 +32,7 @@ defmodule Pleroma.Web.StreamerTest do test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do task = Task.async(fn -> - assert_receive {:text, _}, 4_000 + assert_receive {:text, _}, @streamer_timeout end) Streamer.add_socket( @@ -43,7 +47,7 @@ test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do task = Task.async(fn -> - assert_receive {:text, _}, 4_000 + assert_receive {:text, _}, @streamer_timeout end) Streamer.add_socket( @@ -61,7 +65,7 @@ test "it doesn't send notify to the 'user:notification' stream when a user is bl blocked = insert(:user) {:ok, _user_relationship} = User.block(user, blocked) - task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) + task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end) Streamer.add_socket( "user:notification", @@ -79,7 +83,7 @@ test "it doesn't send notify to the 'user:notification' stream when a thread is user: user } do user2 = insert(:user) - task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) + task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end) Streamer.add_socket( "user:notification", @@ -97,7 +101,7 @@ test "it doesn't send notify to the 'user:notification' stream' when a domain is user: user } do user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"}) - task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) + task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end) Streamer.add_socket( "user:notification", @@ -116,7 +120,9 @@ test "it sends follow activities to the 'user:notification' stream", %{ user: user } do user2 = insert(:user) - task = Task.async(fn -> assert_receive {:text, _}, 4_000 end) + task = Task.async(fn -> assert_receive {:text, _}, @streamer_timeout end) + + Process.sleep(@streamer_start_wait) Streamer.add_socket( "user:notification", @@ -137,7 +143,7 @@ test "it sends to public" do task = Task.async(fn -> - assert_receive {:text, _}, 4_000 + assert_receive {:text, _}, @streamer_timeout end) fake_socket = %StreamerSocket{ @@ -164,7 +170,7 @@ test "it sends to public" do } |> Jason.encode!() - assert_receive {:text, received_event}, 4_000 + assert_receive {:text, received_event}, @streamer_timeout assert received_event == expected_event end) @@ -458,9 +464,7 @@ test "it doesn't send posts from muted threads" do {:ok, activity} = CommonAPI.add_mute(user2, activity) - task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) - - Process.sleep(4000) + task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end) Streamer.add_socket( "user", @@ -482,7 +486,7 @@ test "it sends conversation update to the 'direct' stream", %{} do task = Task.async(fn -> - assert_receive {:text, received_event}, 4_000 + assert_receive {:text, received_event}, @streamer_timeout assert %{"event" => "conversation", "payload" => received_payload} = Jason.decode!(received_event) @@ -518,13 +522,13 @@ test "it doesn't send conversation update to the 'direct' stream when the last m task = Task.async(fn -> - assert_receive {:text, received_event}, 4_000 + assert_receive {:text, received_event}, @streamer_timeout assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event) - refute_receive {:text, _}, 4_000 + refute_receive {:text, _}, @streamer_timeout end) - Process.sleep(1000) + Process.sleep(@streamer_start_wait) Streamer.add_socket( "direct", @@ -555,10 +559,10 @@ test "it sends conversation update to the 'direct' stream when a message is dele task = Task.async(fn -> - assert_receive {:text, received_event}, 4_000 + assert_receive {:text, received_event}, @streamer_timeout assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event) - assert_receive {:text, received_event}, 4_000 + assert_receive {:text, received_event}, @streamer_timeout assert %{"event" => "conversation", "payload" => received_payload} = Jason.decode!(received_event) @@ -567,7 +571,7 @@ test "it sends conversation update to the 'direct' stream when a message is dele assert last_status["id"] == to_string(create_activity.id) end) - Process.sleep(1000) + Process.sleep(@streamer_start_wait) Streamer.add_socket( "direct", diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 734cd2211..43299e147 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -898,8 +898,6 @@ test "with credentials and valid password", %{conn: conn, user: current_user} do |> post("/api/pleroma/delete_account", %{"password" => "test"}) assert json_response(conn, 200) == %{"status" => "success"} - # Wait a second for the started task to end - :timer.sleep(1000) end end end