From 9ad0c9b3fdbef933ccf6d0ec050b88a5c7e929d4 Mon Sep 17 00:00:00 2001 From: Ro Date: Mon, 18 Nov 2024 18:27:25 -0600 Subject: [PATCH] feat: Like and unlike posts --- README.md | 4 +- lib/postland/activities.ex | 37 +++++++++++++++++++ lib/postland/object.ex | 11 ++++++ .../components/core_components.ex | 9 +++++ lib/postland_web/live/timeline_live.ex | 26 +++++++++++++ .../20241118235445_add_my_like_id.exs | 9 +++++ 6 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 priv/repo/migrations/20241118235445_add_my_like_id.exs diff --git a/README.md b/README.md index 2eafa4d..9ca983a 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ - [x] Show the actor avatar and display name - [x] Receiving posts w/ images - [ ] Receiving posts w/ videos -- [ ] Liking posts -- [ ] Unliking posts +- [x] Liking posts +- [x] Unliking posts - [x] Displaying CW posts behind CW - [ ] Displaying polls - [ ] Voting in polls diff --git a/lib/postland/activities.ex b/lib/postland/activities.ex index b0c758f..a3f2687 100644 --- a/lib/postland/activities.ex +++ b/lib/postland/activities.ex @@ -8,6 +8,7 @@ defmodule Postland.Activities do alias Postland.Activity alias Postland.Repo alias Postland.Follows + alias Postland.Object def record_markdown_post(markdown, cw, attachments) do id = Ecto.UUID.autogenerate() @@ -82,6 +83,42 @@ defmodule Postland.Activities do |> broadcast_to_followers(activity) end + def like_post(%{id: post_id} = post) do + like_id = url(~p"/activities/#{Ecto.UUID.autogenerate()}") + + activity = + %{ + "id" => like_id, + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Like", + "actor" => Postland.my_actor_id(), + "object" => post_id + } + + Multi.new() + |> Multi.insert(:activity, Activity.changeset(activity)) + |> Multi.update(:update_meta_i_liked, Object.like_changeset(post, like_id)) + |> Repo.transaction() + |> broadcast_to_followers(activity) + end + + def unlike_post(%{my_like_id: like_id} = post) do + activity = + %{ + "id" => url(~p"/activities/#{Ecto.UUID.autogenerate()}"), + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Undo", + "actor" => Postland.my_actor_id(), + "object" => like_id + } + + Multi.new() + |> Multi.insert(:activity, Activity.changeset(activity)) + |> Multi.update(:object, Object.unlike_changeset(post)) + |> Repo.transaction() + |> broadcast_to_followers(activity) + end + def broadcast_to_followers({:ok, _} = result, activity) do my_actor_id = Postland.my_actor_id() private_key = Postland.Accounts.solo_user().private_key diff --git a/lib/postland/object.ex b/lib/postland/object.ex index 383301c..c1015bc 100644 --- a/lib/postland/object.ex +++ b/lib/postland/object.ex @@ -7,6 +7,7 @@ defmodule Postland.Object do schema "objects" do field :type, :string field :data, :map + field :my_like_id, :string timestamps() end @@ -24,4 +25,14 @@ defmodule Postland.Object do |> validate_required(:data) |> validate_required(:type) end + + def like_changeset(post, like_id) do + post + |> cast(%{"my_like_id" => like_id}, [:my_like_id]) + end + + def unlike_changeset(post) do + post + |> cast(%{"my_like_id" => nil}, [:my_like_id]) + end end diff --git a/lib/postland_web/components/core_components.ex b/lib/postland_web/components/core_components.ex index dab06f7..3353dab 100644 --- a/lib/postland_web/components/core_components.ex +++ b/lib/postland_web/components/core_components.ex @@ -253,6 +253,15 @@ defmodule PostlandWeb.CoreComponents do > <.icon name="hero-trash" /> + + <.icon name="hero-star" /> + diff --git a/lib/postland_web/live/timeline_live.ex b/lib/postland_web/live/timeline_live.ex index 7d96e0f..8795dcd 100644 --- a/lib/postland_web/live/timeline_live.ex +++ b/lib/postland_web/live/timeline_live.ex @@ -73,6 +73,32 @@ defmodule PostlandWeb.TimelineLive do end end + def handle_event("like_post", %{"post-id" => id, "post-dom-id" => dom_id}, socket) do + post = Objects.get_by_id(id) + + case Activities.like_post(post) do + {:ok, _} -> + post = Objects.get_by_id(id) + {:noreply, socket |> stream_insert(:posts, post)} + + _ -> + {:noreply, socket |> put_flash(:error, "An unexpected error has occurred.")} + end + end + + def handle_event("unlike_post", %{"post-id" => id, "post-dom-id" => dom_id}, socket) do + post = Objects.get_by_id(id) + + case Activities.unlike_post(post) do + {:ok, _} -> + post = Objects.get_by_id(id) + {:noreply, socket |> stream_insert(:posts, post)} + + _ -> + {:noreply, socket |> put_flash(:error, "An unexpected error has occurred.")} + end + end + def handle_event("change_post", %{"post" => post} = params, socket) do cw = Map.get(params, "cw") {:noreply, socket |> assign(post: post, cw: cw)} diff --git a/priv/repo/migrations/20241118235445_add_my_like_id.exs b/priv/repo/migrations/20241118235445_add_my_like_id.exs new file mode 100644 index 0000000..fd8e4bc --- /dev/null +++ b/priv/repo/migrations/20241118235445_add_my_like_id.exs @@ -0,0 +1,9 @@ +defmodule Postland.Repo.Migrations.AddMyLikeId do + use Ecto.Migration + + def change do + alter table("objects") do + add :my_like_id, :string + end + end +end