Merge remote-tracking branch 'origin/develop' into benchmark-finishing
[akkoma] / lib / pleroma / scheduled_activity.ex
index 9fdc1399087ce43e7529014d5c6f147155029799..fea2cf3ffab5d7e081c60107198c106dfdc3b596 100644 (file)
@@ -5,9 +5,11 @@
 defmodule Pleroma.ScheduledActivity do
   use Ecto.Schema
 
+  alias Pleroma.Config
   alias Pleroma.Repo
   alias Pleroma.ScheduledActivity
   alias Pleroma.User
+  alias Pleroma.Web.CommonAPI.Utils
 
   import Ecto.Query
   import Ecto.Changeset
@@ -15,7 +17,7 @@ defmodule Pleroma.ScheduledActivity do
   @min_offset :timer.minutes(5)
 
   schema "scheduled_activities" do
-    belongs_to(:user, User, type: Pleroma.FlakeId)
+    belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
     field(:scheduled_at, :naive_datetime)
     field(:params, :map)
 
@@ -25,11 +27,67 @@ defmodule Pleroma.ScheduledActivity do
   def changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
     scheduled_activity
     |> cast(attrs, [:scheduled_at, :params])
+    |> validate_required([:scheduled_at, :params])
+    |> validate_scheduled_at()
+    |> with_media_attachments()
   end
 
+  defp with_media_attachments(
+         %{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset
+       )
+       when is_list(media_ids) do
+    media_attachments = Utils.attachments_from_ids(%{"media_ids" => media_ids})
+
+    params =
+      params
+      |> Map.put("media_attachments", media_attachments)
+      |> Map.put("media_ids", media_ids)
+
+    put_change(changeset, :params, params)
+  end
+
+  defp with_media_attachments(changeset), do: changeset
+
   def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
     scheduled_activity
     |> cast(attrs, [:scheduled_at])
+    |> validate_required([:scheduled_at])
+    |> validate_scheduled_at()
+  end
+
+  def validate_scheduled_at(changeset) do
+    validate_change(changeset, :scheduled_at, fn _, scheduled_at ->
+      cond do
+        not far_enough?(scheduled_at) ->
+          [scheduled_at: "must be at least 5 minutes from now"]
+
+        exceeds_daily_user_limit?(changeset.data.user_id, scheduled_at) ->
+          [scheduled_at: "daily limit exceeded"]
+
+        exceeds_total_user_limit?(changeset.data.user_id) ->
+          [scheduled_at: "total limit exceeded"]
+
+        true ->
+          []
+      end
+    end)
+  end
+
+  def exceeds_daily_user_limit?(user_id, scheduled_at) do
+    ScheduledActivity
+    |> where(user_id: ^user_id)
+    |> where([sa], type(sa.scheduled_at, :date) == type(^scheduled_at, :date))
+    |> select([sa], count(sa.id))
+    |> Repo.one()
+    |> Kernel.>=(Config.get([ScheduledActivity, :daily_user_limit]))
+  end
+
+  def exceeds_total_user_limit?(user_id) do
+    ScheduledActivity
+    |> where(user_id: ^user_id)
+    |> select([sa], count(sa.id))
+    |> Repo.one()
+    |> Kernel.>=(Config.get([ScheduledActivity, :total_user_limit]))
   end
 
   def far_enough?(scheduled_at) when is_binary(scheduled_at) do
@@ -64,22 +122,25 @@ defmodule Pleroma.ScheduledActivity do
     |> Repo.one()
   end
 
-  def update(%User{} = user, scheduled_activity_id, attrs) do
-    with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
-      scheduled_activity
-      |> update_changeset(attrs)
-      |> Repo.update()
-    else
-      nil -> {:error, :not_found}
-    end
+  def update(%ScheduledActivity{} = scheduled_activity, attrs) do
+    scheduled_activity
+    |> update_changeset(attrs)
+    |> Repo.update()
   end
 
-  def delete(%User{} = user, scheduled_activity_id) do
-    with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
-      scheduled_activity
-      |> Repo.delete()
-    else
-      nil -> {:error, :not_found}
+  def delete(%ScheduledActivity{} = scheduled_activity) do
+    scheduled_activity
+    |> Repo.delete()
+  end
+
+  def delete(id) when is_binary(id) or is_integer(id) do
+    ScheduledActivity
+    |> where(id: ^id)
+    |> select([sa], sa)
+    |> Repo.delete_all()
+    |> case do
+      {1, [scheduled_activity]} -> {:ok, scheduled_activity}
+      _ -> :error
     end
   end
 
@@ -87,4 +148,14 @@ defmodule Pleroma.ScheduledActivity do
     ScheduledActivity
     |> where(user_id: ^user.id)
   end
+
+  def due_activities(offset \\ 0) do
+    naive_datetime =
+      NaiveDateTime.utc_now()
+      |> NaiveDateTime.add(offset, :millisecond)
+
+    ScheduledActivity
+    |> where([sa], sa.scheduled_at < ^naive_datetime)
+    |> Repo.all()
+  end
 end