From 55d086b52077a220aef60c8d9071aea990431d74 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Wed, 27 Mar 2019 22:09:39 +0300 Subject: Notification controls Allow users to configure whether they want to receive notifications from people they follow / who follow them, people from remote / local instances --- lib/pleroma/notification.ex | 65 ++++++++++++++++++++++++++++++++++++++++----- lib/pleroma/user/info.ex | 4 +++ 2 files changed, 62 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index cac10f24a..caa6b755e 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -122,13 +122,7 @@ defmodule Pleroma.Notification do # TODO move to sql, too. def create_notification(%Activity{} = activity, %User{} = user) do - unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or - CommonAPI.thread_muted?(user, activity) or user.ap_id == activity.data["actor"] or - (activity.data["type"] == "Follow" and - Enum.any?(Notification.for_user(user), fn notif -> - notif.activity.data["type"] == "Follow" and - notif.activity.data["actor"] == activity.data["actor"] - end)) do + unless skip?(activity, user) do notification = %Notification{user_id: user.id, activity: activity} {:ok, notification} = Repo.insert(notification) Pleroma.Web.Streamer.stream("user", notification) @@ -154,4 +148,61 @@ defmodule Pleroma.Notification do end def get_notified_from_activity(_, _local_only), do: [] + + def skip?(activity, user) do + [:self, :blocked, :local, :muted, :followers, :follows, :recently_followed] + |> Enum.any?(&skip?(&1, activity, user)) + end + + def skip?(:self, activity, user) do + activity.data["actor"] == user.ap_id + end + + def skip?(:blocked, activity, user) do + actor = activity.data["actor"] + User.blocks?(user, %{ap_id: actor}) + end + + def skip?(:local, %{local: true}, user) do + user.info.notification_settings["local"] == false + end + + def skip?(:local, %{local: false}, user) do + user.info.notification_settings["remote"] == false + end + + def skip?(:muted, activity, user) do + actor = activity.data["actor"] + + User.mutes?(user, %{ap_id: actor}) or + CommonAPI.thread_muted?(user, activity) + end + + def skip?( + :followers, + activity, + %{info: %{notification_settings: %{"followers" => false}}} = user + ) do + actor = activity.data["actor"] + follower = User.get_cached_by_ap_id(actor) + User.following?(follower, user) + end + + def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do + actor = activity.data["actor"] + followed = User.get_by_ap_id(actor) + User.following?(user, followed) + end + + def skip?(:recently_followed, activity, user) do + actor = activity.data["actor"] + + Notification.for_user(user) + |> Enum.any?(fn + %{activity: %{data: %{"type" => "Follow", "actor" => ^actor}}} -> true + _ -> false + end) + end + + def skip?(_, _, _), do: false end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 740a46727..c36efa126 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -40,6 +40,10 @@ defmodule Pleroma.User.Info do field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + field(:notification_settings, :map, + default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} + ) + # Found in the wild # ap_id -> Where is this used? # bio -> Where is this used? -- cgit v1.2.3 From cd90695a349f33b84f287794bae6070e9eec446a Mon Sep 17 00:00:00 2001 From: eugenijm Date: Thu, 28 Mar 2019 14:52:09 +0300 Subject: Add PUT /api/pleroma/notification_settings endpoint --- lib/pleroma/notification.ex | 12 +++++------- lib/pleroma/user.ex | 8 ++++++++ lib/pleroma/user/info.ex | 13 +++++++++++++ lib/pleroma/web/mastodon_api/views/account_view.ex | 22 +++++++++++++++------- lib/pleroma/web/router.ex | 1 + .../web/twitter_api/controllers/util_controller.ex | 6 ++++++ 6 files changed, 48 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index caa6b755e..14de1a097 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -163,13 +163,11 @@ defmodule Pleroma.Notification do User.blocks?(user, %{ap_id: actor}) end - def skip?(:local, %{local: true}, user) do - user.info.notification_settings["local"] == false - end + def skip?(:local, %{local: true}, %{info: %{notification_settings: %{"local" => false}}}), + do: true - def skip?(:local, %{local: false}, user) do - user.info.notification_settings["remote"] == false - end + def skip?(:local, %{local: false}, %{info: %{notification_settings: %{"remote" => false}}}), + do: true def skip?(:muted, activity, user) do actor = activity.data["actor"] @@ -194,7 +192,7 @@ defmodule Pleroma.Notification do User.following?(user, followed) end - def skip?(:recently_followed, activity, user) do + def skip?(:recently_followed, %{data: %{"type" => "Follow"}} = activity, user) do actor = activity.data["actor"] Notification.for_user(user) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 728b00a56..73c2a82a7 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1082,6 +1082,14 @@ defmodule Pleroma.User do update_and_set_cache(cng) end + def update_notification_settings(%User{} = user, settings \\ %{}) do + info_changeset = User.Info.update_notification_settings(user.info, settings) + + change(user) + |> put_embed(:info, info_changeset) + |> update_and_set_cache() + end + def delete(%User{} = user) do {:ok, user} = User.deactivate(user) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index c36efa126..33fd77b02 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -61,6 +61,19 @@ defmodule Pleroma.User.Info do |> validate_required([:deactivated]) end + def update_notification_settings(info, settings) do + notification_settings = + info.notification_settings + |> Map.merge(settings) + |> Map.take(["remote", "local", "followers", "follows"]) + + params = %{notification_settings: notification_settings} + + info + |> cast(params, [:notification_settings]) + |> validate_required([:notification_settings]) + end + def add_to_note_count(info, number) do set_note_count(info, info.note_count + number) end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b5f3bbb9d..25899e491 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -117,13 +117,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do }, # Pleroma extension - pleroma: %{ - confirmation_pending: user_info.confirmation_pending, - tags: user.tags, - is_moderator: user.info.is_moderator, - is_admin: user.info.is_admin, - relationship: relationship - } + pleroma: + %{ + confirmation_pending: user_info.confirmation_pending, + tags: user.tags, + is_moderator: user.info.is_moderator, + is_admin: user.info.is_admin, + relationship: relationship + } + |> with_notification_settings(user, opts[:for]) } end @@ -132,4 +134,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do end defp username_from_nickname(_), do: nil + + defp with_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do + Map.put(data, :notification_settings, user.info.notification_settings) + end + + defp with_notification_settings(data, _, _), do: data end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 32e5f7644..36cbf0f57 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -182,6 +182,7 @@ defmodule Pleroma.Web.Router do post("/change_password", UtilController, :change_password) post("/delete_account", UtilController, :delete_account) + put("/notification_settings", UtilController, :update_notificaton_settings) end scope [] do diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index faa733fec..2708299cb 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -269,6 +269,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do json(conn, Enum.into(Emoji.get_all(), %{})) end + def update_notificaton_settings(%{assigns: %{user: user}} = conn, params) do + with {:ok, _} <- User.update_notification_settings(user, params) do + json(conn, %{status: "success"}) + end + end + def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do follow_import(conn, %{"list" => File.read!(listfile.path)}) end -- cgit v1.2.3 From 79910ce5cc85f83e58c5f49e53b4b6263925d110 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Fri, 5 Apr 2019 13:49:33 +0100 Subject: Add API endpoints and user column for subscription --- lib/pleroma/user.ex | 20 ++++++++++++++++++ lib/pleroma/user/info.ex | 17 +++++++++++++++ lib/pleroma/web/router.ex | 3 +++ lib/pleroma/web/twitter_api/twitter_api.ex | 12 +++++++++++ .../web/twitter_api/twitter_api_controller.ex | 24 ++++++++++++++++++++++ 5 files changed, 76 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 5012aef77..b7cab8642 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -923,6 +923,26 @@ defmodule Pleroma.User do update_and_set_cache(cng) end + def subscribe(subscriber, %{ap_id: ap_id}) do + info_cng = + subscriber.info + |> User.Info.add_to_subscriptions(ap_id) + + change(subscriber) + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end + + def unsubscribe(unsubscriber, %{ap_id: ap_id}) do + info_cng = + subscriber.info + |> User.Info.remove_from_subscriptions(ap_id) + + change(subscriber) + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end + def block(blocker, %User{ap_id: ap_id} = blocked) do # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213) blocker = diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 740a46727..30c594f64 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -22,6 +22,7 @@ defmodule Pleroma.User.Info do field(:domain_blocks, {:array, :string}, default: []) field(:mutes, {:array, :string}, default: []) field(:muted_reblogs, {:array, :string}, default: []) + field(:subscribed_to, {:array, :string}, default: []) field(:deactivated, :boolean, default: false) field(:no_rich_text, :boolean, default: false) field(:ap_enabled, :boolean, default: false) @@ -93,6 +94,14 @@ defmodule Pleroma.User.Info do |> validate_required([:blocks]) end + def set_subscriptions(info, subscriptions) do + params = %{subscriptions: subscriptions} + + info + |> cast(params, [:subscribed_to]) + |> validate_required([:subscribed_to]) + end + def add_to_mutes(info, muted) do set_mutes(info, Enum.uniq([muted | info.mutes])) end @@ -109,6 +118,14 @@ defmodule Pleroma.User.Info do set_blocks(info, List.delete(info.blocks, blocked)) end + def add_to_subscriptions(info, subscribed) do + set_subscriptions(info, Enum.uniq([subscribed | info.subscribed_to])) + end + + def remove_from_subscriptions(info, subscribed) do + set_subscriptions(info, List.delete(info.subscribed_to, subscribed)) + end + def set_domain_blocks(info, domain_blocks) do params = %{domain_blocks: domain_blocks} diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 605a327fc..10037b24f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -500,6 +500,9 @@ defmodule Pleroma.Web.Router do post("/blocks/create", TwitterAPI.Controller, :block) post("/blocks/destroy", TwitterAPI.Controller, :unblock) + + post("/subscriptions/create", TwitterAPI.Controller, :subscribe) + post("/subscriptions/destroy", TwitterAPI.Controller, :unsubscribe) end end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 9b081a316..c0a0a500f 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -59,6 +59,18 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end end + def subscribe(%User{} = subscriber, params) do + with {:ok, %User{} = subscribed} <- get_user(params) do + User.subscribe(subscriber, subscribed) + end + end + + def unsubscribe(%User{} = unsubscriber, params) do + with {:ok, %User{} = unsubscribed} <- get_user(params) do + User.unsubscribe(unsubscriber, unsubscribed) + end + end + def repeat(%User{} = user, ap_id_or_id) do with {:ok, _announce, %{data: %{"id" => id}}} <- CommonAPI.repeat(ap_id_or_id, user), %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index a7ec9949c..af4c0a60e 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -269,6 +269,30 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end end + def subscribe(%{assigns: %{user: user}} = conn, params) do + case TwitterAPI.subscribe(user, params) do + {:ok, user, subscribed} -> + conn + |> put_view(UserView) + |> render("show.json", %{user: subscribed, for: user}) + + {:error, msg} -> + forbidden_json_reply(conn, msg) + end + end + + def unsubscribe(%{assigns: %{user: user}} = conn, params) do + case TwitterAPI.unsubscribe(user, params) do + {:ok, user, unsubscribed} -> + conn + |> put_view(UserView) + |> render("show.json", %{user: unsubscribed, for: user}) + + {:error, msg} -> + forbidden_json_reply(conn, msg) + end + end + def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do -- cgit v1.2.3 From 007762e767fcd734bacd9700f5268591854a446a Mon Sep 17 00:00:00 2001 From: Sadposter Date: Fri, 5 Apr 2019 14:20:13 +0100 Subject: Add notification checks --- lib/pleroma/notification.ex | 1 + lib/pleroma/user.ex | 7 +++++-- lib/pleroma/user/info.ex | 10 +++++----- lib/pleroma/web/common_api/utils.ex | 16 ++++++++++++++++ lib/pleroma/web/twitter_api/twitter_api.ex | 1 + 5 files changed, 28 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index cac10f24a..7c5856438 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -148,6 +148,7 @@ defmodule Pleroma.Notification do [] |> Utils.maybe_notify_to_recipients(activity) |> Utils.maybe_notify_mentioned_recipients(activity) + |> Utils.maybe_notify_subscribers(activity) |> Enum.uniq() User.get_users_from_set(recipients, local_only) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b7cab8642..70db520ca 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -935,10 +935,10 @@ defmodule Pleroma.User do def unsubscribe(unsubscriber, %{ap_id: ap_id}) do info_cng = - subscriber.info + unsubscriber.info |> User.Info.remove_from_subscriptions(ap_id) - change(subscriber) + change(unsubscriber) |> put_embed(:info, info_cng) |> update_and_set_cache() end @@ -1005,6 +1005,9 @@ defmodule Pleroma.User do def blocked_users(user), do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) + def subscribed_users(user), + do: Repo.all(from(u in User, where: u.ap_id in ^user.info.subscriptions)) + def block_domain(user, domain) do info_cng = user.info diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 30c594f64..1746da576 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -22,7 +22,7 @@ defmodule Pleroma.User.Info do field(:domain_blocks, {:array, :string}, default: []) field(:mutes, {:array, :string}, default: []) field(:muted_reblogs, {:array, :string}, default: []) - field(:subscribed_to, {:array, :string}, default: []) + field(:subscriptions, {:array, :string}, default: []) field(:deactivated, :boolean, default: false) field(:no_rich_text, :boolean, default: false) field(:ap_enabled, :boolean, default: false) @@ -98,8 +98,8 @@ defmodule Pleroma.User.Info do params = %{subscriptions: subscriptions} info - |> cast(params, [:subscribed_to]) - |> validate_required([:subscribed_to]) + |> cast(params, [:subscriptions]) + |> validate_required([:subscriptions]) end def add_to_mutes(info, muted) do @@ -119,11 +119,11 @@ defmodule Pleroma.User.Info do end def add_to_subscriptions(info, subscribed) do - set_subscriptions(info, Enum.uniq([subscribed | info.subscribed_to])) + set_subscriptions(info, Enum.uniq([subscribed | info.subscriptions])) end def remove_from_subscriptions(info, subscribed) do - set_subscriptions(info, List.delete(info.subscribed_to, subscribed)) + set_subscriptions(info, List.delete(info.subscriptions, subscribed)) end def set_domain_blocks(info, domain_blocks) do diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 9cd8b3758..effc49a01 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -335,6 +335,22 @@ defmodule Pleroma.Web.CommonAPI.Utils do def maybe_notify_mentioned_recipients(recipients, _), do: recipients + def maybe_notify_subscribers( + recipients, + %Activity{data: %{"actor" => actor, "type" => type}} + ) when type == "Create" do + with %User{} = user <- User.get_by_ap_id(actor) do + subscriber_ids = + user + |> User.subscribed_users() + |> Enum.map(& &1.ap_id) + + recipients ++ subscriber_ids + end + end + + def maybe_notify_subscribers(recipients, _), do: recipients + def maybe_extract_mentions(%{"tag" => tag}) do tag |> Enum.filter(fn x -> is_map(x) end) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index c0a0a500f..7720367ad 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -62,6 +62,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do def subscribe(%User{} = subscriber, params) do with {:ok, %User{} = subscribed} <- get_user(params) do User.subscribe(subscriber, subscribed) + |> IO.inspect end end -- cgit v1.2.3 From 23c4f4949436003f6ccd7fd283492a6598f88482 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Fri, 5 Apr 2019 14:27:26 +0100 Subject: Fix subscription endpoint return formats --- lib/pleroma/web/twitter_api/twitter_api.ex | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 7720367ad..5537680ad 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -60,15 +60,16 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def subscribe(%User{} = subscriber, params) do - with {:ok, %User{} = subscribed} <- get_user(params) do - User.subscribe(subscriber, subscribed) - |> IO.inspect + with {:ok, %User{} = subscribed} <- get_user(params), + {:ok, subscriber} <- User.subscribe(subscriber, subscribed) do + {:ok, subscriber, subscribed} end end def unsubscribe(%User{} = unsubscriber, params) do - with {:ok, %User{} = unsubscribed} <- get_user(params) do - User.unsubscribe(unsubscriber, unsubscribed) + with {:ok, %User{} = unsubscribed} <- get_user(params), + {:ok, unsubscriber} <- User.unsubscribe(unsubscriber, unsubscribed) do + {:ok, unsubscriber, unsubscribed} end end -- cgit v1.2.3 From 316fe20d864711c2854401eaa2cb08f627d5e536 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Fri, 5 Apr 2019 14:59:34 +0100 Subject: Make subscriptions the same direction as blocks That being, user - subscribes to -> users, rather than user - has subscribers -> users --- lib/pleroma/user.ex | 7 ++++++- lib/pleroma/web/common_api/utils.ex | 9 +++++---- lib/pleroma/web/twitter_api/twitter_api_controller.ex | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 70db520ca..6b213df58 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1006,7 +1006,12 @@ defmodule Pleroma.User do do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) def subscribed_users(user), - do: Repo.all(from(u in User, where: u.ap_id in ^user.info.subscriptions)) + do: + Repo.all( + from(u in User, + where: fragment("?->'subscriptions' @> ?", u.info, ^user.ap_id) + ) + ) def block_domain(user, domain) do info_cng = diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index effc49a01..087778dfe 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -336,10 +336,11 @@ defmodule Pleroma.Web.CommonAPI.Utils do def maybe_notify_mentioned_recipients(recipients, _), do: recipients def maybe_notify_subscribers( - recipients, - %Activity{data: %{"actor" => actor, "type" => type}} - ) when type == "Create" do - with %User{} = user <- User.get_by_ap_id(actor) do + recipients, + %Activity{data: %{"actor" => actor, "type" => type}} + ) + when type == "Create" do + with %User{} = user <- User.get_by_ap_id(actor) do subscriber_ids = user |> User.subscribed_users() diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index af4c0a60e..0732705e6 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -279,7 +279,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do {:error, msg} -> forbidden_json_reply(conn, msg) end - end + end def unsubscribe(%{assigns: %{user: user}} = conn, params) do case TwitterAPI.unsubscribe(user, params) do @@ -287,7 +287,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do conn |> put_view(UserView) |> render("show.json", %{user: unsubscribed, for: user}) - + {:error, msg} -> forbidden_json_reply(conn, msg) end -- cgit v1.2.3 From d56866c824d8023c9ca162ffef4c2eff150de399 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Fri, 5 Apr 2019 15:21:33 +0100 Subject: Add subscribed status to user view Added in pleroma extensions, but can be moved whenever --- lib/pleroma/user.ex | 5 +++++ lib/pleroma/web/twitter_api/views/user_view.ex | 10 ++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 6b213df58..de7ed6e72 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -999,6 +999,11 @@ defmodule Pleroma.User do end) end + def subscribed_to?(user, %{ap_id: ap_id}) do + subs = user.info.subscriptions + Enum.member?(subs, ap_id) + end + def muted_users(user), do: Repo.all(from(u in User, where: u.ap_id in ^user.info.mutes)) diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 0791ed760..c59570d3e 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -47,15 +47,16 @@ defmodule Pleroma.Web.TwitterAPI.UserView do for_user = assigns[:for] image = User.avatar_url(user) |> MediaProxy.url() - {following, follows_you, statusnet_blocking} = + {following, follows_you, statusnet_blocking, subscribed} = if for_user do { User.following?(for_user, user), User.following?(user, for_user), - User.blocks?(for_user, user) + User.blocks?(for_user, user), + User.subscribed_to?(for_user, user) } else - {false, false, false} + {false, false, false, false} end user_info = User.get_cached_user_info(user) @@ -116,7 +117,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do "pleroma" => %{ "confirmation_pending" => user_info.confirmation_pending, - "tags" => user.tags + "tags" => user.tags, + "subscribed" => subscribed } |> maybe_with_activation_status(user, for_user) } -- cgit v1.2.3 From d35f6551c1e9b11dec81b622c9ed2d9cdd6ac389 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Fri, 5 Apr 2019 15:58:44 +0100 Subject: Move subscriptions endpoint to be under /pleroma --- lib/pleroma/web/router.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 10037b24f..0b571fc0b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -495,14 +495,14 @@ defmodule Pleroma.Web.Router do post("/pleroma/friendships/approve", TwitterAPI.Controller, :approve_friend_request) post("/pleroma/friendships/deny", TwitterAPI.Controller, :deny_friend_request) + post("/pleroma/subscriptions/create", TwitterAPI.Controller, :subscribe) + post("/pleroma/subscriptions/destroy", TwitterAPI.Controller, :unsubscribe) + post("/friendships/create", TwitterAPI.Controller, :follow) post("/friendships/destroy", TwitterAPI.Controller, :unfollow) post("/blocks/create", TwitterAPI.Controller, :block) post("/blocks/destroy", TwitterAPI.Controller, :unblock) - - post("/subscriptions/create", TwitterAPI.Controller, :subscribe) - post("/subscriptions/destroy", TwitterAPI.Controller, :unsubscribe) end end -- cgit v1.2.3 From 9ca91cbb8764ef4f8fe5303705dd98984e4e90c0 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Fri, 5 Apr 2019 16:51:45 +0100 Subject: Change relationship direction of subscriptions --- lib/pleroma/user.ex | 42 +++++++++++----------- lib/pleroma/user/info.ex | 18 +++++----- lib/pleroma/web/common_api/utils.ex | 2 +- .../web/mastodon_api/mastodon_api_controller.ex | 20 +++++++++++ lib/pleroma/web/mastodon_api/views/account_view.ex | 1 + lib/pleroma/web/router.ex | 6 ++-- lib/pleroma/web/twitter_api/twitter_api.ex | 14 -------- .../web/twitter_api/twitter_api_controller.ex | 24 ------------- lib/pleroma/web/twitter_api/views/user_view.ex | 10 +++--- 9 files changed, 59 insertions(+), 78 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index de7ed6e72..f1565ade7 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -924,23 +924,27 @@ defmodule Pleroma.User do end def subscribe(subscriber, %{ap_id: ap_id}) do - info_cng = - subscriber.info - |> User.Info.add_to_subscriptions(ap_id) + with %User{} = user <- get_or_fetch_by_ap_id(ap_id) do + info_cng = + user.info + |> User.Info.add_to_subscribers(subscriber.ap_id) - change(subscriber) - |> put_embed(:info, info_cng) - |> update_and_set_cache() + change(user) + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end end def unsubscribe(unsubscriber, %{ap_id: ap_id}) do - info_cng = - unsubscriber.info - |> User.Info.remove_from_subscriptions(ap_id) + with %User{} = user <- get_or_fetch_by_ap_id(ap_id) do + info_cng = + user.info + |> User.Info.remove_from_subscribers(unsubscriber.ap_id) - change(unsubscriber) - |> put_embed(:info, info_cng) - |> update_and_set_cache() + change(user) + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end end def block(blocker, %User{ap_id: ap_id} = blocked) do @@ -1000,8 +1004,9 @@ defmodule Pleroma.User do end def subscribed_to?(user, %{ap_id: ap_id}) do - subs = user.info.subscriptions - Enum.member?(subs, ap_id) + with %User{} = target <- User.get_by_ap_id(ap_id) do + Enum.member?(target.info.subscribers, user.ap_id) + end end def muted_users(user), @@ -1010,13 +1015,8 @@ defmodule Pleroma.User do def blocked_users(user), do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) - def subscribed_users(user), - do: - Repo.all( - from(u in User, - where: fragment("?->'subscriptions' @> ?", u.info, ^user.ap_id) - ) - ) + def subscribers(user), + do: Repo.all(from(u in User, where: u.ap_id in ^user.info.subscribers)) def block_domain(user, domain) do info_cng = diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 1746da576..1cf46feb3 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -22,7 +22,7 @@ defmodule Pleroma.User.Info do field(:domain_blocks, {:array, :string}, default: []) field(:mutes, {:array, :string}, default: []) field(:muted_reblogs, {:array, :string}, default: []) - field(:subscriptions, {:array, :string}, default: []) + field(:subscribers, {:array, :string}, default: []) field(:deactivated, :boolean, default: false) field(:no_rich_text, :boolean, default: false) field(:ap_enabled, :boolean, default: false) @@ -94,12 +94,12 @@ defmodule Pleroma.User.Info do |> validate_required([:blocks]) end - def set_subscriptions(info, subscriptions) do - params = %{subscriptions: subscriptions} + def set_subscribers(info, subscribers) do + params = %{subscribers: subscribers} info - |> cast(params, [:subscriptions]) - |> validate_required([:subscriptions]) + |> cast(params, [:subscribers]) + |> validate_required([:subscribers]) end def add_to_mutes(info, muted) do @@ -118,12 +118,12 @@ defmodule Pleroma.User.Info do set_blocks(info, List.delete(info.blocks, blocked)) end - def add_to_subscriptions(info, subscribed) do - set_subscriptions(info, Enum.uniq([subscribed | info.subscriptions])) + def add_to_subscribers(info, subscribed) do + set_subscribers(info, Enum.uniq([subscribed | info.subscribers])) end - def remove_from_subscriptions(info, subscribed) do - set_subscriptions(info, List.delete(info.subscriptions, subscribed)) + def remove_from_subscribers(info, subscribed) do + set_subscribers(info, List.delete(info.subscribers, subscribed)) end def set_domain_blocks(info, domain_blocks) do diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 087778dfe..4e0a6b2d9 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -343,7 +343,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do with %User{} = user <- User.get_by_ap_id(actor) do subscriber_ids = user - |> User.subscribed_users() + |> User.subscribers() |> Enum.map(& &1.ap_id) recipients ++ subscriber_ids diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 89fd7629a..e848895f1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -863,6 +863,26 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, %{}) end + def subscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %User{} = subscription_target <- User.get_by_id(id) do + {:ok, subscription_target} = User.subscribe(user, subscription_target) + + conn + |> put_view(AccountView) + |> render("relationship.json", %{user: user, target: subscription_target}) + end + end + + def unsubscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %User{} = subscription_target <- User.get_by_id(id) do + {:ok, subscription_target} = User.unsubscribe(user, subscription_target) + + conn + |> put_view(AccountView) + |> render("relationship.json", %{user: user, target: subscription_target}) + end + end + def status_search(user, query) do fetched = if Regex.match?(~r/https?:/, query) do diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b5f3bbb9d..42595b0b5 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -53,6 +53,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do blocking: User.blocks?(user, target), muting: User.mutes?(user, target), muting_notifications: false, + subscribing: User.subscribed_to?(user, target), requested: requested, domain_blocking: false, showing_reblogs: User.showing_reblogs?(user, target), diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 0b571fc0b..da988e5f2 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -311,6 +311,9 @@ defmodule Pleroma.Web.Router do post("/domain_blocks", MastodonAPIController, :block_domain) delete("/domain_blocks", MastodonAPIController, :unblock_domain) + + post("/pleroma/accounts/:id/subscribe", MastodonAPIController, :subscribe) + post("/pleroma/accounts/:id/unsubscribe", MastodonAPIController, :unsubscribe) end scope [] do @@ -495,9 +498,6 @@ defmodule Pleroma.Web.Router do post("/pleroma/friendships/approve", TwitterAPI.Controller, :approve_friend_request) post("/pleroma/friendships/deny", TwitterAPI.Controller, :deny_friend_request) - post("/pleroma/subscriptions/create", TwitterAPI.Controller, :subscribe) - post("/pleroma/subscriptions/destroy", TwitterAPI.Controller, :unsubscribe) - post("/friendships/create", TwitterAPI.Controller, :follow) post("/friendships/destroy", TwitterAPI.Controller, :unfollow) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 5537680ad..9b081a316 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -59,20 +59,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end end - def subscribe(%User{} = subscriber, params) do - with {:ok, %User{} = subscribed} <- get_user(params), - {:ok, subscriber} <- User.subscribe(subscriber, subscribed) do - {:ok, subscriber, subscribed} - end - end - - def unsubscribe(%User{} = unsubscriber, params) do - with {:ok, %User{} = unsubscribed} <- get_user(params), - {:ok, unsubscriber} <- User.unsubscribe(unsubscriber, unsubscribed) do - {:ok, unsubscriber, unsubscribed} - end - end - def repeat(%User{} = user, ap_id_or_id) do with {:ok, _announce, %{data: %{"id" => id}}} <- CommonAPI.repeat(ap_id_or_id, user), %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 0732705e6..a7ec9949c 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -269,30 +269,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end end - def subscribe(%{assigns: %{user: user}} = conn, params) do - case TwitterAPI.subscribe(user, params) do - {:ok, user, subscribed} -> - conn - |> put_view(UserView) - |> render("show.json", %{user: subscribed, for: user}) - - {:error, msg} -> - forbidden_json_reply(conn, msg) - end - end - - def unsubscribe(%{assigns: %{user: user}} = conn, params) do - case TwitterAPI.unsubscribe(user, params) do - {:ok, user, unsubscribed} -> - conn - |> put_view(UserView) - |> render("show.json", %{user: unsubscribed, for: user}) - - {:error, msg} -> - forbidden_json_reply(conn, msg) - end - end - def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index c59570d3e..0791ed760 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -47,16 +47,15 @@ defmodule Pleroma.Web.TwitterAPI.UserView do for_user = assigns[:for] image = User.avatar_url(user) |> MediaProxy.url() - {following, follows_you, statusnet_blocking, subscribed} = + {following, follows_you, statusnet_blocking} = if for_user do { User.following?(for_user, user), User.following?(user, for_user), - User.blocks?(for_user, user), - User.subscribed_to?(for_user, user) + User.blocks?(for_user, user) } else - {false, false, false, false} + {false, false, false} end user_info = User.get_cached_user_info(user) @@ -117,8 +116,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do "pleroma" => %{ "confirmation_pending" => user_info.confirmation_pending, - "tags" => user.tags, - "subscribed" => subscribed + "tags" => user.tags } |> maybe_with_activation_status(user, for_user) } -- cgit v1.2.3 From 0484f3a8b1ae2103d1d756e5c09f2bdb218a7207 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 6 Apr 2019 16:58:22 +0700 Subject: generating tokens with mix --- lib/mix/tasks/pleroma/user.ex | 75 +++++++++++++++++++++++++++++++-- lib/pleroma/user_invite_token.ex | 89 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 154 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 0d0bea8c0..00a933292 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -7,6 +7,7 @@ defmodule Mix.Tasks.Pleroma.User do import Ecto.Changeset alias Mix.Tasks.Pleroma.Common alias Pleroma.User + alias Pleroma.UserInviteToken @shortdoc "Manages Pleroma users" @moduledoc """ @@ -26,7 +27,19 @@ defmodule Mix.Tasks.Pleroma.User do ## Generate an invite link. - mix pleroma.user invite + mix pleroma.user invite [OPTION...] + + Options: + - `--expire_date DATE` - last day on which token is active (e.g. "2019-04-05") + - `--max_use NUMBER` - maximum numbers of token use + + ## Generated invites list + + mix pleroma.user invites_list + + ## Revoke invite + + mix pleroma.user invite_revoke TOKEN OR TOKEN_ID ## Delete the user's account. @@ -287,11 +300,28 @@ defmodule Mix.Tasks.Pleroma.User do end end - def run(["invite"]) do + def run(["invite" | rest]) do + {options, [], []} = + OptionParser.parse(rest, + strict: [ + expire_date: :string, + max_use: :integer + ] + ) + + expire_at = + with expire_date when expire_date != nil <- Keyword.get(options, :expire_date) do + Date.from_iso8601!(expire_date) + end + + options = Keyword.put(options, :expire_at, expire_at) + Common.start_pleroma() - with {:ok, token} <- Pleroma.UserInviteToken.create_token() do - Mix.shell().info("Generated user invite token") + with {:ok, token} <- UserInviteToken.create_token(options) do + Mix.shell().info( + "Generated user invite token " <> String.replace(token.token_type, "_", " ") + ) url = Pleroma.Web.Router.Helpers.redirect_url( @@ -307,6 +337,43 @@ defmodule Mix.Tasks.Pleroma.User do end end + def run(["invites_list"]) do + Common.start_pleroma() + + Mix.shell().info("Invites list:") + + UserInviteToken.list_invites() + |> Enum.each(fn invite -> + expire_date = + case invite.expire_at do + nil -> nil + date -> " | Expire date: #{Date.to_string(date)}" + end + + using_info = + case invite.max_use do + nil -> nil + max_use -> " | Max use: #{max_use} Left use: #{max_use - invite.uses}" + end + + Mix.shell().info( + "ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.token_type} | Used: #{ + invite.used + }#{expire_date}#{using_info}" + ) + end) + end + + def run(["invite_revoke", token]) do + Common.start_pleroma() + + with {:ok, _} <- UserInviteToken.mark_as_used(token) do + Mix.shell().info("Invite for token #{token} was revoked.") + else + _ -> Mix.shell().error("No invite found with token #{token}") + end + end + def run(["delete_activities", nickname]) do Common.start_pleroma() diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index 9c5579934..3ed39ddd3 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -6,34 +6,54 @@ defmodule Pleroma.UserInviteToken do use Ecto.Schema import Ecto.Changeset - + import Ecto.Query alias Pleroma.Repo alias Pleroma.UserInviteToken + @type token :: String.t() + schema "user_invite_tokens" do field(:token, :string) field(:used, :boolean, default: false) + field(:max_use, :integer) + field(:expire_at, :date) + field(:uses, :integer) + field(:token_type) timestamps() end - def create_token do + def create_token(options \\ []) do token = :crypto.strong_rand_bytes(32) |> Base.url_encode64() - token = %UserInviteToken{ - used: false, - token: token - } + max_use = options[:max_use] + expire_at = options[:expire_at] + + token = + %UserInviteToken{ + used: false, + token: token, + max_use: max_use, + expire_at: expire_at, + uses: 0 + } + |> token_type() Repo.insert(token) end + def list_invites do + query = from(u in UserInviteToken, order_by: u.id) + Repo.all(query) + end + def used_changeset(struct) do struct |> cast(%{}, []) |> put_change(:used, true) end + @spec mark_as_used(token()) :: {:ok, UserInviteToken.t()} | {:error, token()} def mark_as_used(token) do with %{used: false} = token <- Repo.get_by(UserInviteToken, %{token: token}), {:ok, token} <- Repo.update(used_changeset(token)) do @@ -42,4 +62,61 @@ defmodule Pleroma.UserInviteToken do _e -> {:error, token} end end + + defp token_type(%{expire_at: nil, max_use: nil} = token), do: %{token | token_type: "one_time"} + + defp token_type(%{expire_at: _expire_at, max_use: nil} = token), + do: %{token | token_type: "date_limited"} + + defp token_type(%{expire_at: nil, max_use: _max_use} = token), + do: %{token | token_type: "reusable"} + + defp token_type(%{expire_at: _expire_at, max_use: _max_use} = token), + do: %{token | token_type: "reusable_date_limited"} + + @spec valid_token?(UserInviteToken.t()) :: boolean() + def valid_token?(%{token_type: "one_time"} = token) do + not token.used + end + + def valid_token?(%{token_type: "date_limited"} = token) do + not_overdue_date?(token) and not token.used + end + + def valid_token?(%{token_type: "reusable"} = token) do + token.uses < token.max_use and not token.used + end + + def valid_token?(%{token_type: "reusable_date_limited"} = token) do + not_overdue_date?(token) and token.uses < token.max_use and not token.used + end + + defp not_overdue_date?(%{expire_at: expire_at} = token) do + Date.compare(Date.utc_today(), expire_at) in [:lt, :eq] || + (Repo.update!(change(token, used: true)) && false) + end + + def update_usage(%{token_type: "date_limited"}), do: nil + + def update_usage(%{token_type: "one_time"} = token) do + UserInviteToken.mark_as_used(token.token) + end + + def update_usage(%{token_type: token_type} = token) + when token_type == "reusable" or token_type == "reusable_date_limited" do + new_uses = token.uses + 1 + + changes = %{ + uses: new_uses + } + + changes = + if new_uses >= token.max_use do + Map.put(changes, :used, true) + else + changes + end + + change(token, changes) |> Repo.update!() + end end -- cgit v1.2.3 From be54e40890432d2cd8e592e6d4acfa9f1e98586c Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 6 Apr 2019 17:18:59 +0700 Subject: twitter api registration fix for twitter api tests --- lib/pleroma/web/twitter_api/twitter_api.ex | 59 ++++++++++++++++++------------ 1 file changed, 36 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 9b081a316..a578fbbf4 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -163,36 +163,49 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do {:error, %{error: Jason.encode!(%{captcha: [error]})}} else registrations_open = Pleroma.Config.get([:instance, :registrations_open]) + registration_process(registrations_open, params, token_string) + end + end - # no need to query DB if registration is open - token = - unless registrations_open || is_nil(token_string) do - Repo.get_by(UserInviteToken, %{token: token_string}) - end + defp registration_process(_registration_open = true, params, _token_string) do + create_user(params) + end - cond do - registrations_open || (!is_nil(token) && !token.used) -> - changeset = User.register_changeset(%User{}, params) + defp registration_process(registration_open, params, token_string) + when registration_open == false or is_nil(registration_open) do + token = + unless is_nil(token_string) do + Repo.get_by(UserInviteToken, %{token: token_string}) + end - with {:ok, user} <- User.register(changeset) do - !registrations_open && UserInviteToken.mark_as_used(token.token) + valid_token? = token && UserInviteToken.valid_token?(token) - {:ok, user} - else - {:error, changeset} -> - errors = - Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end) - |> Jason.encode!() + case token do + nil -> + {:error, "Invalid token"} - {:error, %{error: errors}} - end + token when valid_token? -> + UserInviteToken.update_usage(token) + create_user(params) - !registrations_open && is_nil(token) -> - {:error, "Invalid token"} + _ -> + {:error, "Expired token"} + end + end - !registrations_open && token.used -> - {:error, "Expired token"} - end + defp create_user(params) do + changeset = User.register_changeset(%User{}, params) + + case User.register(changeset) do + {:ok, user} -> + {:ok, user} + + {:error, changeset} -> + errors = + Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end) + |> Jason.encode!() + + {:error, %{error: errors}} end end -- cgit v1.2.3 From 47b07cec495528ce22f83ca56717cc74aa0096f3 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 6 Apr 2019 20:24:22 +0700 Subject: token -> invite renaming --- lib/mix/tasks/pleroma/user.ex | 12 +-- lib/pleroma/user_invite_token.ex | 113 ++++++++++++++--------------- lib/pleroma/web/twitter_api/twitter_api.ex | 22 +++--- 3 files changed, 72 insertions(+), 75 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 00a933292..887f45029 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -315,19 +315,19 @@ defmodule Mix.Tasks.Pleroma.User do end options = Keyword.put(options, :expire_at, expire_at) - + options = Enum.into(options, %{}) Common.start_pleroma() - with {:ok, token} <- UserInviteToken.create_token(options) do + with {:ok, invite} <- UserInviteToken.create_invite(options) do Mix.shell().info( - "Generated user invite token " <> String.replace(token.token_type, "_", " ") + "Generated user invite token " <> String.replace(invite.invite_type, "_", " ") ) url = Pleroma.Web.Router.Helpers.redirect_url( Pleroma.Web.Endpoint, :registration_page, - token.token + invite.token ) IO.puts(url) @@ -367,7 +367,9 @@ defmodule Mix.Tasks.Pleroma.User do def run(["invite_revoke", token]) do Common.start_pleroma() - with {:ok, _} <- UserInviteToken.mark_as_used(token) do + invite = UserInviteToken.find_by_token!(token) + + with {:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do Mix.shell().info("Invite for token #{token} was revoked.") else _ -> Mix.shell().error("No invite found with token #{token}") diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index 3ed39ddd3..4efdbdc32 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -17,106 +17,101 @@ defmodule Pleroma.UserInviteToken do field(:used, :boolean, default: false) field(:max_use, :integer) field(:expire_at, :date) - field(:uses, :integer) - field(:token_type) + field(:uses, :integer, default: 0) + field(:invite_type, :string) timestamps() end - def create_token(options \\ []) do + @spec create_invite(map()) :: UserInviteToken.t() + def create_invite(params \\ %{}) do + %UserInviteToken{} + |> cast(params, ~w(max_use expire_at)a) + |> add_token() + |> assign_type() + |> Repo.insert() + end + + defp add_token(changeset) do token = :crypto.strong_rand_bytes(32) |> Base.url_encode64() + put_change(changeset, :token, token) + end - max_use = options[:max_use] - expire_at = options[:expire_at] + defp assign_type(%{changes: %{max_use: _max_use, expire_at: _expire_at}} = changeset) do + put_change(changeset, :invite_type, "reusable_date_limited") + end - token = - %UserInviteToken{ - used: false, - token: token, - max_use: max_use, - expire_at: expire_at, - uses: 0 - } - |> token_type() + defp assign_type(%{changes: %{expire_at: _expire_at}} = changeset) do + put_change(changeset, :invite_type, "date_limited") + end - Repo.insert(token) + defp assign_type(%{changes: %{max_use: _max_use}} = changeset) do + put_change(changeset, :invite_type, "reusable") end + defp assign_type(changeset), do: put_change(changeset, :invite_type, "one_time") + + @spec list_invites() :: [UserInviteToken.t()] def list_invites do query = from(u in UserInviteToken, order_by: u.id) Repo.all(query) end - def used_changeset(struct) do - struct - |> cast(%{}, []) - |> put_change(:used, true) + @spec update_invite!(UserInviteToken.t(), map()) :: UserInviteToken.t() | no_return() + def update_invite!(invite, changes) do + change(invite, changes) |> Repo.update!() end - @spec mark_as_used(token()) :: {:ok, UserInviteToken.t()} | {:error, token()} - def mark_as_used(token) do - with %{used: false} = token <- Repo.get_by(UserInviteToken, %{token: token}), - {:ok, token} <- Repo.update(used_changeset(token)) do - {:ok, token} - else - _e -> {:error, token} - end + @spec update_invite(UserInviteToken.t(), map()) :: + {:ok, UserInviteToken.t()} | {:error, Changeset.t()} + def update_invite(invite, changes) do + change(invite, changes) |> Repo.update() end - defp token_type(%{expire_at: nil, max_use: nil} = token), do: %{token | token_type: "one_time"} + @spec find_by_token!(token()) :: UserInviteToken.t() | no_return() + def find_by_token!(token), do: Repo.get_by!(UserInviteToken, token: token) - defp token_type(%{expire_at: _expire_at, max_use: nil} = token), - do: %{token | token_type: "date_limited"} - - defp token_type(%{expire_at: nil, max_use: _max_use} = token), - do: %{token | token_type: "reusable"} - - defp token_type(%{expire_at: _expire_at, max_use: _max_use} = token), - do: %{token | token_type: "reusable_date_limited"} - - @spec valid_token?(UserInviteToken.t()) :: boolean() - def valid_token?(%{token_type: "one_time"} = token) do - not token.used + @spec valid_invite?(UserInviteToken.t()) :: boolean() + def valid_invite?(%{invite_type: "one_time"} = invite) do + not invite.used end - def valid_token?(%{token_type: "date_limited"} = token) do - not_overdue_date?(token) and not token.used + def valid_invite?(%{invite_type: "date_limited"} = invite) do + not_overdue_date?(invite) and not invite.used end - def valid_token?(%{token_type: "reusable"} = token) do - token.uses < token.max_use and not token.used + def valid_invite?(%{invite_type: "reusable"} = invite) do + invite.uses < invite.max_use and not invite.used end - def valid_token?(%{token_type: "reusable_date_limited"} = token) do - not_overdue_date?(token) and token.uses < token.max_use and not token.used + def valid_invite?(%{invite_type: "reusable_date_limited"} = invite) do + not_overdue_date?(invite) and invite.uses < invite.max_use and not invite.used end - defp not_overdue_date?(%{expire_at: expire_at} = token) do + defp not_overdue_date?(%{expire_at: expire_at} = invite) do Date.compare(Date.utc_today(), expire_at) in [:lt, :eq] || - (Repo.update!(change(token, used: true)) && false) + (update_invite!(invite, %{used: true}) && false) end - def update_usage(%{token_type: "date_limited"}), do: nil - - def update_usage(%{token_type: "one_time"} = token) do - UserInviteToken.mark_as_used(token.token) - end + @spec update_usage!(UserInviteToken.t()) :: nil | UserInviteToken.t() | no_return() + def update_usage!(%{invite_type: "date_limited"}), do: nil - def update_usage(%{token_type: token_type} = token) - when token_type == "reusable" or token_type == "reusable_date_limited" do - new_uses = token.uses + 1 + def update_usage!(%{invite_type: "one_time"} = invite), + do: update_invite!(invite, %{used: true}) + def update_usage!(%{invite_type: invite_type} = invite) + when invite_type == "reusable" or invite_type == "reusable_date_limited" do changes = %{ - uses: new_uses + uses: invite.uses + 1 } changes = - if new_uses >= token.max_use do + if changes.uses >= invite.max_use do Map.put(changes, :used, true) else changes end - change(token, changes) |> Repo.update!() + update_invite!(invite, changes) end end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index a578fbbf4..402fd195f 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -129,7 +129,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def register_user(params) do - token_string = params["token"] + token = params["token"] params = %{ nickname: params["nickname"], @@ -163,29 +163,29 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do {:error, %{error: Jason.encode!(%{captcha: [error]})}} else registrations_open = Pleroma.Config.get([:instance, :registrations_open]) - registration_process(registrations_open, params, token_string) + registration_process(registrations_open, params, token) end end - defp registration_process(_registration_open = true, params, _token_string) do + defp registration_process(_registration_open = true, params, _token) do create_user(params) end - defp registration_process(registration_open, params, token_string) + defp registration_process(registration_open, params, token) when registration_open == false or is_nil(registration_open) do - token = - unless is_nil(token_string) do - Repo.get_by(UserInviteToken, %{token: token_string}) + invite = + unless is_nil(token) do + Repo.get_by(UserInviteToken, %{token: token}) end - valid_token? = token && UserInviteToken.valid_token?(token) + valid_invite? = invite && UserInviteToken.valid_invite?(invite) - case token do + case invite do nil -> {:error, "Invalid token"} - token when valid_token? -> - UserInviteToken.update_usage(token) + invite when valid_invite? -> + UserInviteToken.update_usage!(invite) create_user(params) _ -> -- cgit v1.2.3 From dcc54f8cfab2c3d278ea3f3eb54d866c8436703a Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 6 Apr 2019 20:25:19 +0700 Subject: admin api endpoints for invites --- lib/pleroma/web/admin_api/admin_api_controller.ex | 28 +++++++++++++++++++---- lib/pleroma/web/admin_api/views/account_view.ex | 18 +++++++++++++++ lib/pleroma/web/router.ex | 2 ++ 3 files changed, 44 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 78bf31893..8b74efdd3 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -9,6 +9,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.Search + alias Pleroma.UserInviteToken + import Pleroma.Web.ControllerHelper, only: [json_response: 3] require Logger @@ -235,7 +237,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do with true <- Pleroma.Config.get([:instance, :invites_enabled]) && !Pleroma.Config.get([:instance, :registrations_open]), - {:ok, invite_token} <- Pleroma.UserInviteToken.create_token(), + {:ok, invite_token} <- UserInviteToken.create_invite(), email <- Pleroma.UserEmail.user_invitation_email(user, invite_token, email, params["name"]), {:ok, _} <- Pleroma.Mailer.deliver(email) do @@ -244,11 +246,29 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end @doc "Get a account registeration invite token (base64 string)" - def get_invite_token(conn, _params) do - {:ok, token} = Pleroma.UserInviteToken.create_token() + def get_invite_token(conn, params) do + options = params["invite"] || %{} + {:ok, invite} = UserInviteToken.create_invite(options) conn - |> json(token.token) + |> json(invite.token) + end + + @doc "Get list of created invites" + def invites_list(conn, _params) do + invites = UserInviteToken.list_invites() + + conn + |> json(AccountView.render("invites.json", %{invites: invites})) + end + + @doc "Revokes invite by token" + def invite_revoke(conn, %{"token" => token}) do + invite = UserInviteToken.find_by_token!(token) + {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) + + conn + |> json(AccountView.render("invite.json", %{invite: updated_invite})) end @doc "Get a password reset token (base64 string) for given nickname" diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index 4d6f921ef..fd7917500 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -26,4 +26,22 @@ defmodule Pleroma.Web.AdminAPI.AccountView do "tags" => user.tags || [] } end + + def render("invite.json", %{invite: invite}) do + %{ + "id" => invite.id, + "token" => invite.token, + "used" => invite.used, + "expire_at" => invite.expire_at, + "uses" => invite.uses, + "max_use" => invite.max_use, + "invite_type" => invite.invite_type + } + end + + def render("invites.json", %{invites: invites}) do + %{ + invites: render_many(invites, AccountView, "invite.json", as: :invite) + } + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 1c752e44c..f628baa44 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -163,6 +163,8 @@ defmodule Pleroma.Web.Router do delete("/relay", AdminAPIController, :relay_unfollow) get("/invite_token", AdminAPIController, :get_invite_token) + get("/invites_list", AdminAPIController, :invites_list) + post("/invite_revoke", AdminAPIController, :invite_revoke) post("/email_invite", AdminAPIController, :email_invite) get("/password_reset", AdminAPIController, :get_password_reset) -- cgit v1.2.3 From a53d591ac5bc8f19965f1edc71836e42bab3e393 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 6 Apr 2019 20:47:05 +0700 Subject: code style --- lib/pleroma/web/twitter_api/twitter_api.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 402fd195f..9e9a46cf1 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -167,10 +167,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end end - defp registration_process(_registration_open = true, params, _token) do - create_user(params) - end - defp registration_process(registration_open, params, token) when registration_open == false or is_nil(registration_open) do invite = @@ -193,6 +189,10 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end end + defp registration_process(true, params, _token) do + create_user(params) + end + defp create_user(params) do changeset = User.register_changeset(%User{}, params) -- cgit v1.2.3 From c05fe4da0a9ad119891d2fc6cf82ea3beb59fec7 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Sat, 6 Apr 2019 16:20:06 +0100 Subject: Document subscription endpoints, fix typos Also adds a quick error case on the subscription endpoints to avoid 500s --- .../web/mastodon_api/mastodon_api_controller.ex | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index e848895f1..a7c9c4735 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -864,22 +864,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def subscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %User{} = subscription_target <- User.get_by_id(id) do - {:ok, subscription_target} = User.subscribe(user, subscription_target) - + with %User{} = subscription_target <- User.get_by_id(id), + {:ok, subscription_target} = User.subscribe(user, subscription_target) do conn |> put_view(AccountView) |> render("relationship.json", %{user: user, target: subscription_target}) + else + {:error, message} -> + conn + |> put_resp_content_type("application/json") + |> send_resp(403, Jason.encode!(%{"error" => message})) end end def unsubscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %User{} = subscription_target <- User.get_by_id(id) do - {:ok, subscription_target} = User.unsubscribe(user, subscription_target) - + with %User{} = subscription_target <- User.get_by_id(id), + {:ok, subscription_target} = User.unsubscribe(user, subscription_target) do conn |> put_view(AccountView) |> render("relationship.json", %{user: user, target: subscription_target}) + else + {:error, message} -> + conn + |> put_resp_content_type("application/json") + |> send_resp(403, Jason.encode!(%{"error" => message})) end end -- cgit v1.2.3 From ce8d45713287d8f1c413699385950f295085ee77 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 6 Apr 2019 22:38:35 +0700 Subject: little channges --- lib/mix/tasks/pleroma/user.ex | 58 ++++++++++++++++++++-------------------- lib/pleroma/user_invite_token.ex | 7 +++++ 2 files changed, 36 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 887f45029..80b07d1ac 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -30,16 +30,16 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user invite [OPTION...] Options: - - `--expire_date DATE` - last day on which token is active (e.g. "2019-04-05") - - `--max_use NUMBER` - maximum numbers of token use + - `--expire_at DATE` - last day on which token is active (e.g. "2019-04-05") + - `--max_use NUMBER` - maximum numbers of token uses - ## Generated invites list + ## List generated invites - mix pleroma.user invites_list + mix pleroma.user invites ## Revoke invite - mix pleroma.user invite_revoke TOKEN OR TOKEN_ID + mix pleroma.user revoke_invite TOKEN OR TOKEN_ID ## Delete the user's account. @@ -304,21 +304,24 @@ defmodule Mix.Tasks.Pleroma.User do {options, [], []} = OptionParser.parse(rest, strict: [ - expire_date: :string, + expire_at: :string, max_use: :integer ] ) - expire_at = - with expire_date when expire_date != nil <- Keyword.get(options, :expire_date) do - Date.from_iso8601!(expire_date) - end + options = + options + |> Keyword.update(:expire_at, {:ok, nil}, fn + nil -> {:ok, nil} + val -> Date.from_iso8601(val) + end) + |> Enum.into(%{}) - options = Keyword.put(options, :expire_at, expire_at) - options = Enum.into(options, %{}) Common.start_pleroma() - with {:ok, invite} <- UserInviteToken.create_invite(options) do + with {:ok, val} <- options[:expire_at], + options = Map.put(options, :expire_at, val), + {:ok, invite} <- UserInviteToken.create_invite(options) do Mix.shell().info( "Generated user invite token " <> String.replace(invite.invite_type, "_", " ") ) @@ -332,44 +335,41 @@ defmodule Mix.Tasks.Pleroma.User do IO.puts(url) else - _ -> - Mix.shell().error("Could not create invite token.") + error -> + Mix.shell().error("Could not create invite token: #{inspect(error)}") end end - def run(["invites_list"]) do + def run(["invites"]) do Common.start_pleroma() Mix.shell().info("Invites list:") UserInviteToken.list_invites() |> Enum.each(fn invite -> - expire_date = - case invite.expire_at do - nil -> nil - date -> " | Expire date: #{Date.to_string(date)}" + expire_info = + with expire_at when not is_nil(expire_at) <- invite.expire_at do + " | Expire at: #{Date.to_string(expire_at)}" end using_info = - case invite.max_use do - nil -> nil - max_use -> " | Max use: #{max_use} Left use: #{max_use - invite.uses}" + with max_use when not is_nil(max_use) <- invite.max_use do + " | Max use: #{max_use} Left use: #{max_use - invite.uses}" end Mix.shell().info( - "ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.token_type} | Used: #{ + "ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{ invite.used - }#{expire_date}#{using_info}" + }#{expire_info}#{using_info}" ) end) end - def run(["invite_revoke", token]) do + def run(["revoke_invite", token]) do Common.start_pleroma() - invite = UserInviteToken.find_by_token!(token) - - with {:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do + with {:ok, invite} <- UserInviteToken.find_by_token(token), + {:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do Mix.shell().info("Invite for token #{token} was revoked.") else _ -> Mix.shell().error("No invite found with token #{token}") diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index 4efdbdc32..f08309485 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -71,6 +71,13 @@ defmodule Pleroma.UserInviteToken do @spec find_by_token!(token()) :: UserInviteToken.t() | no_return() def find_by_token!(token), do: Repo.get_by!(UserInviteToken, token: token) + @spec find_by_token(token()) :: {:ok, UserInviteToken.t()} | nil + def find_by_token(token) do + with invite <- Repo.get_by(UserInviteToken, token: token) do + {:ok, invite} + end + end + @spec valid_invite?(UserInviteToken.t()) :: boolean() def valid_invite?(%{invite_type: "one_time"} = invite) do not invite.used -- cgit v1.2.3 From b810aac117563a941b50180f19bca2d96a329a0a Mon Sep 17 00:00:00 2001 From: Alex S Date: Sun, 7 Apr 2019 19:48:52 +0700 Subject: added docs to docs/api/admin_api.md code style and little renamings --- lib/pleroma/web/admin_api/admin_api_controller.ex | 5 ++--- lib/pleroma/web/router.ex | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 8b74efdd3..df729ee02 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.Search - alias Pleroma.UserInviteToken import Pleroma.Web.ControllerHelper, only: [json_response: 3] @@ -255,7 +254,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end @doc "Get list of created invites" - def invites_list(conn, _params) do + def invites(conn, _params) do invites = UserInviteToken.list_invites() conn @@ -263,7 +262,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end @doc "Revokes invite by token" - def invite_revoke(conn, %{"token" => token}) do + def revoke_invite(conn, %{"token" => token}) do invite = UserInviteToken.find_by_token!(token) {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f628baa44..b65eaf357 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -163,8 +163,8 @@ defmodule Pleroma.Web.Router do delete("/relay", AdminAPIController, :relay_unfollow) get("/invite_token", AdminAPIController, :get_invite_token) - get("/invites_list", AdminAPIController, :invites_list) - post("/invite_revoke", AdminAPIController, :invite_revoke) + get("/invites", AdminAPIController, :invites) + post("/revoke_invite", AdminAPIController, :revoke_invite) post("/email_invite", AdminAPIController, :email_invite) get("/password_reset", AdminAPIController, :get_password_reset) -- cgit v1.2.3 From 56c75aec123bc22bd0be94cef627beec324bff15 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sun, 7 Apr 2019 20:59:53 +0700 Subject: credo fix --- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index df729ee02..70a5b5c5d 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -5,10 +5,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do use Pleroma.Web, :controller alias Pleroma.User + alias Pleroma.UserInviteToken alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.Search - alias Pleroma.UserInviteToken import Pleroma.Web.ControllerHelper, only: [json_response: 3] -- cgit v1.2.3 From 76fdfd1c7f10332783ef167b7b996edd4813b1c3 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Sun, 7 Apr 2019 15:11:29 +0100 Subject: Add check on activity visibility in sub notification --- lib/pleroma/web/common_api/utils.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 4e0a6b2d9..a450a70c3 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Endpoint alias Pleroma.Web.MediaProxy @@ -337,13 +338,14 @@ defmodule Pleroma.Web.CommonAPI.Utils do def maybe_notify_subscribers( recipients, - %Activity{data: %{"actor" => actor, "type" => type}} + %Activity{data: %{"actor" => actor, "type" => type}} = activity ) when type == "Create" do with %User{} = user <- User.get_by_ap_id(actor) do subscriber_ids = user |> User.subscribers() + |> Enum.filter(&Visibility.visible_for_user?(activity, &1)) |> Enum.map(& &1.ap_id) recipients ++ subscriber_ids -- cgit v1.2.3 From 012bb5dcc9bfbf6f3ea210ec4e865f3adcea9dfd Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 8 Apr 2019 16:01:28 +0700 Subject: renaming expire_at -> expires_at keyword style change --- lib/mix/tasks/pleroma/user.ex | 14 +++++++------- lib/pleroma/user_invite_token.ex | 12 ++++++------ lib/pleroma/web/admin_api/views/account_view.ex | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 80b07d1ac..441168df2 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -30,7 +30,7 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user invite [OPTION...] Options: - - `--expire_at DATE` - last day on which token is active (e.g. "2019-04-05") + - `--expires_at DATE` - last day on which token is active (e.g. "2019-04-05") - `--max_use NUMBER` - maximum numbers of token uses ## List generated invites @@ -304,14 +304,14 @@ defmodule Mix.Tasks.Pleroma.User do {options, [], []} = OptionParser.parse(rest, strict: [ - expire_at: :string, + expires_at: :string, max_use: :integer ] ) options = options - |> Keyword.update(:expire_at, {:ok, nil}, fn + |> Keyword.update(:expires_at, {:ok, nil}, fn nil -> {:ok, nil} val -> Date.from_iso8601(val) end) @@ -319,8 +319,8 @@ defmodule Mix.Tasks.Pleroma.User do Common.start_pleroma() - with {:ok, val} <- options[:expire_at], - options = Map.put(options, :expire_at, val), + with {:ok, val} <- options[:expires_at], + options = Map.put(options, :expires_at, val), {:ok, invite} <- UserInviteToken.create_invite(options) do Mix.shell().info( "Generated user invite token " <> String.replace(invite.invite_type, "_", " ") @@ -348,8 +348,8 @@ defmodule Mix.Tasks.Pleroma.User do UserInviteToken.list_invites() |> Enum.each(fn invite -> expire_info = - with expire_at when not is_nil(expire_at) <- invite.expire_at do - " | Expire at: #{Date.to_string(expire_at)}" + with expires_at when not is_nil(expires_at) <- invite.expires_at do + " | Expires at: #{Date.to_string(expires_at)}" end using_info = diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index f08309485..11f1dcb16 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -16,7 +16,7 @@ defmodule Pleroma.UserInviteToken do field(:token, :string) field(:used, :boolean, default: false) field(:max_use, :integer) - field(:expire_at, :date) + field(:expires_at, :date) field(:uses, :integer, default: 0) field(:invite_type, :string) @@ -26,7 +26,7 @@ defmodule Pleroma.UserInviteToken do @spec create_invite(map()) :: UserInviteToken.t() def create_invite(params \\ %{}) do %UserInviteToken{} - |> cast(params, ~w(max_use expire_at)a) + |> cast(params, [:max_use, :expires_at]) |> add_token() |> assign_type() |> Repo.insert() @@ -37,11 +37,11 @@ defmodule Pleroma.UserInviteToken do put_change(changeset, :token, token) end - defp assign_type(%{changes: %{max_use: _max_use, expire_at: _expire_at}} = changeset) do + defp assign_type(%{changes: %{max_use: _max_use, expires_at: _expires_at}} = changeset) do put_change(changeset, :invite_type, "reusable_date_limited") end - defp assign_type(%{changes: %{expire_at: _expire_at}} = changeset) do + defp assign_type(%{changes: %{expires_at: _expires_at}} = changeset) do put_change(changeset, :invite_type, "date_limited") end @@ -95,8 +95,8 @@ defmodule Pleroma.UserInviteToken do not_overdue_date?(invite) and invite.uses < invite.max_use and not invite.used end - defp not_overdue_date?(%{expire_at: expire_at} = invite) do - Date.compare(Date.utc_today(), expire_at) in [:lt, :eq] || + defp not_overdue_date?(%{expires_at: expires_at} = invite) do + Date.compare(Date.utc_today(), expires_at) in [:lt, :eq] || (update_invite!(invite, %{used: true}) && false) end diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex index fd7917500..28bb667d8 100644 --- a/lib/pleroma/web/admin_api/views/account_view.ex +++ b/lib/pleroma/web/admin_api/views/account_view.ex @@ -32,7 +32,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do "id" => invite.id, "token" => invite.token, "used" => invite.used, - "expire_at" => invite.expire_at, + "expires_at" => invite.expires_at, "uses" => invite.uses, "max_use" => invite.max_use, "invite_type" => invite.invite_type -- cgit v1.2.3 From 13ff312c48c338c93ee9aa85ec2e48c2059d5168 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 8 Apr 2019 12:46:12 +0100 Subject: Sever subscription in case of block --- lib/pleroma/user.ex | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f1565ade7..9a80601c1 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -924,14 +924,23 @@ defmodule Pleroma.User do end def subscribe(subscriber, %{ap_id: ap_id}) do - with %User{} = user <- get_or_fetch_by_ap_id(ap_id) do - info_cng = - user.info - |> User.Info.add_to_subscribers(subscriber.ap_id) + user_config = Application.get_env(:pleroma, :user) + deny_follow_blocked = Keyword.get(user_config, :deny_follow_blocked) - change(user) - |> put_embed(:info, info_cng) - |> update_and_set_cache() + with %User{} = subscribed <- get_or_fetch_by_ap_id(ap_id) do + blocked = blocks?(subscribed, subscriber) and deny_follow_blocked + + if blocked do + {:error, "Could not subscribe: #{subscribed.nickname} is blocking you"} + else + info_cng = + subscribed.info + |> User.Info.add_to_subscribers(subscriber.ap_id) + + change(subscribed) + |> put_embed(:info, info_cng) + |> update_and_set_cache() + end end end @@ -957,6 +966,14 @@ defmodule Pleroma.User do blocker end + blocker = + if subscribed_to?(blocked, blocker) do + {:ok, blocker} = unsubscribe(blocked, blocker) + blocker + else + blocker + end + if following?(blocked, blocker) do unfollow(blocked, blocker) end -- cgit v1.2.3 From 87a01f9ee061d513ede1a18ab494778f4b2eb3a8 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 8 Apr 2019 13:04:30 +0100 Subject: Use Pleroma.Config instead of Application.get_env --- lib/pleroma/user.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 9a80601c1..15f606c5f 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -924,8 +924,7 @@ defmodule Pleroma.User do end def subscribe(subscriber, %{ap_id: ap_id}) do - user_config = Application.get_env(:pleroma, :user) - deny_follow_blocked = Keyword.get(user_config, :deny_follow_blocked) + deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) with %User{} = subscribed <- get_or_fetch_by_ap_id(ap_id) do blocked = blocks?(subscribed, subscriber) and deny_follow_blocked -- cgit v1.2.3 From d0696fdfd6acaee011f4011d69b8221448bfa89e Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 8 Apr 2019 19:16:59 +0700 Subject: fix for elixir 1.7.4 --- lib/pleroma/user_invite_token.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index 11f1dcb16..6247831d5 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -10,6 +10,7 @@ defmodule Pleroma.UserInviteToken do alias Pleroma.Repo alias Pleroma.UserInviteToken + @type t :: %__MODULE__{} @type token :: String.t() schema "user_invite_tokens" do -- cgit v1.2.3 From fee50636d07c54328ececfe8805c658e3bb80cc6 Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 8 Apr 2019 20:08:16 +0700 Subject: removing not needed invite update --- lib/pleroma/user_invite_token.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index 6247831d5..86f0a5486 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -96,9 +96,8 @@ defmodule Pleroma.UserInviteToken do not_overdue_date?(invite) and invite.uses < invite.max_use and not invite.used end - defp not_overdue_date?(%{expires_at: expires_at} = invite) do - Date.compare(Date.utc_today(), expires_at) in [:lt, :eq] || - (update_invite!(invite, %{used: true}) && false) + defp not_overdue_date?(%{expires_at: expires_at}) do + Date.compare(Date.utc_today(), expires_at) in [:lt, :eq] end @spec update_usage!(UserInviteToken.t()) :: nil | UserInviteToken.t() | no_return() -- cgit v1.2.3 From 589629cf3e1bee9a4f6e92b8456d8614eff73c89 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 8 Apr 2019 15:56:14 +0100 Subject: Used cached user resources in subscriptions --- lib/pleroma/user.ex | 4 ++-- lib/pleroma/web/common_api/utils.ex | 2 +- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 15f606c5f..8a0243604 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -926,7 +926,7 @@ defmodule Pleroma.User do def subscribe(subscriber, %{ap_id: ap_id}) do deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) - with %User{} = subscribed <- get_or_fetch_by_ap_id(ap_id) do + with %User{} = subscribed <- get_cached_by_ap_id(ap_id) do blocked = blocks?(subscribed, subscriber) and deny_follow_blocked if blocked do @@ -944,7 +944,7 @@ defmodule Pleroma.User do end def unsubscribe(unsubscriber, %{ap_id: ap_id}) do - with %User{} = user <- get_or_fetch_by_ap_id(ap_id) do + with %User{} = user <- get_cached_by_ap_id(ap_id) do info_cng = user.info |> User.Info.remove_from_subscribers(unsubscriber.ap_id) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index a450a70c3..a830ea5d2 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -341,7 +341,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do %Activity{data: %{"actor" => actor, "type" => type}} = activity ) when type == "Create" do - with %User{} = user <- User.get_by_ap_id(actor) do + with %User{} = user <- User.get_cached_by_ap_id(actor) do subscriber_ids = user |> User.subscribers() diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index a7c9c4735..d9c0cd55e 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -864,7 +864,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def subscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %User{} = subscription_target <- User.get_by_id(id), + with %User{} = subscription_target <- User.get_cached_by_id(id), {:ok, subscription_target} = User.subscribe(user, subscription_target) do conn |> put_view(AccountView) @@ -878,7 +878,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def unsubscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %User{} = subscription_target <- User.get_by_id(id), + with %User{} = subscription_target <- User.get_cached_by_id(id), {:ok, subscription_target} = User.unsubscribe(user, subscription_target) do conn |> put_view(AccountView) -- cgit v1.2.3 From b57b43027cf958d3a3a82b95f155ae27b235b543 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 9 Apr 2019 23:20:31 +0300 Subject: Change response format of /api/pleroma/emoji to the one that actually makes sense --- lib/pleroma/web/twitter_api/controllers/util_controller.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 26407aebd..e6057e072 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -286,8 +286,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do emoji = Emoji.get_all() |> Enum.map(fn {short_code, path, tags} -> - %{short_code => %{image_url: path, tags: String.split(tags, ",")}} + {short_code, %{image_url: path, tags: String.split(tags, ",")}} end) + |> Enum.into(%{}) json(conn, emoji) end -- cgit v1.2.3 From cf9ba8fe1b5a701488889c4bfdde46e7f00b9ebc Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 10 Apr 2019 02:32:04 +0200 Subject: transmogrifier.ex: Add fix_summary/1 MRF.KeywordPolicy assumes that summary is present in a activity, and this would probably simplify code elsewhere too anyway. --- lib/pleroma/web/activity_pub/transmogrifier.ex | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index f733ae7e1..9d4cbab0b 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -83,6 +83,22 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> fix_content_map |> fix_likes |> fix_addressing + |> fix_summary + end + + def fix_summary(%{"summary" => nil} = object) do + object + |> Map.put("summary", "") + end + + def fix_summary(%{"summary" => _} = object) do + # summary is present, nothing to do + object + end + + def fix_summary(object) do + object + |> Map.put("summary", "") end def fix_addressing_list(map, field) do -- cgit v1.2.3