diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/user.ex | 44 | ||||
| -rw-r--r-- | lib/pleroma/user/query.ex | 18 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 13 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/views/user_view.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/operations/account_operation.ex | 23 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex | 29 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/schemas/account.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 4 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 23 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/instance_view.ex | 4 | ||||
| -rw-r--r-- | lib/pleroma/web/pleroma_api/controllers/account_controller.ex | 19 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/twitter_api.ex | 1 | 
13 files changed, 181 insertions, 12 deletions
| diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index bf5b6508b..8bb4fb204 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -154,6 +154,8 @@ defmodule Pleroma.User do      field(:pinned_objects, :map, default: %{})      field(:is_suggested, :boolean, default: false)      field(:last_status_at, :naive_datetime) +    field(:birthday, :date) +    field(:hide_birthday, :boolean, default: false)      embeds_one(        :notification_settings, @@ -470,7 +472,8 @@ defmodule Pleroma.User do          :actor_type,          :also_known_as,          :accepts_chat_messages, -        :pinned_objects +        :pinned_objects, +        :birthday        ]      )      |> cast(params, [:name], empty_values: []) @@ -531,9 +534,12 @@ defmodule Pleroma.User do          :is_discoverable,          :actor_type,          :accepts_chat_messages, -        :disclose_client +        :disclose_client, +        :birthday, +        :hide_birthday        ]      ) +    |> validate_min_age()      |> unique_constraint(:nickname)      |> validate_format(:nickname, local_nickname_regex())      |> validate_length(:bio, max: bio_limit) @@ -738,7 +744,8 @@ defmodule Pleroma.User do        :password_confirmation,        :emoji,        :accepts_chat_messages, -      :registration_reason +      :registration_reason, +      :birthday      ])      |> validate_required([:name, :nickname, :password, :password_confirmation])      |> validate_confirmation(:password) @@ -760,6 +767,8 @@ defmodule Pleroma.User do      |> validate_length(:name, min: 1, max: name_limit)      |> validate_length(:registration_reason, max: reason_limit)      |> maybe_validate_required_email(opts[:external]) +    |> maybe_validate_required_birthday +    |> validate_min_age()      |> put_password_hash      |> put_ap_id()      |> unique_constraint(:ap_id) @@ -776,6 +785,26 @@ defmodule Pleroma.User do      end    end +  defp maybe_validate_required_birthday(changeset) do +    if Config.get([:instance, :birthday_required]) do +      validate_required(changeset, [:birthday]) +    else +      changeset +    end +  end + +  defp validate_min_age(changeset) do +    changeset +    |> validate_change(:birthday, fn :birthday, birthday -> +      valid? = +        Date.utc_today() +        |> Date.diff(birthday) >= +          Config.get([:instance, :birthday_min_age]) + +      if valid?, do: [], else: [birthday: "Invalid age"] +    end) +  end +    defp put_ap_id(changeset) do      ap_id = ap_id(%User{nickname: get_field(changeset, :nickname)})      put_change(changeset, :ap_id, ap_id) @@ -2559,4 +2588,13 @@ defmodule Pleroma.User do        _ -> {:error, user}      end    end + +  def get_friends_birthdays_query(%User{} = user, day, month) do +    User.Query.build(%{ +      friends: user, +      deactivated: false, +      birthday_day: day, +      birthday_month: month +    }) +  end  end diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index bf78cb32d..dddfe07bf 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -59,7 +59,9 @@ defmodule Pleroma.User.Query do              order_by: term(),              select: term(),              limit: pos_integer(), -            actor_types: [String.t()] +            actor_types: [String.t()], +            birthday_day: pos_integer(), +            birthday_month: pos_integer()            }            | map() @@ -230,6 +232,20 @@ defmodule Pleroma.User.Query do      |> where([u], not like(u.nickname, "internal.%"))    end +  defp compose_query({:birthday_day, day}, query) do +    query +    |> where([u], u.hide_birthday == false) +    |> where([u], not is_nil(u.birthday)) +    |> where([u], fragment("date_part('day', ?)", u.birthday) == ^day) +  end + +  defp compose_query({:birthday_month, month}, query) do +    query +    |> where([u], u.hide_birthday == false) +    |> where([u], not is_nil(u.birthday)) +    |> where([u], fragment("date_part('month', ?)", u.birthday) == ^month) +  end +    defp compose_query(_unsupported_param, query), do: query    defp location_query(query, local) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 9ca44c532..7551dd56d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1501,6 +1501,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do          nil        end +    birthday = +      if is_binary(data["vcard:bday"]) do +        case Date.from_iso8601(data["vcard:bday"]) do +          {:ok, date} -> date +          {:error, _} -> nil +        end +      else +        nil +      end +      user_data = %{        ap_id: data["id"],        uri: get_actor_url(data["url"]), @@ -1523,7 +1533,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do        inbox: data["inbox"],        shared_inbox: shared_inbox,        accepts_chat_messages: accepts_chat_messages, -      pinned_objects: pinned_objects +      pinned_objects: pinned_objects, +      birthday: birthday      }      # nickname can be nil because of virtual actors diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 344da19d3..8ab516214 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -92,6 +92,11 @@ defmodule Pleroma.Web.ActivityPub.UserView do          %{}        end +    birthday = +      if !user.hide_birthday, +        do: user.birthday, +        else: nil +      %{        "id" => user.ap_id,        "type" => user.actor_type, @@ -116,7 +121,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do        # Note: key name is indeed "discoverable" (not an error)        "discoverable" => user.is_discoverable,        "capabilities" => capabilities, -      "alsoKnownAs" => user.also_known_as +      "alsoKnownAs" => user.also_known_as, +      "vcard:bday" => birthday      }      |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))      |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 768d3c720..1b2bffa3e 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -543,6 +543,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do            type: :string,            nullable: true,            description: "Invite token required when the registrations aren't public" +        }, +        birthday: %Schema{ +          type: :string, +          nullable: true, +          description: "User's birthday", +          format: :date          }        },        example: %{ @@ -720,7 +726,18 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do            description:              "Discovery (listing, indexing) of this account by external services (search bots etc.) is allowed."          }, -        actor_type: ActorType +        actor_type: ActorType, +        birthday: %Schema{ +          type: :string, +          nullable: true, +          description: "User's birthday", +          format: :date +        }, +        hide_birthday: %Schema{ +          allOf: [BooleanLike], +          nullable: true, +          description: "User's birthday will be hidden" +        }        },        example: %{          bot: false, @@ -740,7 +757,9 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do          allow_following_move: false,          also_known_as: ["https://foo.bar/users/foo"],          discoverable: false, -        actor_type: "Person" +        actor_type: "Person", +        hide_birthday: true, +        birthday: "2001-02-12"        }      }    end diff --git a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex index ed0db173e..23201a4ba 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex @@ -4,6 +4,7 @@  defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do    alias OpenApiSpex.Operation +  alias OpenApiSpex.Schema    alias Pleroma.Web.ApiSpec.AccountOperation    alias Pleroma.Web.ApiSpec.Schemas.AccountRelationship    alias Pleroma.Web.ApiSpec.Schemas.ApiError @@ -112,6 +113,34 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do      }    end +  def birthdays_operation do +    %Operation{ +      tags: ["Retrieve account information"], +      summary: "Birthday reminders", +      description: "Birthday reminders about users you follow.", +      operationId: "PleromaAPI.AccountController.birthdays", +      parameters: [ +        Operation.parameter( +          :day, +          :query, +          %Schema{type: :integer}, +          "Day of users' birthdays" +        ), +        Operation.parameter( +          :month, +          :query, +          %Schema{type: :integer}, +          "Month of users' birthdays" +        ) +      ], +      security: [%{"oAuth" => ["read:accounts"]}], +      responses: %{ +        200 => +          Operation.response("Accounts", "application/json", AccountOperation.array_of_accounts()) +      } +    } +  end +    defp id_param do      Operation.parameter(:id, :path, FlakeID, "Account ID",        example: "9umDrYheeY451cQnEe", diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index 548e70544..2113f0d31 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -47,12 +47,14 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do              description: "whether the user allows automatically follow moved following accounts"            },            background_image: %Schema{type: :string, nullable: true, format: :uri}, +          birthday: %Schema{type: :string, nullable: true, format: :date},            chat_token: %Schema{type: :string},            is_confirmed: %Schema{              type: :boolean,              description:                "whether the user account is waiting on email confirmation to be activated"            }, +          hide_birthday: %Schema{type: :boolean, nullable: true},            hide_favorites: %Schema{type: :boolean},            hide_followers_count: %Schema{              type: :boolean, @@ -202,7 +204,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do          },          "settings_store" => %{            "pleroma-fe" => %{} -        } +        }, +        "birthday" => "2001-02-12"        },        "source" => %{          "fields" => [], diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index a90833bf0..60c9f7d69 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -191,7 +191,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do          :skip_thread_containment,          :allow_following_move,          :also_known_as, -        :accepts_chat_messages +        :accepts_chat_messages, +        :hide_birthday        ]        |> Enum.reduce(%{}, fn key, acc ->          Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)}) @@ -219,6 +220,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do        |> Maps.put_if_present(:is_locked, params[:locked])        # Note: param name is indeed :discoverable (not an error)        |> Maps.put_if_present(:is_discoverable, params[:discoverable]) +      |> Maps.put_if_present(:birthday, params[:birthday])      # What happens here:      # diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b964fdc54..e0137a112 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -297,7 +297,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do          skip_thread_containment: user.skip_thread_containment,          background_image: image_url(user.background) |> MediaProxy.url(),          accepts_chat_messages: user.accepts_chat_messages, -        favicon: favicon +        favicon: favicon, +        birthday: user.birthday, +        hide_birthday: user.hide_birthday        }      }      |> maybe_put_role(user, opts[:for]) @@ -311,6 +313,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do      |> maybe_put_unread_conversation_count(user, opts[:for])      |> maybe_put_unread_notification_count(user, opts[:for])      |> maybe_put_email_address(user, opts[:for]) +    |> maybe_hide_birthday(user, opts[:for])    end    defp username_from_nickname(string) when is_binary(string) do @@ -432,6 +435,24 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    defp maybe_put_email_address(data, _, _), do: data +  defp maybe_hide_birthday(data, %User{id: user_id}, %User{id: user_id}) do +    data +  end + +  defp maybe_hide_birthday(data, %User{hide_birthday: true}, _) do +    data +    |> Kernel.pop_in([:pleroma, :birthday]) +    |> elem(1) +    |> Kernel.pop_in([:pleroma, :hide_birthday]) +    |> elem(1) +  end + +  defp maybe_hide_birthday(data, _, _) do +    data +    |> Kernel.pop_in([:pleroma, :hide_birthday]) +    |> elem(1) +  end +    defp image_url(%{"url" => [%{"href" => href} | _]}), do: href    defp image_url(_), do: nil  end diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index cbed5fba9..fa6c20a30 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -46,7 +46,9 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do            federation: federation(),            fields_limits: fields_limits(),            post_formats: Config.get([:instance, :allowed_post_formats]), -          privileged_staff: Config.get([:instance, :privileged_staff]) +          privileged_staff: Config.get([:instance, :privileged_staff]), +          birthday_required: Config.get([:instance, :birthday_required]), +          birthday_min_age: Config.get([:instance, :birthday_min_age])          },          stats: %{mau: Pleroma.User.active_user_count()},          vapid_public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key) diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index 66a8d1c1c..20697fa46 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -51,6 +51,11 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do      when action == :endorsements    ) +  plug( +    OAuthScopesPlug, +    %{scopes: ["read:accounts"]} when action == :birthdays +  ) +    plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend)    plug( @@ -137,4 +142,18 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do        {:error, message} -> json_response(conn, :forbidden, %{error: message})      end    end + +  @doc "GET /api/v1/pleroma/birthday_reminders" +  def birthdays(%{assigns: %{user: %User{} = user}} = conn, %{day: day, month: month} = _params) do +    birthdays = +      User.get_friends_birthdays_query(user, day, month) +      |> Pleroma.Repo.all() + +    conn +    |> render("index.json", +      for: user, +      users: birthdays, +      as: :user +    ) +  end  end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 67c1a3e5c..2d896fdd4 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -448,6 +448,8 @@ defmodule Pleroma.Web.Router do        post("/accounts/:id/subscribe", AccountController, :subscribe)        post("/accounts/:id/unsubscribe", AccountController, :unsubscribe) + +      get("/birthday_reminders", AccountController, :birthdays)      end      post("/accounts/confirmation_resend", AccountController, :confirmation_resend) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 76ca82d20..aa4dfb145 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -20,6 +20,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do        |> Map.put(:name, Map.get(params, :fullname, params[:username]))        |> Map.put(:password_confirmation, params[:password])        |> Map.put(:registration_reason, params[:reason]) +      |> Map.put(:birthday, params[:birthday])      if Pleroma.Config.get([:instance, :registrations_open]) do        create_user(params, opts) | 
