diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 46552c7be..be4850560 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Activity do
use Ecto.Schema
alias Pleroma.Activity
+ alias Pleroma.ActivityExpiration
alias Pleroma.Bookmark
alias Pleroma.Notification
alias Pleroma.Object
@@ -59,6 +60,8 @@ defmodule Pleroma.Activity do
# typical case.
has_one(:object, Object, on_delete: :nothing, foreign_key: :id)
+ has_one(:expiration, ActivityExpiration, on_delete: :delete_all)
+
timestamps()
end
diff --git a/lib/pleroma/activity_expiration.ex b/lib/pleroma/activity_expiration.ex
new file mode 100644
index 000000000..d3d95f9e9
--- /dev/null
+++ b/lib/pleroma/activity_expiration.ex
@@ -0,0 +1,31 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ActivityExpiration do
+ use Ecto.Schema
+
+ alias Pleroma.Activity
+ alias Pleroma.ActivityExpiration
+ alias Pleroma.FlakeId
+ alias Pleroma.Repo
+
+ import Ecto.Query
+
+ @type t :: %__MODULE__{}
+
+ schema "activity_expirations" do
+ belongs_to(:activity, Activity, type: FlakeId)
+ field(:scheduled_at, :naive_datetime)
+ end
+
+ def due_expirations(offset \\ 0) do
+ naive_datetime =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(offset, :millisecond)
+
+ ActivityExpiration
+ |> where([exp], exp.scheduled_at < ^naive_datetime)
+ |> Repo.all()
+ end
+end
diff --git a/priv/repo/migrations/20190716100804_add_expirations_table.exs b/priv/repo/migrations/20190716100804_add_expirations_table.exs
new file mode 100644
index 000000000..fbde8f9d6
--- /dev/null
+++ b/priv/repo/migrations/20190716100804_add_expirations_table.exs
@@ -0,0 +1,10 @@
+defmodule Pleroma.Repo.Migrations.AddExpirationsTable do
+ use Ecto.Migration
+
+ def change do
+ create_if_not_exists table(:activity_expirations) do
+ add(:activity_id, references(:activities, type: :uuid, on_delete: :delete_all))
+ add(:scheduled_at, :naive_datetime, null: false)
+ end
+ end
+end
diff --git a/test/activity_expiration_test.exs b/test/activity_expiration_test.exs
new file mode 100644
index 000000000..20566a186
--- /dev/null
+++ b/test/activity_expiration_test.exs
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ActivityExpirationTest do
+ use Pleroma.DataCase
+ alias Pleroma.ActivityExpiration
+ import Pleroma.Factory
+
+ test "finds activities due to be deleted only" do
+ activity = insert(:note_activity)
+ expiration_due = insert(:expiration_in_the_past, %{activity_id: activity.id})
+ activity2 = insert(:note_activity)
+ insert(:expiration_in_the_future, %{activity_id: activity2.id})
+
+ expirations = ActivityExpiration.due_expirations()
+
+ assert length(expirations) == 1
+ assert hd(expirations) == expiration_due
+ end
+end
diff --git a/test/activity_test.exs b/test/activity_test.exs
index b27f6fd36..785c4b3cf 100644
--- a/test/activity_test.exs
+++ b/test/activity_test.exs
@@ -164,4 +164,13 @@ test "find all statuses for unauthenticated users when `limit_to_local_content`
Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
end
end
+
+ test "add an activity with an expiration" do
+ activity = insert(:note_activity)
+ insert(:expiration_in_the_future, %{activity_id: activity.id})
+
+ Pleroma.ActivityExpiration
+ |> where([a], a.activity_id == ^activity.id)
+ |> Repo.one!()
+ end
end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index c751546ce..7b52b1328 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors
+# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Factory do
@@ -142,6 +142,23 @@ def note_activity_factory(attrs \\ %{}) do
|> Map.merge(attrs)
end
+ defp expiration_offset_by_minutes(attrs, minutes) do
+ %Pleroma.ActivityExpiration{}
+ |> Map.merge(attrs)
+ |> Map.put(
+ :scheduled_at,
+ NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(minutes), :millisecond)
+ )
+ end
+
+ def expiration_in_the_past_factory(attrs \\ %{}) do
+ expiration_offset_by_minutes(attrs, -60)
+ end
+
+ def expiration_in_the_future_factory(attrs \\ %{}) do
+ expiration_offset_by_minutes(attrs, 60)
+ end
+
def article_activity_factory do
article = insert(:article)