Browse Source

Add replying to statuses

master
Shadowfacts 1 year ago
parent
commit
7d071d971c
Signed by: shadowfacts GPG Key ID: 94A5AB95422746E5
6 changed files with 116 additions and 10 deletions
  1. +3
    -0
      lib/clacks/activitypub.ex
  2. +21
    -1
      lib/clacks_web/controllers/activities_controller.ex
  3. +80
    -7
      lib/clacks_web/controllers/frontend_controller.ex
  4. +3
    -2
      lib/clacks_web/router.ex
  5. +1
    -0
      lib/clacks_web/templates/frontend/_status.html.eex
  6. +8
    -0
      lib/clacks_web/templates/frontend/status.html.eex

+ 3
- 0
lib/clacks/activitypub.ex View File

@ -32,6 +32,7 @@ defmodule Clacks.ActivityPub do
actor :: String.t(),
html :: String.t(),
context :: String.t() | nil,
in_reply_to :: String.t() | nil,
id :: String.t() | nil,
published :: DateTime.t(),
to :: [String.t()],
@ -41,6 +42,7 @@ defmodule Clacks.ActivityPub do
actor,
html,
context \\ nil,
in_reply_to \\ nil,
id \\ nil,
published \\ DateTime.utc_now(),
to \\ [@public],
@ -61,6 +63,7 @@ defmodule Clacks.ActivityPub do
"content" => html,
"conversation" => context,
"context" => context,
"inReplyTo" => in_reply_to,
"published" => published |> DateTime.to_iso8601()
}
end


+ 21
- 1
lib/clacks_web/controllers/activities_controller.ex View File

@ -18,7 +18,27 @@ defmodule ClacksWeb.ActivitiesController do
end
_ ->
resp(conn, 404, "Not Found")
case conn.assigns[:format] do
"activity+json" ->
conn
|> put_status(404)
|> json(%{error: "Not Found"})
"html" ->
resp(conn, 404, "Not Found")
end
end
end
def get_status(conn, %{"id" => status_id}) do
case Activity.get(status_id) do
%Activity{local: true, data: data} ->
json(conn, data)
_ ->
conn
|> put_status(404)
|> json(%{error: "Not Found"})
end
end
end

+ 80
- 7
lib/clacks_web/controllers/frontend_controller.ex View File

@ -4,6 +4,8 @@ defmodule ClacksWeb.FrontendController do
alias ClacksWeb.Router.Helpers, as: Routes
alias ClacksWeb.Endpoint
@public "https://www.w3.org/ns/activitystreams#Public"
def index(%Plug.Conn{assigns: %{user: user}} = conn, params) do
user = Repo.preload(user, :actor)
@ -48,23 +50,67 @@ defmodule ClacksWeb.FrontendController do
with %Activity{
local: true,
data:
%{
"type" => "Create",
"object" => %{"type" => "Note", "attributedTo" => author_id} = note
} = data
} <- Activity.get(id),
%Actor{} = author <- Actor.get_by_ap_id(author_id) do
case conn.assigns[:format] do
"activity+json" ->
json(conn, data)
"html" ->
render(conn, "status.html", %{
current_user: current_user,
note: note,
author: author
})
end
else
nil ->
case conn.assigns[:format] do
"activity+json" ->
conn
|> put_status(404)
|> json(%{error: "Not Found"})
"html" ->
resp(conn, 404, "Not Found")
end
%Activity{local: false, data: %{"id" => ap_id}} ->
case conn.assigns[:format] do
"activity+json" ->
conn
|> put_status(404)
|> json(%{error: "Not Found"})
"html" ->
redirect(conn, external: ap_id)
end
end
end
def reply(conn, %{"id" => id}) do
current_user = conn.assigns[:user]
with %Activity{
data: %{
"type" => "Create",
"object" => %{"type" => "Note", "attributedTo" => author_id} = note
}
} <- Activity.get(id),
%Actor{} = author <- Actor.get_by_ap_id(author_id) do
render(conn, "status.html", %{
render(conn, "reply.html", %{
current_user: current_user,
note: note,
author: author
})
else
nil ->
put_status(conn, 404)
%Activity{local: false, data: %{"id" => ap_id}} ->
redirect(conn, external: ap_id)
_ ->
resp(conn, 404, "Not Found")
end
end
@ -89,7 +135,7 @@ defmodule ClacksWeb.FrontendController do
def post_status(conn, %{"content" => content} = params) do
current_user = conn.assigns[:user] |> Repo.preload(:actor)
note = ActivityPub.note(current_user.actor.ap_id, content)
note = note_for_posting(current_user, params)
note_changeset = Object.changeset_for_creating(note)
{:ok, object} = Repo.insert(note_changeset)
@ -104,4 +150,31 @@ defmodule ClacksWeb.FrontendController do
path = Map.get(params, "continue", Routes.frontend_path(Endpoint, :status, activity.id))
redirect(conn, to: path)
end
defp note_for_posting(current_user, %{"content" => content, "in_reply_to" => in_reply_to_ap_id}) do
with %Activity{data: %{"context" => context, "actor" => in_reply_to_actor}} <-
Activity.get_by_ap_id(in_reply_to_ap_id) do
to = [in_reply_to_actor, @public]
# todo: followers
cc = []
ActivityPub.note(
current_user.actor.ap_id,
content,
context,
in_reply_to_ap_id,
nil,
DateTime.utc_now(),
to,
cc
)
else
_ ->
ActivityPub.note(current_user.actor.ap_id, content)
end
end
defp note_for_posting(current_user, %{"content" => content}) do
ActivityPub.note(current_user.actor.ap_id, content)
end
end

+ 3
- 2
lib/clacks_web/router.ex View File

@ -51,13 +51,13 @@ defmodule ClacksWeb.Router do
pipe_through :browser_maybe_authenticated
get "/", FrontendController, :index
get "/status/:id", FrontendController, :status
post "/post", FrontendController, :post_status
end
scope "/", ClacksWeb do
pipe_through :browser
pipe_through :browser_authenticated
post "/post", FrontendController, :post_status
end
scope "/", ClacksWeb do
@ -80,6 +80,7 @@ defmodule ClacksWeb.Router do
get "/users/:username", ActorController, :get
get "/activities/:id", ActivitiesController, :get
get "/objects/:id", ObjectsController, :get
get "/status/:id", FrontendController, :status
end
# Other scopes may use custom stacks.


+ 1
- 0
lib/clacks_web/templates/frontend/_status.html.eex View File

@ -9,6 +9,7 @@
<%= @author.data["name"] %>
</a>
</h3>
<a href="<%= @note["url"] %>">Permalink</a>
<div class="status-content">
<%= @note["content"] %>
</div>


+ 8
- 0
lib/clacks_web/templates/frontend/status.html.eex View File

@ -1 +1,9 @@
<%= render "_status.html", author: @author, note: @note %>
<hr>
<%= form_tag Routes.frontend_path(@conn, :post_status), method: :post do %>
<input type="hidden" name="in_reply_to" value="<%= @note["id"] %>">
<textarea id="content" name="content" cols="30" rows="10" placeholder="Reply"></textarea>
<%= submit "Post" %>
<% end %>

Loading…
Cancel
Save