Require that ephemeral posts live for at least one hour
If we didn't put some kind of lifetime requirement on these, I guess you could annoy people by sending large numbers of ephemeral posts that provoke notifications but then disappear before anyone can read them.
This commit is contained in:
parent
704960b3c1
commit
36012ef6c1
|
@ -14,6 +14,7 @@ defmodule Pleroma.ActivityExpiration do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
@type t :: %__MODULE__{}
|
@type t :: %__MODULE__{}
|
||||||
|
@min_activity_lifetime :timer.hours(1)
|
||||||
|
|
||||||
schema "activity_expirations" do
|
schema "activity_expirations" do
|
||||||
belongs_to(:activity, Activity, type: FlakeId)
|
belongs_to(:activity, Activity, type: FlakeId)
|
||||||
|
@ -24,6 +25,7 @@ def changeset(%ActivityExpiration{} = expiration, attrs) do
|
||||||
expiration
|
expiration
|
||||||
|> cast(attrs, [:scheduled_at])
|
|> cast(attrs, [:scheduled_at])
|
||||||
|> validate_required([:scheduled_at])
|
|> validate_required([:scheduled_at])
|
||||||
|
|> validate_scheduled_at()
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_by_activity_id(activity_id) do
|
def get_by_activity_id(activity_id) do
|
||||||
|
@ -47,4 +49,20 @@ def due_expirations(offset \\ 0) do
|
||||||
|> where([exp], exp.scheduled_at < ^naive_datetime)
|
|> where([exp], exp.scheduled_at < ^naive_datetime)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_scheduled_at(changeset) do
|
||||||
|
validate_change(changeset, :scheduled_at, fn _, scheduled_at ->
|
||||||
|
if not expires_late_enough?(scheduled_at) do
|
||||||
|
[scheduled_at: "an ephemeral activity must live for at least one hour"]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def expires_late_enough?(scheduled_at) do
|
||||||
|
now = NaiveDateTime.utc_now()
|
||||||
|
diff = NaiveDateTime.diff(scheduled_at, now, :millisecond)
|
||||||
|
diff >= @min_activity_lifetime
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -196,6 +196,16 @@ def get_replied_to_visibility(activity) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp check_expiry_date(expiry_str) do
|
||||||
|
{:ok, expiry} = Ecto.Type.cast(:naive_datetime, expiry_str)
|
||||||
|
|
||||||
|
if is_nil(expiry) || ActivityExpiration.expires_late_enough?(expiry) do
|
||||||
|
{:ok, expiry}
|
||||||
|
else
|
||||||
|
{:error, "Expiry date is too soon"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def post(user, %{"status" => status} = data) do
|
def post(user, %{"status" => status} = data) do
|
||||||
limit = Pleroma.Config.get([:instance, :limit])
|
limit = Pleroma.Config.get([:instance, :limit])
|
||||||
|
|
||||||
|
@ -219,7 +229,7 @@ def post(user, %{"status" => status} = data) do
|
||||||
context <- make_context(in_reply_to),
|
context <- make_context(in_reply_to),
|
||||||
cw <- data["spoiler_text"] || "",
|
cw <- data["spoiler_text"] || "",
|
||||||
sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}),
|
sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}),
|
||||||
{:ok, expires_at} <- Ecto.Type.cast(:naive_datetime, data["expires_at"]),
|
{:ok, expires_at} <- check_expiry_date(data["expires_at"]),
|
||||||
full_payload <- String.trim(status <> cw),
|
full_payload <- String.trim(status <> cw),
|
||||||
:ok <- validate_character_limit(full_payload, attachments, limit),
|
:ok <- validate_character_limit(full_payload, attachments, limit),
|
||||||
object <-
|
object <-
|
||||||
|
@ -258,7 +268,7 @@ def post(user, %{"status" => status} = data) do
|
||||||
|
|
||||||
if expires_at do
|
if expires_at do
|
||||||
with {:ok, activity} <- result do
|
with {:ok, activity} <- result do
|
||||||
ActivityExpiration.create(activity, expires_at)
|
{:ok, _} = ActivityExpiration.create(activity, expires_at)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,4 +18,10 @@ test "finds activities due to be deleted only" do
|
||||||
assert length(expirations) == 1
|
assert length(expirations) == 1
|
||||||
assert hd(expirations) == expiration_due
|
assert hd(expirations) == expiration_due
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "denies expirations that don't live long enough" do
|
||||||
|
activity = insert(:note_activity)
|
||||||
|
now = NaiveDateTime.utc_now()
|
||||||
|
assert {:error, _} = ActivityExpiration.create(activity, now)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -158,7 +158,7 @@ def expiration_in_the_past_factory(attrs \\ %{}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def expiration_in_the_future_factory(attrs \\ %{}) do
|
def expiration_in_the_future_factory(attrs \\ %{}) do
|
||||||
expiration_offset_by_minutes(attrs, 60)
|
expiration_offset_by_minutes(attrs, 61)
|
||||||
end
|
end
|
||||||
|
|
||||||
def article_activity_factory do
|
def article_activity_factory do
|
||||||
|
|
Loading…
Reference in New Issue