diff options
| author | marcin mikołajczak <git@mkljczk.pl> | 2021-12-25 00:52:02 +0100 | 
|---|---|---|
| committer | marcin mikołajczak <git@mkljczk.pl> | 2021-12-25 00:52:02 +0100 | 
| commit | 9775955974171c19e2dd9e6930e96e33f25cb4db (patch) | |
| tree | 498b0572f6edb8d09acb471b6b557de6ca9bc638 /lib | |
| parent | cd5fb84b76a51fe6c7b5d672298a87c34737c303 (diff) | |
| parent | 1fa616638b8823a6cc0d67d0354cc179da5943f8 (diff) | |
| download | pleroma-9775955974171c19e2dd9e6930e96e33f25cb4db.tar.gz pleroma-9775955974171c19e2dd9e6930e96e33f25cb4db.zip  | |
Merge remote-tracking branch 'origin/develop' into remote-follow-api
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
Diffstat (limited to 'lib')
28 files changed, 451 insertions, 69 deletions
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index da27a99d0..d98cb8e37 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -199,6 +199,7 @@ defmodule Mix.Tasks.Pleroma.Instance do        secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)        jwt_secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)        signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8) +      lv_signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)        {web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1)        template_dir = Application.app_dir(:pleroma, "priv") <> "/templates" @@ -217,6 +218,7 @@ defmodule Mix.Tasks.Pleroma.Instance do            secret: secret,            jwt_secret: jwt_secret,            signing_salt: signing_salt, +          lv_signing_salt: lv_signing_salt,            web_push_public_key: Base.url_encode64(web_push_public_key, padding: false),            web_push_private_key: Base.url_encode64(web_push_private_key, padding: false),            db_configurable?: db_configurable?, diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index b88f74f47..4106feef6 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -362,11 +362,9 @@ defmodule Pleroma.Activity do    end    def restrict_deactivated_users(query) do -    deactivated_users = -      from(u in User.Query.build(%{deactivated: true}), select: u.ap_id) -      |> Repo.all() +    deactivated_users_query = from(u in User.Query.build(%{deactivated: true}), select: u.ap_id) -    Activity.Queries.exclude_authors(query, deactivated_users) +    from(activity in query, where: activity.actor not in subquery(deactivated_users_query))    end    defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search diff --git a/lib/pleroma/ecto_enums.ex b/lib/pleroma/ecto_enums.ex index 2a9addabc..0e3e1e5de 100644 --- a/lib/pleroma/ecto_enums.ex +++ b/lib/pleroma/ecto_enums.ex @@ -9,7 +9,8 @@ defenum(Pleroma.UserRelationship.Type,    mute: 2,    reblog_mute: 3,    notification_mute: 4, -  inverse_subscription: 5 +  inverse_subscription: 5, +  suggestion_dismiss: 6  )  defenum(Pleroma.FollowingRelationship.State, diff --git a/lib/pleroma/emoji/loader.ex b/lib/pleroma/emoji/loader.ex index 95937a892..abc95d902 100644 --- a/lib/pleroma/emoji/loader.ex +++ b/lib/pleroma/emoji/loader.ex @@ -103,6 +103,7 @@ defmodule Pleroma.Emoji.Loader do      pack_file = Path.join(pack_dir, "pack.json")      if File.exists?(pack_file) do +      Logger.info("Loading emoji pack from JSON: #{pack_file}")        contents = Jason.decode!(File.read!(pack_file))        contents["files"] @@ -115,6 +116,7 @@ defmodule Pleroma.Emoji.Loader do        emoji_txt = Path.join(pack_dir, "emoji.txt")        if File.exists?(emoji_txt) do +        Logger.info("Loading emoji pack from emoji.txt: #{emoji_txt}")          load_from_file(emoji_txt, emoji_groups)        else          extensions = Config.get([:emoji, :pack_extensions]) diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 993cff09b..adb51d33a 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -341,6 +341,26 @@ defmodule Pleroma.ModerationLog do    def get_log_entry_message(%ModerationLog{          data: %{            "actor" => %{"nickname" => actor_nickname}, +          "action" => "add_suggestion", +          "subject" => users +        } +      }) do +    "@#{actor_nickname} added suggested users: #{users_to_nicknames_string(users)}" +  end + +  def get_log_entry_message(%ModerationLog{ +        data: %{ +          "actor" => %{"nickname" => actor_nickname}, +          "action" => "remove_suggestion", +          "subject" => users +        } +      }) do +    "@#{actor_nickname} removed suggested users: #{users_to_nicknames_string(users)}" +  end + +  def get_log_entry_message(%ModerationLog{ +        data: %{ +          "actor" => %{"nickname" => actor_nickname},            "nicknames" => nicknames,            "tags" => tags,            "action" => "tag" diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3b4e49176..c25023dc1 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -148,6 +148,7 @@ defmodule Pleroma.User do      field(:last_active_at, :naive_datetime)      field(:disclose_client, :boolean, default: true)      field(:pinned_objects, :map, default: %{}) +    field(:is_suggested, :boolean, default: false)      embeds_one(        :notification_settings, @@ -1676,6 +1677,22 @@ defmodule Pleroma.User do    def confirm(%User{} = user), do: {:ok, user} +  def set_suggestion(users, is_suggested) when is_list(users) do +    Repo.transaction(fn -> +      Enum.map(users, fn user -> +        with {:ok, user} <- set_suggestion(user, is_suggested), do: user +      end) +    end) +  end + +  def set_suggestion(%User{is_suggested: is_suggested} = user, is_suggested), do: {:ok, user} + +  def set_suggestion(%User{} = user, is_suggested) when is_boolean(is_suggested) do +    user +    |> change(is_suggested: is_suggested) +    |> update_and_set_cache() +  end +    def update_notification_settings(%User{} = user, settings) do      user      |> cast(%{notification_settings: settings}, []) @@ -2474,8 +2491,8 @@ defmodule Pleroma.User do      |> update_and_set_cache()    end -  def active_user_count(weeks \\ 4) do -    active_after = Timex.shift(NaiveDateTime.utc_now(), weeks: -weeks) +  def active_user_count(days \\ 30) do +    active_after = Timex.shift(NaiveDateTime.utc_now(), days: -days)      __MODULE__      |> where([u], u.last_active_at >= ^active_after) diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index ac807fc79..6d4a4ead6 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -46,6 +46,7 @@ defmodule Pleroma.User.Query do              unconfirmed: boolean(),              is_admin: boolean(),              is_moderator: boolean(), +            is_suggested: boolean(),              super_users: boolean(),              invisible: boolean(),              internal: boolean(), @@ -167,6 +168,10 @@ defmodule Pleroma.User.Query do      where(query, [u], u.is_confirmed == false)    end +  defp compose_query({:is_suggested, bool}, query) do +    where(query, [u], u.is_suggested == ^bool) +  end +    defp compose_query({:followers, %User{id: id}}, query) do      query      |> where([u], u.id != ^id) diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex index 837787b9f..59fef42d6 100644 --- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex @@ -68,12 +68,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do      end    end -  defp handle_href(href, mediaType) do +  defp handle_href(href, mediaType, data) do      [        %{          "href" => href,          "type" => "Link", -        "mediaType" => mediaType +        "mediaType" => mediaType, +        "width" => data["width"], +        "height" => data["height"]        }      ]    end @@ -81,10 +83,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do    defp fix_url(data) do      cond do        is_binary(data["url"]) -> -        Map.put(data, "url", handle_href(data["url"], data["mediaType"])) +        Map.put(data, "url", handle_href(data["url"], data["mediaType"], data))        is_binary(data["href"]) and data["url"] == nil -> -        Map.put(data, "url", handle_href(data["href"], data["mediaType"])) +        Map.put(data, "url", handle_href(data["href"], data["mediaType"], data))        true ->          data diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 4f29a4411..ed99079e2 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -63,18 +63,17 @@ defmodule Pleroma.Web.ActivityPub.Publisher do          date: date        }) -    with {:ok, %{status: code}} when code in 200..299 <- -           result = -             HTTP.post( -               inbox, -               json, -               [ -                 {"Content-Type", "application/activity+json"}, -                 {"Date", date}, -                 {"signature", signature}, -                 {"digest", digest} -               ] -             ) do +    with {:ok, %{status: code}} = result when code in 200..299 <- +           HTTP.post( +             inbox, +             json, +             [ +               {"Content-Type", "application/activity+json"}, +               {"Date", date}, +               {"signature", signature}, +               {"digest", digest} +             ] +           ) do        if not Map.has_key?(params, :unreachable_since) || params[:unreachable_since] do          Instances.set_reachable(inbox)        end diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 701181a14..d55a4b340 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -200,7 +200,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do        {:ok, notifications} = Notification.create_notifications(activity, do_send: false)        {:ok, _user} = ActivityPub.increase_note_count_if_public(user, object) -      if in_reply_to = object.data["inReplyTo"] && object.data["type"] != "Answer" do +      if in_reply_to = object.data["type"] != "Answer" && object.data["inReplyTo"] do          Object.increase_replies_count(in_reply_to)        end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 1df53f79a..c1f6b2b49 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -446,7 +446,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do      |> Activity.Queries.by_type()      |> Activity.Queries.by_actor(actor)      |> Activity.Queries.by_object_id(object) -    |> where(fragment("data->>'state' = 'pending'")) +    |> where(fragment("data->>'state' = 'pending'") or fragment("data->>'state' = 'accept'"))      |> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)])      |> Repo.update_all([]) diff --git a/lib/pleroma/web/admin_api/controllers/user_controller.ex b/lib/pleroma/web/admin_api/controllers/user_controller.ex index 637a0e702..50208a8b7 100644 --- a/lib/pleroma/web/admin_api/controllers/user_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/user_controller.ex @@ -35,7 +35,9 @@ defmodule Pleroma.Web.AdminAPI.UserController do             :toggle_activation,             :activate,             :deactivate, -           :approve +           :approve, +           :suggest, +           :unsuggest           ]    ) @@ -239,6 +241,32 @@ defmodule Pleroma.Web.AdminAPI.UserController do      render(conn, "index.json", users: updated_users)    end +  def suggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do +    users = Enum.map(nicknames, &User.get_cached_by_nickname/1) +    {:ok, updated_users} = User.set_suggestion(users, true) + +    ModerationLog.insert_log(%{ +      actor: admin, +      subject: users, +      action: "add_suggestion" +    }) + +    render(conn, "index.json", users: updated_users) +  end + +  def unsuggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do +    users = Enum.map(nicknames, &User.get_cached_by_nickname/1) +    {:ok, updated_users} = User.set_suggestion(users, false) + +    ModerationLog.insert_log(%{ +      actor: admin, +      subject: users, +      action: "remove_suggestion" +    }) + +    render(conn, "index.json", users: updated_users) +  end +    def index(conn, params) do      {page, page_size} = page_params(params)      filters = maybe_parse_filters(params[:filters]) diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index fae0c07f0..2f1f7e627 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -80,6 +80,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do        "tags" => user.tags || [],        "is_confirmed" => user.is_confirmed,        "is_approved" => user.is_approved, +      "is_suggested" => user.is_suggested,        "url" => user.uri || user.ap_id,        "registration_reason" => user.registration_reason,        "actor_type" => user.actor_type, diff --git a/lib/pleroma/web/api_spec/operations/admin/user_operation.ex b/lib/pleroma/web/api_spec/operations/admin/user_operation.ex index c9d0bfd7c..57fb1ad65 100644 --- a/lib/pleroma/web/api_spec/operations/admin/user_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/user_operation.ex @@ -216,7 +216,71 @@ defmodule Pleroma.Web.ApiSpec.Admin.UserOperation do          request_body(            "Parameters",            %Schema{ -            description: "POST body for deleting multiple users", +            description: "POST body for approving multiple users", +            type: :object, +            properties: %{ +              nicknames: %Schema{ +                type: :array, +                items: %Schema{type: :string} +              } +            } +          } +        ), +      responses: %{ +        200 => +          Operation.response("Response", "application/json", %Schema{ +            type: :object, +            properties: %{user: %Schema{type: :array, items: user()}} +          }), +        403 => Operation.response("Forbidden", "application/json", ApiError) +      } +    } +  end + +  def suggest_operation do +    %Operation{ +      tags: ["User administration"], +      summary: "Suggest multiple users", +      operationId: "AdminAPI.UserController.suggest", +      security: [%{"oAuth" => ["admin:write:accounts"]}], +      parameters: admin_api_params(), +      requestBody: +        request_body( +          "Parameters", +          %Schema{ +            description: "POST body for adding multiple suggested users", +            type: :object, +            properties: %{ +              nicknames: %Schema{ +                type: :array, +                items: %Schema{type: :string} +              } +            } +          } +        ), +      responses: %{ +        200 => +          Operation.response("Response", "application/json", %Schema{ +            type: :object, +            properties: %{user: %Schema{type: :array, items: user()}} +          }), +        403 => Operation.response("Forbidden", "application/json", ApiError) +      } +    } +  end + +  def unsuggest_operation do +    %Operation{ +      tags: ["User administration"], +      summary: "Unsuggest multiple users", +      operationId: "AdminAPI.UserController.unsuggest", +      security: [%{"oAuth" => ["admin:write:accounts"]}], +      parameters: admin_api_params(), +      requestBody: +        request_body( +          "Parameters", +          %Schema{ +            description: "POST body for removing multiple suggested users",              type: :object,              properties: %{                nicknames: %Schema{ diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index 1a2dbb166..2a701066d 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -191,6 +191,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do        parameters: [          Operation.parameter(:password, :query, :string, "Password")        ], +      requestBody: request_body("Parameters", delete_account_request(), required: false),        responses: %{          200 =>            Operation.response("Success", "application/json", %Schema{ @@ -263,4 +264,22 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do        }      }    end + +  defp delete_account_request do +    %Schema{ +      title: "AccountDeleteRequest", +      description: "POST body for deleting one's own account", +      type: :object, +      properties: %{ +        password: %Schema{ +          type: :string, +          description: "The user's own password for confirmation.", +          format: :password +        } +      }, +      example: %{ +        "password" => "prettyp0ony1313" +      } +    } +  end  end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 8e274de88..75484fac5 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.Endpoint do    alias Pleroma.Config    socket("/socket", Pleroma.Web.UserSocket) +  socket("/live", Phoenix.LiveView.Socket)    plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint]) diff --git a/lib/pleroma/web/manifest_controller.ex b/lib/pleroma/web/manifest_controller.ex new file mode 100644 index 000000000..52589540b --- /dev/null +++ b/lib/pleroma/web/manifest_controller.ex @@ -0,0 +1,14 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ManifestController do +  use Pleroma.Web, :controller + +  plug(:skip_auth when action == :show) + +  @doc "GET /manifest.json" +  def show(conn, _params) do +    render(conn, "manifest.json") +  end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 64b177eb3..1459fc492 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -17,6 +17,8 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do    require Logger +  @search_limit 40 +    plug(Pleroma.Web.ApiSpec.CastAndValidate)    # Note: Mastodon doesn't allow unauthenticated access (requires read:accounts / read:search) @@ -77,7 +79,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do      [        resolve: params[:resolve],        following: params[:following], -      limit: params[:limit], +      limit: min(params[:limit], @search_limit),        offset: params[:offset],        type: params[:type],        author: get_author(params), diff --git a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex index 01e122dd9..e913fcf4b 100644 --- a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex @@ -4,11 +4,16 @@  defmodule Pleroma.Web.MastodonAPI.SuggestionController do    use Pleroma.Web, :controller +  import Ecto.Query +  alias Pleroma.FollowingRelationship +  alias Pleroma.User +  alias Pleroma.UserRelationship    require Logger    plug(Pleroma.Web.ApiSpec.CastAndValidate) -  plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read"]} when action == :index) +  plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read"]} when action in [:index, :index2]) +  plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["write"]} when action in [:dismiss])    def open_api_operation(action) do      operation = String.to_existing_atom("#{action}_operation") @@ -26,7 +31,90 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionController do      }    end +  def index2_operation do +    %OpenApiSpex.Operation{ +      tags: ["Suggestions"], +      summary: "Follow suggestions", +      operationId: "SuggestionController.index2", +      responses: %{ +        200 => Pleroma.Web.ApiSpec.Helpers.empty_array_response() +      } +    } +  end + +  def dismiss_operation do +    %OpenApiSpex.Operation{ +      tags: ["Suggestions"], +      summary: "Remove a suggestion", +      operationId: "SuggestionController.dismiss", +      parameters: [ +        OpenApiSpex.Operation.parameter( +          :account_id, +          :path, +          %OpenApiSpex.Schema{type: :string}, +          "Account to dismiss", +          required: true +        ) +      ], +      responses: %{ +        200 => Pleroma.Web.ApiSpec.Helpers.empty_object_response() +      } +    } +  end +    @doc "GET /api/v1/suggestions"    def index(conn, params),      do: Pleroma.Web.MastodonAPI.MastodonAPIController.empty_array(conn, params) + +  @doc "GET /api/v2/suggestions" +  def index2(%{assigns: %{user: user}} = conn, params) do +    limit = Map.get(params, :limit, 40) |> min(80) + +    users = +      %{is_suggested: true, invisible: false, limit: limit} +      |> User.Query.build() +      |> exclude_user(user) +      |> exclude_relationships(user, [:block, :mute, :suggestion_dismiss]) +      |> exclude_following(user) +      |> Pleroma.Repo.all() + +    render(conn, "index.json", %{ +      users: users, +      source: :staff, +      for: user, +      skip_visibility_check: true +    }) +  end + +  defp exclude_user(query, %User{id: user_id}) do +    where(query, [u], u.id != ^user_id) +  end + +  defp exclude_relationships(query, %User{id: user_id}, relationship_types) do +    query +    |> join(:left, [u], r in UserRelationship, +      as: :user_relationships, +      on: +        r.target_id == u.id and r.source_id == ^user_id and +          r.relationship_type in ^relationship_types +    ) +    |> where([user_relationships: r], is_nil(r.target_id)) +  end + +  defp exclude_following(query, %User{id: user_id}) do +    query +    |> join(:left, [u], r in FollowingRelationship, +      as: :following_relationships, +      on: r.following_id == u.id and r.follower_id == ^user_id and r.state == :follow_accept +    ) +    |> where([following_relationships: r], is_nil(r.following_id)) +  end + +  @doc "DELETE /api/v1/suggestions/:account_id" +  def dismiss(%{assigns: %{user: source}} = conn, %{account_id: user_id}) do +    with %User{} = target <- User.get_cached_by_id(user_id), +         {:ok, _} <- UserRelationship.create(:suggestion_dismiss, source, target) do +      json(conn, %{}) +    end +  end  end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 9e9de33f6..6114e12b1 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -269,6 +269,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do          ap_id: user.ap_id,          also_known_as: user.also_known_as,          is_confirmed: user.is_confirmed, +        is_suggested: user.is_suggested,          tags: user.tags,          hide_followers_count: user.hide_followers_count,          hide_follows_count: user.hide_follows_count, diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index ef208062b..ec7d150a9 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -59,6 +59,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do        "mastodon_api",        "mastodon_api_streaming",        "polls", +      "v2_suggestions",        "pleroma_explicit_addressing",        "shareable_emoji_packs",        "multifetch", @@ -83,7 +84,10 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do          "safe_dm_mentions"        end,        "pleroma_emoji_reactions", -      "pleroma_chat_messages" +      "pleroma_chat_messages", +      if Config.get([:instance, :show_reactions]) do +        "exposable_reactions" +      end      ]      |> Enum.filter(& &1)    end diff --git a/lib/pleroma/web/mastodon_api/views/suggestion_view.ex b/lib/pleroma/web/mastodon_api/views/suggestion_view.ex new file mode 100644 index 000000000..865229a88 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/suggestion_view.ex @@ -0,0 +1,28 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.SuggestionView do +  use Pleroma.Web, :view +  alias Pleroma.Web.MastodonAPI.AccountView + +  @source_types [:staff, :global, :past_interactions] + +  def render("index.json", %{users: users} = opts) do +    Enum.map(users, fn user -> +      opts = +        opts +        |> Map.put(:user, user) +        |> Map.delete(:users) + +      render("show.json", opts) +    end) +  end + +  def render("show.json", %{source: source, user: _user} = opts) when source in @source_types do +    %{ +      source: source, +      account: AccountView.render("show.json", opts) +    } +  end +end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex index 6a0112d2a..3781781c8 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex @@ -35,7 +35,9 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo do        openRegistrations: Config.get([:instance, :registrations_open]),        usage: %{          users: %{ -          total: Map.get(stats, :user_count, 0) +          total: Map.get(stats, :user_count, 0), +          activeMonth: Pleroma.User.active_user_count(30), +          activeHalfyear: Pleroma.User.active_user_count(180)          },          localPosts: Map.get(stats, :status_count, 0)        }, diff --git a/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex b/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex index dcd54b1af..669d50132 100644 --- a/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex @@ -151,7 +151,9 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do        index_query(user, params)        |> Pagination.fetch_paginated(params) -    render(conn, "index.json", chats: chats) +    conn +    |> add_link_headers(chats) +    |> render("index.json", chats: chats)    end    defp index_query(%{id: user_id} = user, params) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f8bafd3c2..965cd507f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -4,6 +4,7 @@  defmodule Pleroma.Web.Router do    use Pleroma.Web, :router +  import Phoenix.LiveDashboard.Router    pipeline :accepts_html do      plug(:accepts, ["html"]) @@ -158,12 +159,11 @@ defmodule Pleroma.Web.Router do      post("/uploader_callback/:upload_path", UploaderController, :callback)    end +  # AdminAPI: only admins can perform these actions    scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do      pipe_through([:admin_api, :require_admin])      put("/users/disable_mfa", AdminAPIController, :disable_mfa) -    put("/users/tag", AdminAPIController, :tag_users) -    delete("/users/tag", AdminAPIController, :untag_users)      get("/users/:nickname/permission_group", AdminAPIController, :right_get)      get("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_get) @@ -186,16 +186,61 @@ defmodule Pleroma.Web.Router do      post("/users/follow", UserController, :follow)      post("/users/unfollow", UserController, :unfollow) -    delete("/users", UserController, :delete)      post("/users", UserController, :create) + +    patch("/users/suggest", UserController, :suggest) +    patch("/users/unsuggest", UserController, :unsuggest) + +    get("/relay", RelayController, :index) +    post("/relay", RelayController, :follow) +    delete("/relay", RelayController, :unfollow) + +    get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) +    patch("/users/force_password_reset", AdminAPIController, :force_password_reset) +    get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials) +    patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) + +    get("/instance_document/:name", InstanceDocumentController, :show) +    patch("/instance_document/:name", InstanceDocumentController, :update) +    delete("/instance_document/:name", InstanceDocumentController, :delete) + +    patch("/users/confirm_email", AdminAPIController, :confirm_email) +    patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) + +    get("/config", ConfigController, :show) +    post("/config", ConfigController, :update) +    get("/config/descriptions", ConfigController, :descriptions) +    get("/need_reboot", AdminAPIController, :need_reboot) +    get("/restart", AdminAPIController, :restart) + +    get("/oauth_app", OAuthAppController, :index) +    post("/oauth_app", OAuthAppController, :create) +    patch("/oauth_app/:id", OAuthAppController, :update) +    delete("/oauth_app/:id", OAuthAppController, :delete) + +    get("/media_proxy_caches", MediaProxyCacheController, :index) +    post("/media_proxy_caches/delete", MediaProxyCacheController, :delete) +    post("/media_proxy_caches/purge", MediaProxyCacheController, :purge) + +    get("/frontends", FrontendController, :index) +    post("/frontends/install", FrontendController, :install) + +    post("/backups", AdminAPIController, :create_backup) +  end + +  # AdminAPI: admins and mods (staff) can perform these actions +  scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do +    pipe_through(:admin_api) + +    put("/users/tag", AdminAPIController, :tag_users) +    delete("/users/tag", AdminAPIController, :untag_users) +      patch("/users/:nickname/toggle_activation", UserController, :toggle_activation)      patch("/users/activate", UserController, :activate)      patch("/users/deactivate", UserController, :deactivate)      patch("/users/approve", UserController, :approve) -    get("/relay", RelayController, :index) -    post("/relay", RelayController, :follow) -    delete("/relay", RelayController, :unfollow) +    delete("/users", UserController, :delete)      post("/users/invite_token", InviteController, :create)      get("/users/invites", InviteController, :index) @@ -215,13 +260,6 @@ defmodule Pleroma.Web.Router do      get("/instances/:instance/statuses", InstanceController, :list_statuses)      delete("/instances/:instance", InstanceController, :delete) -    get("/instance_document/:name", InstanceDocumentController, :show) -    patch("/instance_document/:name", InstanceDocumentController, :update) -    delete("/instance_document/:name", InstanceDocumentController, :delete) - -    patch("/users/confirm_email", AdminAPIController, :confirm_email) -    patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) -      get("/reports", ReportController, :index)      get("/reports/:id", ReportController, :show)      patch("/reports", ReportController, :update) @@ -233,39 +271,19 @@ defmodule Pleroma.Web.Router do      delete("/statuses/:id", StatusController, :delete)      get("/statuses", StatusController, :index) -    get("/config", ConfigController, :show) -    post("/config", ConfigController, :update) -    get("/config/descriptions", ConfigController, :descriptions) -    get("/need_reboot", AdminAPIController, :need_reboot) -    get("/restart", AdminAPIController, :restart) -      get("/moderation_log", AdminAPIController, :list_log)      post("/reload_emoji", AdminAPIController, :reload_emoji)      get("/stats", AdminAPIController, :stats) -    get("/oauth_app", OAuthAppController, :index) -    post("/oauth_app", OAuthAppController, :create) -    patch("/oauth_app/:id", OAuthAppController, :update) -    delete("/oauth_app/:id", OAuthAppController, :delete) - -    get("/media_proxy_caches", MediaProxyCacheController, :index) -    post("/media_proxy_caches/delete", MediaProxyCacheController, :delete) -    post("/media_proxy_caches/purge", MediaProxyCacheController, :purge) -      get("/chats/:id", ChatController, :show)      get("/chats/:id/messages", ChatController, :messages)      delete("/chats/:id/messages/:message_id", ChatController, :delete_message) - -    get("/frontends", FrontendController, :index) -    post("/frontends/install", FrontendController, :install) - -    post("/backups", AdminAPIController, :create_backup)    end    scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do      scope "/pack" do -      pipe_through([:admin_api, :require_admin]) +      pipe_through(:admin_api)        post("/", EmojiPackController, :create)        patch("/", EmojiPackController, :update) @@ -280,7 +298,7 @@ defmodule Pleroma.Web.Router do      # Modifying packs      scope "/packs" do -      pipe_through([:admin_api, :require_admin]) +      pipe_through(:admin_api)        get("/import", EmojiPackController, :import_from_filesystem)        get("/remote", EmojiPackController, :remote) @@ -536,6 +554,7 @@ defmodule Pleroma.Web.Router do      delete("/push/subscription", SubscriptionController, :delete)      get("/suggestions", SuggestionController, :index) +    delete("/suggestions/:account_id", SuggestionController, :dismiss)      get("/timelines/home", TimelineController, :home)      get("/timelines/direct", TimelineController, :direct) @@ -587,6 +606,8 @@ defmodule Pleroma.Web.Router do      get("/search", SearchController, :search2)      post("/media", MediaController, :create2) + +    get("/suggestions", SuggestionController, :index2)    end    scope "/api", Pleroma.Web do @@ -737,6 +758,18 @@ defmodule Pleroma.Web.Router do      get("/:version", Nodeinfo.NodeinfoController, :nodeinfo)    end +  scope "/", Pleroma.Web do +    pipe_through(:api) + +    get("/manifest.json", ManifestController, :show) +  end + +  scope "/", Pleroma.Web do +    pipe_through(:pleroma_html) + +    post("/auth/password", TwitterAPI.PasswordController, :request) +  end +    scope "/proxy/", Pleroma.Web do      get("/preview/:sig/:url", MediaProxy.MediaProxyController, :preview)      get("/preview/:sig/:url/:filename", MediaProxy.MediaProxyController, :preview) @@ -752,6 +785,11 @@ defmodule Pleroma.Web.Router do      end    end +  scope "/" do +    pipe_through([:pleroma_html, :authenticate, :require_admin]) +    live_dashboard("/phoenix/live_dashboard") +  end +    # Test-only routes needed to test action dispatching and plug chain execution    if Pleroma.Config.get(:env) == :test do      @test_actions [ diff --git a/lib/pleroma/web/twitter_api/controllers/password_controller.ex b/lib/pleroma/web/twitter_api/controllers/password_controller.ex index bc04a4d49..133a588b0 100644 --- a/lib/pleroma/web/twitter_api/controllers/password_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/password_controller.ex @@ -11,9 +11,23 @@ defmodule Pleroma.Web.TwitterAPI.PasswordController do    require Logger +  import Pleroma.Web.ControllerHelper, only: [json_response: 3] +    alias Pleroma.PasswordResetToken    alias Pleroma.Repo    alias Pleroma.User +  alias Pleroma.Web.TwitterAPI.TwitterAPI + +  plug(Pleroma.Web.Plugs.RateLimiter, [name: :request] when action == :request) + +  @doc "POST /auth/password" +  def request(conn, params) do +    nickname_or_email = params["email"] || params["nickname"] + +    TwitterAPI.password_reset(nickname_or_email) + +    json_response(conn, :no_content, "") +  end    def reset(conn, %{"token" => token}) do      with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index cbcef7475..ccbef6d9f 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -132,8 +132,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do      end    end -  def delete_account(%{assigns: %{user: user}} = conn, params) do -    password = params[:password] || "" +  def delete_account(%{assigns: %{user: user}, body_params: body_params} = conn, params) do +    # This endpoint can accept a query param or JSON body for backwards-compatibility. +    # Submitting a JSON body is recommended, so passwords don't end up in server logs. +    password = body_params[:password] || params[:password] || ""      case CommonAPI.Utils.confirm_current_password(user, password) do        {:ok, user} -> diff --git a/lib/pleroma/web/views/manifest_view.ex b/lib/pleroma/web/views/manifest_view.ex new file mode 100644 index 000000000..cc78ea347 --- /dev/null +++ b/lib/pleroma/web/views/manifest_view.ex @@ -0,0 +1,28 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ManifestView do +  use Pleroma.Web, :view +  alias Pleroma.Config +  alias Pleroma.Web.Endpoint + +  def render("manifest.json", _params) do +    %{ +      name: Config.get([:instance, :name]), +      description: Config.get([:instance, :description]), +      icons: Config.get([:manifest, :icons]), +      theme_color: Config.get([:manifest, :theme_color]), +      background_color: Config.get([:manifest, :background_color]), +      display: "standalone", +      scope: Endpoint.url(), +      start_url: "/", +      categories: [ +        "social" +      ], +      serviceworker: %{ +        src: "/sw.js" +      } +    } +  end +end  | 
