Handle scheduled_at on status creation.

This commit is contained in:
eugenijm 2019-03-30 12:58:40 +03:00
parent 7bf622ce73
commit b3870df51f
4 changed files with 75 additions and 6 deletions

View file

@ -31,7 +31,7 @@ defmodule Pleroma.Activity do
field(:data, :map) field(:data, :map)
field(:local, :boolean, default: true) field(:local, :boolean, default: true)
field(:actor, :string) field(:actor, :string)
field(:recipients, {:array, :string}) field(:recipients, {:array, :string}, default: [])
has_many(:notifications, Notification, on_delete: :delete_all) has_many(:notifications, Notification, on_delete: :delete_all)
# Attention: this is a fake relation, don't try to preload it blindly and expect it to work! # Attention: this is a fake relation, don't try to preload it blindly and expect it to work!

View file

@ -12,6 +12,8 @@ defmodule Pleroma.ScheduledActivity do
import Ecto.Query import Ecto.Query
import Ecto.Changeset import Ecto.Changeset
@min_offset :timer.minutes(5)
schema "scheduled_activities" do schema "scheduled_activities" do
belongs_to(:user, User, type: Pleroma.FlakeId) belongs_to(:user, User, type: Pleroma.FlakeId)
field(:scheduled_at, :naive_datetime) field(:scheduled_at, :naive_datetime)
@ -30,6 +32,20 @@ def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
|> cast(attrs, [:scheduled_at]) |> cast(attrs, [:scheduled_at])
end end
def far_enough?(scheduled_at) when is_binary(scheduled_at) do
with {:ok, scheduled_at} <- Ecto.Type.cast(:naive_datetime, scheduled_at) do
far_enough?(scheduled_at)
else
_ -> false
end
end
def far_enough?(scheduled_at) do
now = NaiveDateTime.utc_now()
diff = NaiveDateTime.diff(scheduled_at, now, :millisecond)
diff > @min_offset
end
def new(%User{} = user, attrs) do def new(%User{} = user, attrs) do
%ScheduledActivity{user_id: user.id} %ScheduledActivity{user_id: user.id}
|> changeset(attrs) |> changeset(attrs)

View file

@ -425,13 +425,30 @@ def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do
_ -> Ecto.UUID.generate() _ -> Ecto.UUID.generate()
end end
scheduled_at = params["scheduled_at"]
if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do
{:ok, scheduled_activity} =
Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ ->
ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at})
end)
conn
|> put_view(ScheduledActivityView)
|> render("show.json", %{scheduled_activity: scheduled_activity})
else
params = Map.drop(params, ["scheduled_at"])
{:ok, activity} = {:ok, activity} =
Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> CommonAPI.post(user, params) end) Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ ->
CommonAPI.post(user, params)
end)
conn conn
|> put_view(StatusView) |> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity}) |> try_render("status.json", %{activity: activity, for: user, as: :activity})
end end
end
def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do

View file

@ -2410,6 +2410,42 @@ test "redirects to the getting-started page when referer is not present", %{conn
end end
describe "scheduled activities" do describe "scheduled activities" do
test "creates a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "scheduled",
"scheduled_at" => scheduled_at
})
assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
assert [] == Repo.all(Activity)
end
test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
%{conn: conn} do
user = insert(:user)
scheduled_at =
NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "not scheduled",
"scheduled_at" => scheduled_at
})
assert %{"content" => "not scheduled"} = json_response(conn, 200)
assert [] == Repo.all(ScheduledActivity)
end
test "shows scheduled activities", %{conn: conn} do test "shows scheduled activities", %{conn: conn} do
user = insert(:user) user = insert(:user)
scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string() scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()