diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1468cc133..aced21ece 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -39,6 +39,7 @@ defmodule Pleroma.User do field(:follower_address, :string) field(:search_rank, :float, virtual: true) field(:tags, {:array, :string}, default: []) + field(:bookmarks, {:array, :string}, default: []) field(:last_refreshed_at, :naive_datetime) has_many(:notifications, Notification) embeds_one(:info, Pleroma.User.Info) @@ -1156,6 +1157,22 @@ defp update_tags(%User{} = user, new_tags) do updated_user end + def bookmark(%User{} = user, status_id) do + bookmarks = Enum.uniq(user.bookmarks ++ [status_id]) + update_bookmarks(user, bookmarks) + end + + def unbookmark(%User{} = user, status_id) do + bookmarks = Enum.uniq(user.bookmarks -- [status_id]) + update_bookmarks(user, bookmarks) + end + + def update_bookmarks(%User{} = user, bookmarks) do + user + |> change(%{bookmarks: bookmarks}) + |> update_and_set_cache + end + defp normalize_tags(tags) do [tags] |> List.flatten() diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index a366a149f..2530b51d2 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -424,6 +424,28 @@ def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do end end + def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Repo.get(Activity, id), + %User{} = user <- User.get_by_nickname(user.nickname), + true <- ActivityPub.visible_for_user?(activity, user), + {:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do + conn + |> put_view(StatusView) + |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + end + end + + def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Activity{} = activity <- Repo.get(Activity, id), + %User{} = user <- User.get_by_nickname(user.nickname), + true <- ActivityPub.visible_for_user?(activity, user), + {:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do + conn + |> put_view(StatusView) + |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + end + end + def notifications(%{assigns: %{user: user}} = conn, params) do notifications = Notification.for_user(user, params) @@ -859,6 +881,19 @@ def favourites(%{assigns: %{user: user}} = conn, params) do |> render("index.json", %{activities: activities, for: user, as: :activity}) end + def bookmarks(%{assigns: %{user: user}} = conn, _) do + user = Repo.get(User, user.id) + + activities = + user.bookmarks + |> Enum.map(fn id -> Activity.get_create_by_object_ap_id(id) end) + |> Enum.reverse() + + conn + |> put_view(StatusView) + |> render("index.json", %{activities: activities, for: user, as: :activity}) + end + def get_lists(%{assigns: %{user: user}} = conn, opts) do lists = Pleroma.List.for_user(user, opts) res = ListView.render("lists.json", lists: lists) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 0f2679444..0b6a9d9fc 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -88,6 +88,7 @@ def render( favourites_count: 0, reblogged: false, favourited: false, + bookmarked: false, muted: false, pinned: pinned?(activity, user), sensitive: false, @@ -122,6 +123,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || []) favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || []) + bookmarked = opts[:for] && object["id"] in opts[:for].bookmarks attachment_data = object["attachment"] || [] attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) @@ -155,6 +157,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} favourites_count: like_count, reblogged: present?(repeated), favourited: present?(favorited), + bookmarked: present?(bookmarked), muted: false, pinned: pinned?(activity, user), sensitive: sensitive, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 31f739738..3d0227582 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -185,6 +185,7 @@ defmodule Pleroma.Web.Router do get("/timelines/direct", MastodonAPIController, :dm_timeline) get("/favourites", MastodonAPIController, :favourites) + get("/bookmarks", MastodonAPIController, :bookmarks) post("/statuses", MastodonAPIController, :post_status) delete("/statuses/:id", MastodonAPIController, :delete_status) @@ -195,6 +196,8 @@ defmodule Pleroma.Web.Router do post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status) post("/statuses/:id/pin", MastodonAPIController, :pin_status) post("/statuses/:id/unpin", MastodonAPIController, :unpin_status) + post("/statuses/:id/bookmark", MastodonAPIController, :bookmark_status) + post("/statuses/:id/unbookmark", MastodonAPIController, :unbookmark_status) post("/notifications/clear", MastodonAPIController, :clear_notifications) post("/notifications/dismiss", MastodonAPIController, :dismiss_notification) diff --git a/priv/repo/migrations/20181214121049_add_bookmarks_to_users.exs b/priv/repo/migrations/20181214121049_add_bookmarks_to_users.exs new file mode 100644 index 000000000..55e97ae0e --- /dev/null +++ b/priv/repo/migrations/20181214121049_add_bookmarks_to_users.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddBookmarksToUsers do + use Ecto.Migration + + def change do + alter table(:users) do + add :bookmarks, {:array, :string}, null: false, default: [] + end + end +end diff --git a/test/user_test.exs b/test/user_test.exs index a0657c7b6..b33398ff6 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -945,4 +945,31 @@ test "preserves hosts in user links text" do assert expected_text == User.parse_bio(bio, user) end end + + test "bookmarks" do + user = insert(:user) + + {:ok, activity1} = + CommonAPI.post(user, %{ + "status" => "heweoo!" + }) + + id1 = activity1.data["object"]["id"] + + {:ok, activity2} = + CommonAPI.post(user, %{ + "status" => "heweoo!" + }) + + id2 = activity2.data["object"]["id"] + + assert {:ok, user_state1} = User.bookmark(user, id1) + assert user_state1.bookmarks == [id1] + + assert {:ok, user_state2} = User.unbookmark(user, id1) + assert user_state2.bookmarks == [] + + assert {:ok, user_state3} = User.bookmark(user, id2) + assert user_state3.bookmarks == [id2] + end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b8f901e6c..edc74d802 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1669,4 +1669,55 @@ test "Status rich-media Card", %{conn: conn, user: user} do } end end + + test "bookmarks" do + user = insert(:user) + for_user = insert(:user) + + {:ok, activity1} = + CommonAPI.post(user, %{ + "status" => "heweoo?" + }) + + {:ok, activity2} = + CommonAPI.post(user, %{ + "status" => "heweoo!" + }) + + response1 = + build_conn() + |> assign(:user, for_user) + |> post("/api/v1/statuses/#{activity1.id}/bookmark") + + assert json_response(response1, 200)["bookmarked"] == true + + response2 = + build_conn() + |> assign(:user, for_user) + |> post("/api/v1/statuses/#{activity2.id}/bookmark") + + assert json_response(response2, 200)["bookmarked"] == true + + bookmarks = + build_conn() + |> assign(:user, for_user) + |> get("/api/v1/bookmarks") + + assert [json_response(response2, 200), json_response(response1, 200)] == + json_response(bookmarks, 200) + + response1 = + build_conn() + |> assign(:user, for_user) + |> post("/api/v1/statuses/#{activity1.id}/unbookmark") + + assert json_response(response1, 200)["bookmarked"] == false + + bookmarks = + build_conn() + |> assign(:user, for_user) + |> get("/api/v1/bookmarks") + + assert [json_response(response2, 200)] == json_response(bookmarks, 200) + end end diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs index ebf6273e8..f054ded1c 100644 --- a/test/web/mastodon_api/status_view_test.exs +++ b/test/web/mastodon_api/status_view_test.exs @@ -91,6 +91,7 @@ test "a note activity" do replies_count: 0, favourites_count: 0, reblogged: false, + bookmarked: false, favourited: false, muted: false, pinned: false,