Merge branch 'birth-dates' into 'develop'
Birth dates See merge request pleroma/pleroma!3608
This commit is contained in:
commit
dd7977bb68
|
@ -26,6 +26,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- Ability to log slow Ecto queries by configuring `:pleroma, :telemetry, :slow_queries_logging`
|
||||
- Added Phoenix LiveDashboard at `/phoenix/live_dashboard`
|
||||
- Added `/manifest.json` for progressive web apps.
|
||||
- MastoAPI: Support for `birthday` and `show_birthday` field in `/api/v1/accounts/update_credentials`.
|
||||
- Configuration: Add `birthday_required` and `birthday_min_age` settings to provide a way to require users to enter their birth date.
|
||||
- PleromaAPI: Add `GET /api/v1/pleroma/birthdays` API endpoint
|
||||
|
||||
### Fixed
|
||||
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
||||
|
|
|
@ -257,7 +257,9 @@
|
|||
password_reset_token_validity: 60 * 60 * 24,
|
||||
profile_directory: true,
|
||||
privileged_staff: false,
|
||||
max_endorsed_users: 20
|
||||
max_endorsed_users: 20,
|
||||
birthday_required: false,
|
||||
birthday_min_age: 0
|
||||
|
||||
config :pleroma, :welcome,
|
||||
direct_message: [
|
||||
|
|
|
@ -957,6 +957,17 @@
|
|||
type: :boolean,
|
||||
description:
|
||||
"Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)"
|
||||
},
|
||||
%{
|
||||
key: :birthday_required,
|
||||
type: :boolean,
|
||||
description: "Require users to enter their birthday."
|
||||
},
|
||||
%{
|
||||
key: :birthday_min_age,
|
||||
type: :integer,
|
||||
description:
|
||||
"Minimum required age for users to create account. Only used if birthday is required."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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(:show_birthday, :boolean, default: false)
|
||||
|
||||
embeds_one(
|
||||
:notification_settings,
|
||||
|
@ -470,7 +472,9 @@ def remote_user_changeset(struct \\ %User{local: false}, params) do
|
|||
:actor_type,
|
||||
:also_known_as,
|
||||
:accepts_chat_messages,
|
||||
:pinned_objects
|
||||
:pinned_objects,
|
||||
:birthday,
|
||||
:show_birthday
|
||||
]
|
||||
)
|
||||
|> cast(params, [:name], empty_values: [])
|
||||
|
@ -531,9 +535,12 @@ def update_changeset(struct, params \\ %{}) do
|
|||
:is_discoverable,
|
||||
:actor_type,
|
||||
:accepts_chat_messages,
|
||||
:disclose_client
|
||||
:disclose_client,
|
||||
:birthday,
|
||||
:show_birthday
|
||||
]
|
||||
)
|
||||
|> validate_min_age()
|
||||
|> unique_constraint(:nickname)
|
||||
|> validate_format(:nickname, local_nickname_regex())
|
||||
|> validate_length(:bio, max: bio_limit)
|
||||
|
@ -738,7 +745,8 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do
|
|||
:password_confirmation,
|
||||
:emoji,
|
||||
:accepts_chat_messages,
|
||||
:registration_reason
|
||||
:registration_reason,
|
||||
:birthday
|
||||
])
|
||||
|> validate_required([:name, :nickname, :password, :password_confirmation])
|
||||
|> validate_confirmation(:password)
|
||||
|
@ -760,6 +768,8 @@ def register_changeset(struct, params \\ %{}, opts \\ []) 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 +786,26 @@ def maybe_validate_required_email(changeset, _) 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)
|
||||
|
@ -2560,4 +2590,13 @@ def update_last_status_at(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
|
||||
|
|
|
@ -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 @@ defp compose_query({:internal, false}, query) do
|
|||
|> where([u], not like(u.nickname, "internal.%"))
|
||||
end
|
||||
|
||||
defp compose_query({:birthday_day, day}, query) do
|
||||
query
|
||||
|> where([u], u.show_birthday == true)
|
||||
|> 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.show_birthday == true)
|
||||
|> 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
|
||||
|
|
|
@ -1501,6 +1501,18 @@ defp object_to_user_data(data) 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
|
||||
|
||||
show_birthday = !!birthday
|
||||
|
||||
user_data = %{
|
||||
ap_id: data["id"],
|
||||
uri: get_actor_url(data["url"]),
|
||||
|
@ -1523,7 +1535,9 @@ defp object_to_user_data(data) do
|
|||
inbox: data["inbox"],
|
||||
shared_inbox: shared_inbox,
|
||||
accepts_chat_messages: accepts_chat_messages,
|
||||
pinned_objects: pinned_objects
|
||||
pinned_objects: pinned_objects,
|
||||
birthday: birthday,
|
||||
show_birthday: show_birthday
|
||||
}
|
||||
|
||||
# nickname can be nil because of virtual actors
|
||||
|
|
|
@ -92,6 +92,11 @@ def render("user.json", %{user: user}) do
|
|||
%{}
|
||||
end
|
||||
|
||||
birthday =
|
||||
if user.show_birthday,
|
||||
do: user.birthday,
|
||||
else: nil
|
||||
|
||||
%{
|
||||
"id" => user.ap_id,
|
||||
"type" => user.actor_type,
|
||||
|
@ -116,7 +121,8 @@ def render("user.json", %{user: user}) 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))
|
||||
|
|
|
@ -543,6 +543,12 @@ defp create_request 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 @@ defp update_credentials_request 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
|
||||
},
|
||||
show_birthday: %Schema{
|
||||
allOf: [BooleanLike],
|
||||
nullable: true,
|
||||
description: "User's birthday will be visible"
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
bot: false,
|
||||
|
@ -740,7 +757,9 @@ defp update_credentials_request do
|
|||
allow_following_move: false,
|
||||
also_known_as: ["https://foo.bar/users/foo"],
|
||||
discoverable: false,
|
||||
actor_type: "Person"
|
||||
actor_type: "Person",
|
||||
show_birthday: false,
|
||||
birthday: "2001-02-12"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -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 @@ def unsubscribe_operation 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",
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
show_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" => [],
|
||||
|
|
|
@ -191,7 +191,8 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
|
|||
:skip_thread_containment,
|
||||
:allow_following_move,
|
||||
:also_known_as,
|
||||
:accepts_chat_messages
|
||||
:accepts_chat_messages,
|
||||
:show_birthday
|
||||
]
|
||||
|> Enum.reduce(%{}, fn key, acc ->
|
||||
Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)})
|
||||
|
@ -219,6 +220,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
|
|||
|> 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:
|
||||
#
|
||||
|
|
|
@ -297,7 +297,8 @@ defp do_render("show.json", %{user: user} = opts) 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
|
||||
}
|
||||
}
|
||||
|> maybe_put_role(user, opts[:for])
|
||||
|
@ -311,6 +312,7 @@ defp do_render("show.json", %{user: user} = opts) 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_show_birthday(user, opts[:for])
|
||||
end
|
||||
|
||||
defp username_from_nickname(string) when is_binary(string) do
|
||||
|
@ -344,6 +346,7 @@ defp maybe_put_settings(
|
|||
|> Kernel.put_in([:source, :privacy], user.default_scope)
|
||||
|> Kernel.put_in([:source, :pleroma, :show_role], user.show_role)
|
||||
|> Kernel.put_in([:source, :pleroma, :no_rich_text], user.no_rich_text)
|
||||
|> Kernel.put_in([:source, :pleroma, :show_birthday], user.show_birthday)
|
||||
end
|
||||
|
||||
defp maybe_put_settings(data, _, _, _), do: data
|
||||
|
@ -432,6 +435,20 @@ defp maybe_put_email_address(data, %User{id: user_id}, %User{id: user_id} = user
|
|||
|
||||
defp maybe_put_email_address(data, _, _), do: data
|
||||
|
||||
defp maybe_show_birthday(data, %User{id: user_id} = user, %User{id: user_id}) do
|
||||
data
|
||||
|> Kernel.put_in([:pleroma, :birthday], user.birthday)
|
||||
end
|
||||
|
||||
defp maybe_show_birthday(data, %User{show_birthday: true} = user, _) do
|
||||
data
|
||||
|> Kernel.put_in([:pleroma, :birthday], user.birthday)
|
||||
end
|
||||
|
||||
defp maybe_show_birthday(data, _, _) do
|
||||
data
|
||||
end
|
||||
|
||||
defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
|
||||
defp image_url(_), do: nil
|
||||
end
|
||||
|
|
|
@ -46,7 +46,9 @@ def render("show.json", _) 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)
|
||||
|
|
|
@ -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 @@ def unsubscribe(%{assigns: %{user: user, account: subscription_target}} = conn,
|
|||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/pleroma/birthdays"
|
||||
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
|
||||
|
|
|
@ -448,6 +448,8 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
post("/accounts/:id/subscribe", AccountController, :subscribe)
|
||||
post("/accounts/:id/unsubscribe", AccountController, :unsubscribe)
|
||||
|
||||
get("/birthdays", AccountController, :birthdays)
|
||||
end
|
||||
|
||||
post("/accounts/confirmation_resend", AccountController, :confirmation_resend)
|
||||
|
|
|
@ -20,6 +20,7 @@ def register_user(params, opts \\ []) 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)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
defmodule Pleroma.Repo.Migrations.AddBirthdayToUsers do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:users) do
|
||||
add_if_not_exists(:birthday, :date)
|
||||
add_if_not_exists(:show_birthday, :boolean, default: false, null: false)
|
||||
end
|
||||
|
||||
create_if_not_exists(index(:users, [:show_birthday]))
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
defmodule Pleroma.Repo.Migrations.AddBirthdayMonthDayIndexToUsers do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create(
|
||||
index(:users, ["date_part('month', birthday)", "date_part('day', birthday)"],
|
||||
name: :users_birthday_month_day_index
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
|
@ -35,7 +35,8 @@
|
|||
"alsoKnownAs": {
|
||||
"@id": "as:alsoKnownAs",
|
||||
"@type": "@id"
|
||||
}
|
||||
},
|
||||
"vcard": "http://www.w3.org/2006/vcard/ns#"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","Hashtag":"as:Hashtag","quoteUrl":"as:quoteUrl","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji","featured":"toot:featured","discoverable":"toot:discoverable","schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value","misskey":"https://misskey.io/ns#","_misskey_content":"misskey:_misskey_content","_misskey_quote":"misskey:_misskey_quote","_misskey_reaction":"misskey:_misskey_reaction","_misskey_votes":"misskey:_misskey_votes","_misskey_talk":"misskey:_misskey_talk","isCat":"misskey:isCat","vcard":"http://www.w3.org/2006/vcard/ns#"}],"type":"Person","id":"https://misskey.io/users/8dhi2ne167","inbox":"https://misskey.io/users/8dhi2ne167/inbox","outbox":"https://misskey.io/users/8dhi2ne167/outbox","followers":"https://misskey.io/users/8dhi2ne167/followers","following":"https://misskey.io/users/8dhi2ne167/following","sharedInbox":"https://misskey.io/inbox","endpoints":{"sharedInbox":"https://misskey.io/inbox"},"url":"https://misskey.io/@mkljczk","preferredUsername":"mkljczk","name":null,"summary":null,"icon":null,"image":null,"tag":[],"manuallyApprovesFollowers":false,"discoverable":true,"publicKey":{"id":"https://misskey.io/users/8dhi2ne167#main-key","type":"Key","owner":"https://misskey.io/users/8dhi2ne167","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7CI3Ol1M0TDdLL+E8Uhd\nJ8l/RTEtxl39MKxsqSCZr9itf/EBn4dGTifK9LN3XZD2fjmX4hdwaxndp2HYVDqn\ndc6O57u8dHxFv9wTwXQrLzEonOzbrBec6WB42ZpkFHi4XEyqg8iYGu5Yy7ttXJ21\nOfWqi+eytttcTErKuu4z8MX1L1IlmpfSmH1trMyDZLFMRqVJ0416/qI0K3l3cmIf\n8cuWbJ57UxVbYxp9242der/3vrNIU24rAouYQYe1atUgFPKil3w8dCY7magy36Wg\nOXC1hdRsFcsVW54/3cSQ9fc/+1HIg16/zlS+AWb4dVDhrAUJLYIBrkMPRnu/cDuI\ndvyL+KtZUxhDBoSO0JLrd1+GZGt0WD+mfutCugJS8IGlWQmGq8WRmM2vYfZgEYkq\nCv4392VSsWvg4iluKz0eX+8l7QKHseJwGBvk89Txlz6f7QkooBXYuuyHZS1ZLZBW\nfooK+RNAquDU+cVUu1gVt1V5yt3IxF1qvMRtlElNJKN5NUJT9/K2YcVX6UoMXhDd\noSOpARqPm9E2pdjI62pAOBbCplMSoBprhoCYm0iozf9QhNyUBGWDcTsFDDgqOwy4\nYjGQ5jsnCrkhSzRkTViWD+Pgw+Ar4fxcjySGUf0x7HkNfteDPSdLMD8J2vTJXfoB\nGAQQmGMZmFgONC62FrDphlsCAwEAAQ==\n-----END PUBLIC KEY-----\n"},"isCat":true,"vcard:bday":"2001-02-12"}
|
|
@ -755,6 +755,54 @@ test "it restricts length of registration reason" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "user registration, with :birthday_required and :birthday_min_age" do
|
||||
@full_user_data %{
|
||||
bio: "A guy",
|
||||
name: "my name",
|
||||
nickname: "nick",
|
||||
password: "test",
|
||||
password_confirmation: "test",
|
||||
email: "email@example.com"
|
||||
}
|
||||
|
||||
setup do
|
||||
clear_config([:instance, :birthday_required], true)
|
||||
clear_config([:instance, :birthday_min_age], 18 * 365)
|
||||
end
|
||||
|
||||
test "it passes when correct birth date is provided" do
|
||||
today = Date.utc_today()
|
||||
birthday = Date.add(today, -19 * 365)
|
||||
|
||||
params =
|
||||
@full_user_data
|
||||
|> Map.put(:birthday, birthday)
|
||||
|
||||
changeset = User.register_changeset(%User{}, params)
|
||||
|
||||
assert changeset.valid?
|
||||
end
|
||||
|
||||
test "it fails when birth date is not provided" do
|
||||
changeset = User.register_changeset(%User{}, @full_user_data)
|
||||
|
||||
refute changeset.valid?
|
||||
end
|
||||
|
||||
test "it fails when provided invalid birth date" do
|
||||
today = Date.utc_today()
|
||||
birthday = Date.add(today, -17 * 365)
|
||||
|
||||
params =
|
||||
@full_user_data
|
||||
|> Map.put(:birthday, birthday)
|
||||
|
||||
changeset = User.register_changeset(%User{}, params)
|
||||
|
||||
refute changeset.valid?
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_or_fetch/1" do
|
||||
test "gets an existing user by nickname" do
|
||||
user = insert(:user)
|
||||
|
|
|
@ -389,6 +389,26 @@ test "fetches user featured collection without embedded object" do
|
|||
|
||||
assert %{data: %{"id" => ^object_url}} = Object.get_by_ap_id(object_url)
|
||||
end
|
||||
|
||||
test "fetches user birthday information from misskey" do
|
||||
user_id = "https://misskey.io/@mkljczk"
|
||||
|
||||
Tesla.Mock.mock(fn
|
||||
%{
|
||||
method: :get,
|
||||
url: ^user_id
|
||||
} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/birthdays/misskey-user.json"),
|
||||
headers: [{"content-type", "application/activity+json"}]
|
||||
}
|
||||
end)
|
||||
|
||||
{:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
|
||||
|
||||
assert user.birthday == ~D[2001-02-12]
|
||||
end
|
||||
end
|
||||
|
||||
test "it fetches the appropriate tag-restricted posts" do
|
||||
|
|
|
@ -1608,6 +1608,60 @@ test "returns an error if captcha is invalid", %{conn: conn} do
|
|||
end
|
||||
end
|
||||
|
||||
describe "create account with required birth date" do
|
||||
setup %{conn: conn} do
|
||||
clear_config([:instance, :birthday_required], true)
|
||||
clear_config([:instance, :birthday_min_age], 18 * 365)
|
||||
|
||||
app_token = insert(:oauth_token, user: nil)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("authorization", "Bearer " <> app_token.token)
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|
||||
[conn: conn]
|
||||
end
|
||||
|
||||
test "creates an account if provided valid birth date", %{conn: conn} do
|
||||
birthday =
|
||||
Date.utc_today()
|
||||
|> Date.add(-19 * 365)
|
||||
|> Date.to_string()
|
||||
|
||||
params = %{
|
||||
username: "mkljczk",
|
||||
email: "mkljczk@example.org",
|
||||
password: "dupa.8",
|
||||
agreement: true,
|
||||
birthday: birthday
|
||||
}
|
||||
|
||||
res =
|
||||
conn
|
||||
|> post("/api/v1/accounts", params)
|
||||
|
||||
assert json_response_and_validate_schema(res, 200)
|
||||
end
|
||||
|
||||
test "returns an error if missing birth date", %{conn: conn} do
|
||||
params = %{
|
||||
username: "mkljczk",
|
||||
email: "mkljczk@example.org",
|
||||
password: "dupa.8",
|
||||
agreement: true
|
||||
}
|
||||
|
||||
res =
|
||||
conn
|
||||
|> post("/api/v1/accounts", params)
|
||||
|
||||
assert json_response_and_validate_schema(res, 400) == %{
|
||||
"error" => "{\"birthday\":[\"can't be blank\"]}"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/v1/accounts/:id/lists - account_lists" do
|
||||
test "returns lists to which the account belongs" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:lists"])
|
||||
|
|
|
@ -370,6 +370,26 @@ test "update fields", %{conn: conn} do
|
|||
]
|
||||
end
|
||||
|
||||
test "updates birth date", %{conn: conn} do
|
||||
res =
|
||||
patch(conn, "/api/v1/accounts/update_credentials", %{
|
||||
"birthday" => "2001-02-12"
|
||||
})
|
||||
|
||||
assert user_data = json_response_and_validate_schema(res, 200)
|
||||
assert user_data["pleroma"]["birthday"] == "2001-02-12"
|
||||
end
|
||||
|
||||
test "updates the user's show_birthday status", %{conn: conn} do
|
||||
res =
|
||||
patch(conn, "/api/v1/accounts/update_credentials", %{
|
||||
"show_birthday" => true
|
||||
})
|
||||
|
||||
assert user_data = json_response_and_validate_schema(res, 200)
|
||||
assert user_data["source"]["pleroma"]["show_birthday"] == true
|
||||
end
|
||||
|
||||
test "emojis in fields labels", %{conn: conn} do
|
||||
fields = [
|
||||
%{"name" => ":firefox:", "value" => "is best 2hu"},
|
||||
|
|
|
@ -79,6 +79,7 @@ test "Represent a user account" do
|
|||
ap_id: user.ap_id,
|
||||
also_known_as: ["https://shitposter.zone/users/shp"],
|
||||
background_image: "https://example.com/images/asuka_hospital.png",
|
||||
birthday: nil,
|
||||
favicon: nil,
|
||||
is_confirmed: true,
|
||||
tags: [],
|
||||
|
@ -181,6 +182,7 @@ test "Represent a Service(bot) account" do
|
|||
ap_id: user.ap_id,
|
||||
also_known_as: [],
|
||||
background_image: nil,
|
||||
birthday: nil,
|
||||
favicon: nil,
|
||||
is_confirmed: true,
|
||||
tags: [],
|
||||
|
|
|
@ -304,4 +304,59 @@ test "returns 404 error when specified user is not exist", %{conn: conn} do
|
|||
assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}
|
||||
end
|
||||
end
|
||||
|
||||
describe "birthday reminders" do
|
||||
test "returns a list of friends having birthday on specified day" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:accounts"])
|
||||
|
||||
%{id: id1} =
|
||||
user1 =
|
||||
insert(:user, %{
|
||||
birthday: "2001-02-12",
|
||||
show_birthday: true
|
||||
})
|
||||
|
||||
user2 =
|
||||
insert(:user, %{
|
||||
birthday: "2001-02-14",
|
||||
show_birthday: true
|
||||
})
|
||||
|
||||
user3 = insert(:user)
|
||||
|
||||
CommonAPI.follow(user, user1)
|
||||
CommonAPI.follow(user, user2)
|
||||
CommonAPI.follow(user, user3)
|
||||
|
||||
[%{"id" => ^id1}] =
|
||||
conn
|
||||
|> get("/api/v1/pleroma/birthdays?day=12&month=2")
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
end
|
||||
|
||||
test "the list doesn't list friends with hidden birth date" do
|
||||
%{user: user, conn: conn} = oauth_access(["read:accounts"])
|
||||
|
||||
user1 =
|
||||
insert(:user, %{
|
||||
birthday: "2001-02-12",
|
||||
show_birthday: false
|
||||
})
|
||||
|
||||
%{id: id2} =
|
||||
user2 =
|
||||
insert(:user, %{
|
||||
birthday: "2001-02-12",
|
||||
show_birthday: true
|
||||
})
|
||||
|
||||
CommonAPI.follow(user, user1)
|
||||
CommonAPI.follow(user, user2)
|
||||
|
||||
[%{"id" => ^id2}] =
|
||||
conn
|
||||
|> get("/api/v1/pleroma/birthdays?day=12&month=2")
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue