Add basic mastodon notification support.

This commit is contained in:
Roger Braun 2017-09-11 16:15:28 +02:00
parent 7616b202ea
commit 61adf676d5
8 changed files with 108 additions and 6 deletions

View File

@ -1,11 +1,12 @@
defmodule Pleroma.Activity do defmodule Pleroma.Activity do
use Ecto.Schema use Ecto.Schema
alias Pleroma.{Repo, Activity} alias Pleroma.{Repo, Activity, Notification}
import Ecto.Query import Ecto.Query
schema "activities" do schema "activities" do
field :data, :map field :data, :map
field :local, :boolean, default: true field :local, :boolean, default: true
has_many :notifications, Notification
timestamps() timestamps()
end end

View File

@ -0,0 +1,38 @@
defmodule Pleroma.Notification do
use Ecto.Schema
alias Pleroma.{User, Activity, Notification, Repo}
import Ecto.Query
schema "notifications" do
field :seen, :boolean, default: false
belongs_to :user, Pleroma.User
belongs_to :activity, Pleroma.Activity
timestamps()
end
def for_user(user, opts \\ %{}) do
query = from n in Notification,
where: n.user_id == ^user.id,
order_by: [desc: n.id],
preload: [:activity],
limit: 20
Repo.all(query)
end
def create_notifications(%Activity{id: id, data: %{"to" => to, "type" => type}} = activity) when type in ["Create"] do
users = User.get_notified_from_activity(activity)
notifications = Enum.map(users, fn (user) -> create_notification(activity, user) end)
{:ok, notifications}
end
def create_notifications(_), do: {:ok, []}
# TODO move to sql, too.
def create_notification(%Activity{} = activity, %User{} = user) do
notification = %Notification{user_id: user.id, activity_id: activity.id}
{:ok, notification} = Repo.insert(notification)
notification
end
end

View File

@ -2,7 +2,7 @@ defmodule Pleroma.User do
use Ecto.Schema use Ecto.Schema
import Ecto.{Changeset, Query} import Ecto.{Changeset, Query}
alias Pleroma.{Repo, User, Object, Web} alias Pleroma.{Repo, User, Object, Web, Activity, Notification}
alias Comeonin.Pbkdf2 alias Comeonin.Pbkdf2
alias Pleroma.Web.{OStatus, Websub} alias Pleroma.Web.{OStatus, Websub}
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
@ -22,6 +22,7 @@ defmodule Pleroma.User do
field :local, :boolean, default: true field :local, :boolean, default: true
field :info, :map, default: %{} field :info, :map, default: %{}
field :follower_address, :string field :follower_address, :string
has_many :notifications, Notification
timestamps() timestamps()
end end
@ -239,4 +240,12 @@ def update_follower_count(%User{} = user) do
Repo.update(cs) Repo.update(cs)
end end
def get_notified_from_activity(%Activity{data: %{"to" => to}} = activity) do
query = from u in User,
where: u.ap_id in ^to,
where: u.local == true
Repo.all(query)
end
end end

View File

@ -1,5 +1,5 @@
defmodule Pleroma.Web.ActivityPub.ActivityPub do defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.{Activity, Repo, Object, Upload, User, Web} alias Pleroma.{Activity, Repo, Object, Upload, User, Web, Notification}
alias Ecto.{Changeset, UUID} alias Ecto.{Changeset, UUID}
import Ecto.Query import Ecto.Query
import Pleroma.Web.ActivityPub.Utils import Pleroma.Web.ActivityPub.Utils
@ -9,7 +9,9 @@ def insert(map, local \\ true) when is_map(map) do
with nil <- Activity.get_by_ap_id(map["id"]), with nil <- Activity.get_by_ap_id(map["id"]),
map <- lazy_put_activity_defaults(map), map <- lazy_put_activity_defaults(map),
:ok <- insert_full_object(map) do :ok <- insert_full_object(map) do
Repo.insert(%Activity{data: map, local: local}) {:ok, activity} = Repo.insert(%Activity{data: map, local: local})
Notification.create_notifications(activity)
{:ok, activity}
else else
%Activity{} = activity -> {:ok, activity} %Activity{} = activity -> {:ok, activity}
error -> {:error, error} error -> {:error, error}

View File

@ -1,6 +1,6 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.{Repo, Activity, User} alias Pleroma.{Repo, Activity, User, Notification}
alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.App
alias Pleroma.Web alias Pleroma.Web
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView} alias Pleroma.Web.MastodonAPI.{StatusView, AccountView}
@ -132,6 +132,20 @@ def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
end end
end end
def notifications(%{assigns: %{user: user}} = conn, params) do
notifications = Notification.for_user(user, params)
result = Enum.map(notifications, fn (%{id: id, activity: activity, inserted_at: created_at}) ->
actor = User.get_cached_by_ap_id(activity.data["actor"])
case activity.data["type"] do
"Create" -> %{ id: id, type: "mention", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: activity})}
_ -> nil
end
end)
|> Enum.filter(&(&1))
json(conn, result)
end
def empty_array(conn, _) do def empty_array(conn, _) do
Logger.debug("Unimplemented, returning an empty array") Logger.debug("Unimplemented, returning an empty array")
json(conn, []) json(conn, [])

View File

@ -65,7 +65,7 @@ def user_fetcher(username) do
post "/statuses/:id/favourite", MastodonAPIController, :fav_status post "/statuses/:id/favourite", MastodonAPIController, :fav_status
post "/statuses/:id/unfavourite", MastodonAPIController, :unfav_status post "/statuses/:id/unfavourite", MastodonAPIController, :unfav_status
get "/notifications", MastodonAPIController, :empty_array get "/notifications", MastodonAPIController, :notifications
end end
scope "/api", Pleroma.Web do scope "/api", Pleroma.Web do

View File

@ -0,0 +1,15 @@
defmodule Pleroma.Repo.Migrations.CreateNotifications do
use Ecto.Migration
def change do
create table(:notifications) do
add :user_id, references(:users, on_delete: :delete_all)
add :activity_id, references(:activities, on_delete: :delete_all)
add :seen, :boolean, default: false
timestamps()
end
create index(:notifications, [:user_id])
end
end

View File

@ -0,0 +1,23 @@
defmodule Pleroma.NotificationTest do
use Pleroma.DataCase
alias Pleroma.Web.TwitterAPI.TwitterAPI
alias Pleroma.{User, Notification}
import Pleroma.Factory
describe "create_notifications" do
test "notifies someone when they are directly addressed" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"})
{:ok, [notification, other_notification]} = Notification.create_notifications(activity)
assert notification.user_id == other_user.id
assert notification.activity_id == activity.id
assert other_notification.user_id == third_user.id
assert other_notification.activity_id == activity.id
end
end
end