Compare commits
No commits in common. "fd336f0bed2d777664b09330502719e1fb45b1ad" and "a2ddde09f7ac7c8fc750178707c91b743fb05c6c" have entirely different histories.
fd336f0bed
...
a2ddde09f7
|
@ -97,8 +97,7 @@ header {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.status-list,
|
ul.status-list {
|
||||||
ul.notifications-list {
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
@ -112,16 +111,11 @@ ul.notifications-list {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status, .notification {
|
.status {
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
background-color: #f2f2f2;
|
background-color: #f2f2f2;
|
||||||
|
|
||||||
.status-announcer {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-meta {
|
.status-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -132,12 +126,8 @@ ul.notifications-list {
|
||||||
.status-meta-right {
|
.status-meta-right {
|
||||||
display: inline;
|
display: inline;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-author-nickname,
|
|
||||||
.status-author-username {
|
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-author-username {
|
.status-author-username {
|
||||||
|
@ -161,18 +151,6 @@ ul.notifications-list {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification {
|
|
||||||
.notification-info, .notification-info-right {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-info-right {
|
|
||||||
flex-grow: 1;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-status {
|
.compose-status {
|
||||||
textarea {
|
textarea {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule Clacks.Inbox do
|
defmodule Clacks.Inbox do
|
||||||
require Logger
|
require Logger
|
||||||
alias Clacks.{Repo, Activity, Object, Actor, ActivityPub, Notification}
|
alias Clacks.{Repo, Activity, Object, Actor, ActivityPub}
|
||||||
|
|
||||||
defp store_activity(%{"actor" => actor, "id" => ap_id} = activity, local \\ false)
|
defp store_activity(%{"actor" => actor, "id" => ap_id} = activity, local \\ false)
|
||||||
when is_binary(actor) do
|
when is_binary(actor) do
|
||||||
|
@ -11,15 +11,7 @@ defmodule Clacks.Inbox do
|
||||||
actor: actor
|
actor: actor
|
||||||
})
|
})
|
||||||
|
|
||||||
case Repo.insert_or_update(changeset) do
|
Repo.insert_or_update(changeset)
|
||||||
{:ok, activity} ->
|
|
||||||
Notification.process_notifications_for_incoming(activity)
|
|
||||||
|
|
||||||
{:ok, activity}
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
{:error, reason}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec handle(activity :: map()) :: :ok | {:error, reason :: any()}
|
@spec handle(activity :: map()) :: :ok | {:error, reason :: any()}
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
defmodule Clacks.Notification do
|
|
||||||
use Ecto.Schema
|
|
||||||
import Ecto.Changeset
|
|
||||||
alias Clacks.{Activity, Actor, Repo}
|
|
||||||
|
|
||||||
@type t() :: %__MODULE__{}
|
|
||||||
|
|
||||||
@valid_types ["follow", "mention", "announce", "like"]
|
|
||||||
|
|
||||||
schema "notifications" do
|
|
||||||
field :type, :string
|
|
||||||
|
|
||||||
belongs_to :user, Clacks.User
|
|
||||||
belongs_to :activity, Clacks.Activity, type: FlakeId.Ecto.Type
|
|
||||||
|
|
||||||
timestamps()
|
|
||||||
end
|
|
||||||
|
|
||||||
def changeset(%__MODULE__{} = schema, attrs) do
|
|
||||||
schema
|
|
||||||
|> cast(attrs, [:type, :user_id, :activity_id])
|
|
||||||
|> validate_required([:type, :user_id])
|
|
||||||
|> validate_inclusion(:type, @valid_types)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec create(type :: String.t(), activity :: Activity.t(), actor :: Actor.t()) ::
|
|
||||||
{:ok, Notification.t()} | {:error, any()}
|
|
||||||
|
|
||||||
def create(type, _, _) when not (type in @valid_types) do
|
|
||||||
{:error, "invalid notification type '#{type}'"}
|
|
||||||
end
|
|
||||||
|
|
||||||
def create(type, activity, actor) do
|
|
||||||
changeset =
|
|
||||||
changeset(%__MODULE__{}, %{
|
|
||||||
type: type,
|
|
||||||
user_id: actor.user_id,
|
|
||||||
activity_id: activity.id
|
|
||||||
})
|
|
||||||
|
|
||||||
Repo.insert(changeset)
|
|
||||||
end
|
|
||||||
|
|
||||||
def process_notifications_for_incoming(
|
|
||||||
%Activity{
|
|
||||||
data: %{"type" => "Follow", "object" => followee_ap_id}
|
|
||||||
} = activity
|
|
||||||
) do
|
|
||||||
case Actor.get_cached_by_ap_id(followee_ap_id) do
|
|
||||||
%Actor{local: true} = followee ->
|
|
||||||
create("follow", activity, followee)
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def process_notifications_for_incoming(
|
|
||||||
%Activity{data: %{"type" => "Create", "object" => %{"type" => "Note", "tag" => tags}}} =
|
|
||||||
activity
|
|
||||||
) do
|
|
||||||
Enum.each(tags, fn %{"href" => mentioned_actor_id} ->
|
|
||||||
case Actor.get_cached_by_ap_id(mentioned_actor_id) do
|
|
||||||
%Actor{local: true} = mentioned_actor ->
|
|
||||||
create("mention", activity, mentioned_actor)
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
def process_notifications_for_incoming(
|
|
||||||
%Activity{data: %{"type" => type, "object" => original_object_ap_id}} = activity
|
|
||||||
)
|
|
||||||
when type in ["Announce", "Like"] do
|
|
||||||
with %Activity{local: true, actor: local_actor_id} <-
|
|
||||||
Activity.get_by_object_ap_id(original_object_ap_id),
|
|
||||||
%Actor{local: true} = original_activity_actor <-
|
|
||||||
Actor.get_cached_by_ap_id(local_actor_id) do
|
|
||||||
create(String.downcase(type), activity, original_activity_actor)
|
|
||||||
else
|
|
||||||
_ ->
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def process_notifications_for_incoming(_), do: :ok
|
|
||||||
end
|
|
|
@ -1,18 +1,17 @@
|
||||||
defmodule Clacks.Timeline do
|
defmodule Clacks.Timeline do
|
||||||
alias Clacks.{Repo, Actor, Activity, User, Notification}
|
alias Clacks.{Repo, Actor, Activity, User}
|
||||||
import Clacks.Paginator
|
import Clacks.Paginator
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||||
@timeline_types ["Create", "Announce"]
|
@timeline_types ["Create", "Announce"]
|
||||||
@notification_types ["Create", "Announce", "Like", "Follow"]
|
|
||||||
|
|
||||||
@spec actor_timeline(
|
@spec actor_timeline(
|
||||||
actor :: Actor.t(),
|
actor :: Actor.t(),
|
||||||
params :: map(),
|
params :: map(),
|
||||||
only_public :: boolean()
|
only_public :: boolean()
|
||||||
) :: [
|
) :: [
|
||||||
{Activity.t(), Actor.t(), {Activity.t() | nil, Actor.t() | nil}}
|
Activity.t()
|
||||||
]
|
]
|
||||||
def actor_timeline(actor, params, only_public \\ true) do
|
def actor_timeline(actor, params, only_public \\ true) do
|
||||||
Activity
|
Activity
|
||||||
|
@ -21,16 +20,11 @@ defmodule Clacks.Timeline do
|
||||||
|> restrict_to_public(only_public)
|
|> restrict_to_public(only_public)
|
||||||
|> paginate(params)
|
|> paginate(params)
|
||||||
|> limit(^Map.get(params, "limit", 20))
|
|> limit(^Map.get(params, "limit", 20))
|
||||||
|> join_with_announced_or_liked()
|
|
||||||
|> select(
|
|
||||||
[activity, announced, announced_actor],
|
|
||||||
{activity, {announced, announced_actor}}
|
|
||||||
)
|
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec home_timeline(user :: User.t(), params :: map()) :: [
|
@spec home_timeline(user :: User.t(), params :: map()) :: [
|
||||||
{Activity.t(), Actor.t(), {Activity.t() | nil, Actor.t() | nil}}
|
{Activity.t(), Actor.t()}
|
||||||
]
|
]
|
||||||
def home_timeline(user, params) do
|
def home_timeline(user, params) do
|
||||||
user =
|
user =
|
||||||
|
@ -52,17 +46,10 @@ defmodule Clacks.Timeline do
|
||||||
|> restrict_to_types(@timeline_types)
|
|> restrict_to_types(@timeline_types)
|
||||||
|> paginate(params)
|
|> paginate(params)
|
||||||
|> limit(^Map.get(params, "limit", 20))
|
|> limit(^Map.get(params, "limit", 20))
|
||||||
|> join_with_announced_or_liked()
|
|
||||||
|> select(
|
|
||||||
[activity, actor, announced, announced_actor],
|
|
||||||
{activity, actor, {announced, announced_actor}}
|
|
||||||
)
|
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec local_timeline(params :: map()) :: [
|
@spec local_timeline(params :: map()) :: [{Activity.t(), Actor.t()}]
|
||||||
{Activity.t(), Actor.t(), {Activity.t() | nil, Actor.t() | nil}}
|
|
||||||
]
|
|
||||||
def local_timeline(params) do
|
def local_timeline(params) do
|
||||||
Activity
|
Activity
|
||||||
|> where([a], a.local)
|
|> where([a], a.local)
|
||||||
|
@ -71,44 +58,9 @@ defmodule Clacks.Timeline do
|
||||||
|> paginate(params)
|
|> paginate(params)
|
||||||
|> limit(^Map.get(params, "limit", 20))
|
|> limit(^Map.get(params, "limit", 20))
|
||||||
|> join_with_actors()
|
|> join_with_actors()
|
||||||
|> join_with_announced_or_liked()
|
|
||||||
|> select(
|
|
||||||
[activity, actor, announced, announced_actor],
|
|
||||||
{activity, actor, {announced, announced_actor}}
|
|
||||||
)
|
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec notifications(actor :: Actor.t(), params :: map()) :: [
|
|
||||||
{:follow, activity :: Activity.t(), actor :: Actor.t()}
|
|
||||||
| {:mention, activity :: Activity.t(), actor :: Actor.t()}
|
|
||||||
| {:announce, announce :: Activity.t(), announce_actor :: Actor.t(),
|
|
||||||
activity :: Activity.t(), actor :: Actor.t()}
|
|
||||||
| {:like, like :: Activity.t(), like_actor :: Actor.t(), activity :: Activity.t(),
|
|
||||||
actor :: Actor.t()}
|
|
||||||
]
|
|
||||||
def notifications(actor, params) do
|
|
||||||
Notification
|
|
||||||
|> where([n], n.user_id == ^actor.user_id)
|
|
||||||
|> join(:inner, [n], activity in Activity, on: activity.id == n.activity_id)
|
|
||||||
|> join(:inner, [n, activity], actor in Actor, on: activity.actor == actor.ap_id)
|
|
||||||
|> join(:left, [n, activity, actor], other in Activity,
|
|
||||||
on:
|
|
||||||
n.type in ["announce", "like"] and fragment("?->>'type'", other.data) == "Create" and
|
|
||||||
fragment("?->>'object'", activity.data) == fragment("?->'object'->>'id'", other.data)
|
|
||||||
)
|
|
||||||
|> paginate(params)
|
|
||||||
|> limit(^Map.get(params, "limit", 20))
|
|
||||||
|> select(
|
|
||||||
[notification, activity, actor, original_activity],
|
|
||||||
{notification, activity, actor, original_activity}
|
|
||||||
)
|
|
||||||
|> Repo.all()
|
|
||||||
|> Enum.map(fn {notification, activity, actor, original_activity} ->
|
|
||||||
{String.to_existing_atom(notification.type), activity, actor, original_activity}
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp restrict_to_actor(query, actor_id) do
|
defp restrict_to_actor(query, actor_id) do
|
||||||
where(query, [a], fragment("?->>'actor'", a.data) == ^actor_id)
|
where(query, [a], fragment("?->>'actor'", a.data) == ^actor_id)
|
||||||
end
|
end
|
||||||
|
@ -130,18 +82,6 @@ defmodule Clacks.Timeline do
|
||||||
defp join_with_actors(query) do
|
defp join_with_actors(query) do
|
||||||
query
|
query
|
||||||
|> join(:left, [o], a in Actor, on: a.ap_id == fragment("?->>'actor'", o.data))
|
|> join(:left, [o], a in Actor, on: a.ap_id == fragment("?->>'actor'", o.data))
|
||||||
end
|
|> select([o, a], {o, a})
|
||||||
|
|
||||||
defp join_with_announced_or_liked(query) do
|
|
||||||
query
|
|
||||||
|> join(:left, [a], other in Activity,
|
|
||||||
on:
|
|
||||||
fragment("?->>'type'", a.data) in ["Announce", "Like"] and
|
|
||||||
fragment("?->>'type'", other.data) == "Create" and
|
|
||||||
fragment("?->>'object'", a.data) == fragment("?->'object'->>'id'", other.data)
|
|
||||||
)
|
|
||||||
|> join(:left, [a, ..., announced], actor in Actor,
|
|
||||||
on: actor.ap_id == fragment("?->>'actor'", announced.data)
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Clacks.UserActionsHelper do
|
defmodule Clacks.UserActionsHelper do
|
||||||
alias Clacks.{User, Repo, Activity, Object, ActivityPub, Actor, Notification}
|
alias Clacks.{User, Repo, Activity, Object, ActivityPub, Actor}
|
||||||
|
|
||||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
||||||
|
@ -37,8 +37,6 @@ defmodule Clacks.UserActionsHelper do
|
||||||
|
|
||||||
case ActivityPub.Helper.save_and_federate(create, author.actor) do
|
case ActivityPub.Helper.save_and_federate(create, author.actor) do
|
||||||
{:ok, activity} ->
|
{:ok, activity} ->
|
||||||
Notification.process_notifications_for_incoming(activity)
|
|
||||||
|
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
|
|
|
@ -31,15 +31,11 @@ defmodule ClacksWeb.FrontendController do
|
||||||
|
|
||||||
defp index({:profile, nickname}, conn, params) do
|
defp index({:profile, nickname}, conn, params) do
|
||||||
case Actor.get_by_nickname(nickname) do
|
case Actor.get_by_nickname(nickname) do
|
||||||
# only local profiles are shown
|
|
||||||
%Actor{local: true} = actor ->
|
%Actor{local: true} = actor ->
|
||||||
statuses_with_actor =
|
# only local profiles are shown
|
||||||
actor_statuses(actor, params, only_public: true)
|
|
||||||
|> Enum.map(fn {activity, announce} -> {activity, actor, announce} end)
|
|
||||||
|
|
||||||
render(conn, "profile.html", %{
|
render(conn, "profile.html", %{
|
||||||
actor: actor,
|
actor: actor,
|
||||||
statuses_with_actor: statuses_with_actor
|
statuses: actor_statuses(actor, params, only_public: true)
|
||||||
})
|
})
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -131,14 +127,10 @@ defmodule ClacksWeb.FrontendController do
|
||||||
user ->
|
user ->
|
||||||
user = Repo.preload(user, :actor)
|
user = Repo.preload(user, :actor)
|
||||||
|
|
||||||
statuses_with_actor =
|
|
||||||
actor_statuses(user.actor, params, only_public: true)
|
|
||||||
|> Enum.map(fn {activity, announce} -> {activity, user.actor, announce} end)
|
|
||||||
|
|
||||||
render(conn, "profile.html", %{
|
render(conn, "profile.html", %{
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
actor: user.actor,
|
actor: user.actor,
|
||||||
statuses_with_actor: statuses_with_actor,
|
statuses: actor_statuses(user.actor, params, only_public: true),
|
||||||
following_state: following_state(current_user.actor, user.actor)
|
following_state: following_state(current_user.actor, user.actor)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
@ -152,14 +144,10 @@ defmodule ClacksWeb.FrontendController do
|
||||||
resp(conn, 404, "Not Found")
|
resp(conn, 404, "Not Found")
|
||||||
|
|
||||||
actor ->
|
actor ->
|
||||||
statuses_with_actor =
|
|
||||||
actor_statuses(actor, params, only_public: true)
|
|
||||||
|> Enum.map(fn {activity, announce} -> {activity, actor, announce} end)
|
|
||||||
|
|
||||||
render(conn, "profile.html", %{
|
render(conn, "profile.html", %{
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
actor: actor,
|
actor: actor,
|
||||||
statuses_with_actor: statuses_with_actor,
|
statuses: actor_statuses(actor, params, only_public: true),
|
||||||
following_state: following_state(current_user.actor, actor)
|
following_state: following_state(current_user.actor, actor)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
@ -263,17 +251,6 @@ defmodule ClacksWeb.FrontendController do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
def notifications(conn, params) do
|
|
||||||
current_user = conn.assigns[:user] |> Repo.preload(:actor)
|
|
||||||
|
|
||||||
notifications = Timeline.notifications(current_user.actor, params)
|
|
||||||
|
|
||||||
render(conn, "notifications.html", %{
|
|
||||||
current_user: current_user,
|
|
||||||
notifications: notifications
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
def post_status(conn, %{"content" => content} = params) do
|
def post_status(conn, %{"content" => content} = params) do
|
||||||
current_user = conn.assigns[:user] |> Repo.preload(:actor)
|
current_user = conn.assigns[:user] |> Repo.preload(:actor)
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,6 @@ defmodule ClacksWeb.Router do
|
||||||
get "/actors/:id", FrontendController, :actor
|
get "/actors/:id", FrontendController, :actor
|
||||||
post "/actors/:id/follow", FrontendController, :follow
|
post "/actors/:id/follow", FrontendController, :follow
|
||||||
post "/actors/:id/unfollow", FrontendController, :unfollow
|
post "/actors/:id/unfollow", FrontendController, :unfollow
|
||||||
get "/notifications", FrontendController, :notifications
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", ClacksWeb do
|
scope "/", ClacksWeb do
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
<% past_tense =
|
|
||||||
case @action do
|
|
||||||
:like -> "Liked"
|
|
||||||
:announce -> "Announced"
|
|
||||||
end
|
|
||||||
%>
|
|
||||||
|
|
||||||
<div class="<%= assigns[:class] || "status" %>">
|
|
||||||
<div class="status-meta">
|
|
||||||
<p class="status-announcer">
|
|
||||||
<%= past_tense %> by <a href="<%= local_actor_link(@action_actor) %>"><%= @action_actor.data["preferredUsername"] %></a>
|
|
||||||
</p>
|
|
||||||
<p class="status-meta-right">
|
|
||||||
<time datetime="<%= @action_activity.data["published"] %>"><%= display_timestamp(@action_activity.data["published"]) %></time>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="status-meta">
|
|
||||||
<h2 class="status-author-nickname">
|
|
||||||
<a href="<%= local_actor_link(@original_actor) %>">
|
|
||||||
<%= @original_actor.data["preferredUsername"] %>
|
|
||||||
</a>
|
|
||||||
</h2>
|
|
||||||
<h3 class="status-author-username">
|
|
||||||
<a href="<%= @original_actor.ap_id %>">
|
|
||||||
<%= display_username(@original_actor) %>
|
|
||||||
</a>
|
|
||||||
</h3>
|
|
||||||
<p class="status-meta-right">
|
|
||||||
<time datetime="<%= @original_note["published"] %>"><%= display_timestamp(@original_note["published"]) %></time>
|
|
||||||
<a href="<%= @original_note["url"] || @original_note["id"] %>" class="status-permalink">Permalink</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="status-content">
|
|
||||||
<%= raw(@original_note["content"]) %>
|
|
||||||
</div>
|
|
||||||
<div class="status-actions">
|
|
||||||
<a href="<%= Routes.frontend_path(@conn, :reply, @original_activity.id) %>">Reply</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<div class="notification">
|
|
||||||
<div class="status-meta">
|
|
||||||
<p class="notification-info">
|
|
||||||
Followed by <a href="<%= local_actor_link(@actor) %>"><%= @actor.data["preferredUsername"] %></a>
|
|
||||||
</p>
|
|
||||||
<p class="notification-info-right">
|
|
||||||
<time datetime="<%= @activity.data["published"] %>"><%= display_timestamp(@activity.data["published"]) %></time>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="<%= assigns[:class] || "status h-entry" %>">
|
<div class="status h-entry">
|
||||||
<div class="status-meta">
|
<div class="status-meta">
|
||||||
<h2 class="status-author-nickname">
|
<h2 class="status-author-nickname">
|
||||||
<a href="<%= local_actor_link(@author) %>" class="p-author">
|
<a href="<%= local_actor_link(@author) %>" class="p-author">
|
||||||
|
|
|
@ -6,14 +6,9 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<ul class="status-list">
|
<ul class="status-list">
|
||||||
<%= for {status, author, announced} <- @statuses_with_authors do %>
|
<%= for {status, author} <- @statuses_with_authors do %>
|
||||||
<li>
|
<li>
|
||||||
<%= if status.data["type"] == "Announce" do %>
|
|
||||||
<% {announced_status, announced_actor} = announced %>
|
|
||||||
<%= render "_action_status.html", conn: @conn, action: :announce, action_activity: status, action_actor: author, original_activity: announced_status, original_note: announced_status.data["object"], original_actor: announced_actor %>
|
|
||||||
<% else %>
|
|
||||||
<%= render "_status.html", conn: @conn, author: author, status: status, note: status.data["object"] %>
|
<%= render "_status.html", conn: @conn, author: author, status: status, note: status.data["object"] %>
|
||||||
<% end %>
|
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<h1>Notifications</h1>
|
|
||||||
|
|
||||||
<% newer = prev_page_path(@conn, @notifications) %>
|
|
||||||
<%= if newer do %>
|
|
||||||
<p class="pagination-link">
|
|
||||||
<a href="<%= newer %>">Newer</a>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<ul class="notifications-list">
|
|
||||||
<%= for notification <- @notifications do %>
|
|
||||||
<li>
|
|
||||||
<%= case notification do %>
|
|
||||||
<% {:like, like_activity, actor, original_activity} -> %>
|
|
||||||
<%= render "_action_status.html", class: "notification", conn: @conn, action: :like, action_activity: like_activity, action_actor: actor, original_activity: original_activity, original_note: original_activity.data["object"], original_actor: @current_user.actor %>
|
|
||||||
|
|
||||||
<% {:announce, announce_activity, actor, original_activity} -> %>
|
|
||||||
<%= render "_action_status.html", class: "notification", conn: @conn, action: :announce, action_activity: announce_activity, action_actor: actor, original_activity: original_activity, original_note: original_activity.data["object"], original_actor: @current_user.actor %>
|
|
||||||
|
|
||||||
<% {:mention, mention_activity, actor, _} -> %>
|
|
||||||
<%= render "_status.html", class: "notification", conn: @conn, author: actor, status: mention_activity, note: mention_activity.data["object"] %>
|
|
||||||
|
|
||||||
<% {:follow, follow_activity, actor, _} -> %>
|
|
||||||
<%= render "_follow_notification.html", activity: follow_activity, actor: actor %>
|
|
||||||
<% end %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<% older = next_page_path(@conn, @notifications) %>
|
|
||||||
<%= if older do %>
|
|
||||||
<p class="pagination-link">
|
|
||||||
<a href="<%= older %>">Older</a>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
|
@ -30,4 +30,4 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= render "_timeline.html", conn: @conn, statuses_with_authors: @statuses_with_actor %>
|
<%= render "_timeline.html", conn: @conn, statuses_with_authors: Enum.map(@statuses, &({&1, @actor})) %>
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/"><%= instance_name() %></a></li>
|
<li><a href="/"><%= instance_name() %></a></li>
|
||||||
<%= if @conn.assigns[:user] do %>
|
<%= if @conn.assigns[:user] do %>
|
||||||
<li><a href="<%= Routes.frontend_path(@conn, :notifications) %>">Notifications</a></li>
|
|
||||||
<li><a href="<%= Routes.frontend_path(@conn, :search) %>">Search</a></li>
|
<li><a href="<%= Routes.frontend_path(@conn, :search) %>">Search</a></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule ClacksWeb.FrontendView do
|
defmodule ClacksWeb.FrontendView do
|
||||||
use ClacksWeb, :view
|
use ClacksWeb, :view
|
||||||
alias Clacks.{Actor, Activity, Repo, Notification}
|
alias Clacks.{Actor, Activity, Repo}
|
||||||
alias ClacksWeb.Router.Helpers, as: Routes
|
alias ClacksWeb.Router.Helpers, as: Routes
|
||||||
alias ClacksWeb.Endpoint
|
alias ClacksWeb.Endpoint
|
||||||
|
|
||||||
|
@ -60,24 +60,20 @@ defmodule ClacksWeb.FrontendView do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec prev_page_path(conn :: Plug.Conn.t(), [
|
@spec prev_page_path(conn :: Plug.Conn.t(), [Activity.t() | {Activity.t(), Actor.t()}]) ::
|
||||||
Activity.t() | {Activity.t(), Actor.t()} | Notification.t()
|
|
||||||
]) ::
|
|
||||||
String.t() | nil
|
String.t() | nil
|
||||||
|
|
||||||
def prev_page_path(conn, activities) do
|
def prev_page_path(conn, activities) do
|
||||||
if Map.has_key?(conn.query_params, "max_id") do
|
if Map.has_key?(conn.query_params, "max_id") do
|
||||||
Phoenix.Controller.current_path(conn, %{
|
Phoenix.Controller.current_path(conn, %{
|
||||||
since_id: activities |> List.first() |> timeline_id()
|
since_id: activities |> List.first() |> activity_id()
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec next_page_path(conn :: Plug.Conn.t(), [
|
@spec next_page_path(conn :: Plug.Conn.t(), [Activity.t() | {Activity.t(), Actor.t()}]) ::
|
||||||
Activity.t() | {Activity.t(), Actor.t()} | Notification.t()
|
|
||||||
]) ::
|
|
||||||
String.t() | nil
|
String.t() | nil
|
||||||
|
|
||||||
def next_page_path(conn, activities) do
|
def next_page_path(conn, activities) do
|
||||||
|
@ -85,15 +81,13 @@ defmodule ClacksWeb.FrontendView do
|
||||||
nil
|
nil
|
||||||
else
|
else
|
||||||
Phoenix.Controller.current_path(conn, %{
|
Phoenix.Controller.current_path(conn, %{
|
||||||
max_id: activities |> List.last() |> timeline_id()
|
max_id: activities |> List.last() |> activity_id()
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp timeline_id(%Activity{id: id}), do: id
|
defp activity_id(%Activity{id: id}), do: id
|
||||||
defp timeline_id({%Activity{id: id}, _}), do: id
|
defp activity_id({%Activity{id: id}, _}), do: id
|
||||||
defp timeline_id({%Activity{id: id}, _, _}), do: id
|
|
||||||
defp timeline_id(%Notification{id: id}), do: id
|
|
||||||
|
|
||||||
@spec mentions_for_replying_to(Activity.t()) :: String.t()
|
@spec mentions_for_replying_to(Activity.t()) :: String.t()
|
||||||
defp mentions_for_replying_to(conn, %Activity{
|
defp mentions_for_replying_to(conn, %Activity{
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
defmodule Clacks.Repo.Migrations.CreateNotifications do
|
|
||||||
use Ecto.Migration
|
|
||||||
|
|
||||||
def change do
|
|
||||||
create table(:notifications) do
|
|
||||||
add :type, :string
|
|
||||||
add :user_id, references(:users)
|
|
||||||
add :activity_id, references(:activities, type: :uuid)
|
|
||||||
|
|
||||||
timestamps()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue