defmodule Pleroma.Activity do
use Ecto.Schema
- alias Pleroma.{Repo, Activity}
+ alias Pleroma.{Repo, Activity, Notification}
import Ecto.Query
schema "activities" do
field :data, :map
field :local, :boolean, default: true
+ has_many :notifications, Notification
timestamps()
end
--- /dev/null
+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
+
use Ecto.Schema
import Ecto.{Changeset, Query}
- alias Pleroma.{Repo, User, Object, Web}
+ alias Pleroma.{Repo, User, Object, Web, Activity, Notification}
alias Comeonin.Pbkdf2
alias Pleroma.Web.{OStatus, Websub}
alias Pleroma.Web.ActivityPub.ActivityPub
field :local, :boolean, default: true
field :info, :map, default: %{}
field :follower_address, :string
+ has_many :notifications, Notification
timestamps()
end
Repo.update(cs)
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
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}
import Ecto.Query
import Pleroma.Web.ActivityPub.Utils
with nil <- Activity.get_by_ap_id(map["id"]),
map <- lazy_put_activity_defaults(map),
: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
%Activity{} = activity -> {:ok, activity}
error -> {:error, error}
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
- alias Pleroma.{Repo, Activity, User}
+ alias Pleroma.{Repo, Activity, User, Notification}
alias Pleroma.Web.OAuth.App
alias Pleroma.Web
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView}
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
Logger.debug("Unimplemented, returning an empty array")
json(conn, [])
post "/statuses/:id/favourite", MastodonAPIController, :fav_status
post "/statuses/:id/unfavourite", MastodonAPIController, :unfav_status
- get "/notifications", MastodonAPIController, :empty_array
+ get "/notifications", MastodonAPIController, :notifications
end
scope "/api", Pleroma.Web do
--- /dev/null
+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
--- /dev/null
+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