summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gleason <alex@alexgleason.me>2022-01-25 15:35:47 +0000
committerAlex Gleason <alex@alexgleason.me>2022-01-25 15:35:47 +0000
commitdd7977bb68f8289b1487159a81df510da11cd944 (patch)
tree9266f4bee07fe384076ae6ff6f3b7839cf142942
parent19d557c870c3ec43dd3b0ee7ea85259a89bd9a80 (diff)
parent249fe88d12345c1c93f1812871cd70424b9e9a0d (diff)
Merge branch 'birth-dates' into 'develop'
Birth dates See merge request pleroma/pleroma!3608
-rw-r--r--CHANGELOG.md3
-rw-r--r--config/config.exs4
-rw-r--r--config/description.exs11
-rw-r--r--lib/pleroma/user.ex45
-rw-r--r--lib/pleroma/user/query.ex18
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex16
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex8
-rw-r--r--lib/pleroma/web/api_spec/operations/account_operation.ex23
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex29
-rw-r--r--lib/pleroma/web/api_spec/schemas/account.ex5
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex19
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex4
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/account_controller.ex19
-rw-r--r--lib/pleroma/web/router.ex2
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex1
-rw-r--r--priv/repo/migrations/20220116183110_add_birthday_to_users.exs12
-rw-r--r--priv/repo/migrations/20220125104429_add_birthday_month_day_index_to_users.exs11
-rw-r--r--priv/static/schemas/litepub-0.1.jsonld3
-rw-r--r--test/fixtures/birthdays/misskey-user.json1
-rw-r--r--test/pleroma/user_test.exs48
-rw-r--r--test/pleroma/web/activity_pub/activity_pub_test.exs20
-rw-r--r--test/pleroma/web/mastodon_api/controllers/account_controller_test.exs54
-rw-r--r--test/pleroma/web/mastodon_api/update_credentials_test.exs20
-rw-r--r--test/pleroma/web/mastodon_api/views/account_view_test.exs2
-rw-r--r--test/pleroma/web/pleroma_api/controllers/account_controller_test.exs55
26 files changed, 423 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6aaadca42..9e6e0fdf2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/config/config.exs b/config/config.exs
index 8ac650f6a..5e82f203c 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -257,7 +257,9 @@ config :pleroma, :instance,
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: [
diff --git a/config/description.exs b/config/description.exs
index 644c60a63..3f66877e4 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -957,6 +957,17 @@ config :pleroma, :config_description, [
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."
}
]
},
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index ef5a02249..36177bda3 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(:show_birthday, :boolean, default: false)
embeds_one(
:notification_settings,
@@ -470,7 +472,9 @@ defmodule Pleroma.User 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 @@ defmodule Pleroma.User 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 @@ 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 +768,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 +786,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)
@@ -2560,4 +2590,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..bd11d287c 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.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
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 9ca44c532..e6475a2b7 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1501,6 +1501,18 @@ 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
+
+ show_birthday = !!birthday
+
user_data = %{
ap_id: data["id"],
uri: get_actor_url(data["url"]),
@@ -1523,7 +1535,9 @@ 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,
+ show_birthday: show_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..5ed08d7f6 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.show_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..03efa3c38 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
+ },
+ show_birthday: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "User's birthday will be visible"
+ }
},
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",
+ show_birthday: false,
+ 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..029c6f6cf 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"
},
+ 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" => [],
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index a90833bf0..8e6d49168 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,
+ :show_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..e73d03f06 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -297,7 +297,8 @@ 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
}
}
|> maybe_put_role(user, opts[:for])
@@ -311,6 +312,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_show_birthday(user, opts[:for])
end
defp username_from_nickname(string) when is_binary(string) do
@@ -344,6 +346,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|> 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 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
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
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..d78ebbe2e 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/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
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 67c1a3e5c..26706a6b8 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("/birthdays", 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)
diff --git a/priv/repo/migrations/20220116183110_add_birthday_to_users.exs b/priv/repo/migrations/20220116183110_add_birthday_to_users.exs
new file mode 100644
index 000000000..0b22ecc69
--- /dev/null
+++ b/priv/repo/migrations/20220116183110_add_birthday_to_users.exs
@@ -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
diff --git a/priv/repo/migrations/20220125104429_add_birthday_month_day_index_to_users.exs b/priv/repo/migrations/20220125104429_add_birthday_month_day_index_to_users.exs
new file mode 100644
index 000000000..8ce4c77c5
--- /dev/null
+++ b/priv/repo/migrations/20220125104429_add_birthday_month_day_index_to_users.exs
@@ -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
diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld
index e7722cf72..946099a6e 100644
--- a/priv/static/schemas/litepub-0.1.jsonld
+++ b/priv/static/schemas/litepub-0.1.jsonld
@@ -35,7 +35,8 @@
"alsoKnownAs": {
"@id": "as:alsoKnownAs",
"@type": "@id"
- }
+ },
+ "vcard": "http://www.w3.org/2006/vcard/ns#"
}
]
}
diff --git a/test/fixtures/birthdays/misskey-user.json b/test/fixtures/birthdays/misskey-user.json
new file mode 100644
index 000000000..4ffee3910
--- /dev/null
+++ b/test/fixtures/birthdays/misskey-user.json
@@ -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"} \ No newline at end of file
diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs
index a5a9021f6..a9a3004a8 100644
--- a/test/pleroma/user_test.exs
+++ b/test/pleroma/user_test.exs
@@ -755,6 +755,54 @@ defmodule Pleroma.UserTest 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)
diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs
index 3d152b4d0..9789d7704 100644
--- a/test/pleroma/web/activity_pub/activity_pub_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_test.exs
@@ -389,6 +389,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest 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
diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
index 9b07cd5c2..f272ed1ae 100644
--- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
@@ -1608,6 +1608,60 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest 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"])
diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs
index 1d2027899..f0618885a 100644
--- a/test/pleroma/web/mastodon_api/update_credentials_test.exs
+++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs
@@ -370,6 +370,26 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest 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"},
diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs
index c23ffb966..329813994 100644
--- a/test/pleroma/web/mastodon_api/views/account_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs
@@ -79,6 +79,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest 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 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
ap_id: user.ap_id,
also_known_as: [],
background_image: nil,
+ birthday: nil,
favicon: nil,
is_confirmed: true,
tags: [],
diff --git a/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs
index d9aa8ce55..15682e40a 100644
--- a/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs
@@ -304,4 +304,59 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest 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