defmodule Mobilizon.Service.CleanOldActivity do @moduledoc """ Service to clean old activities """ alias Mobilizon.Activities.Activity alias Mobilizon.Actors.Actor alias Mobilizon.Config alias Mobilizon.Storage.Repo import Ecto.Query @doc """ Clean old activities Remove activities that are older than a certain period Options: * `grace_period` how old in hours can the media be before it's taken into account for deletion * `dry_run` just return the media that would have been deleted, don't actually delete it """ @spec clean(Keyword.t()) :: {:ok, list(Media.t())} | {:error, String.t()} def clean(opts \\ []) do {query, nb_actors} = find_activities(opts) if Keyword.get(opts, :dry_run, false) do nb_activities = Repo.aggregate(query, :count) {:ok, actors: nb_actors, activities: nb_activities} else {nb_activities, _} = Repo.delete_all(query) {:ok, actors: nb_actors, activities: nb_activities} end end @spec find_activities(Keyword.t()) :: {Ecto.Query.t(), integer()} defp find_activities(opts) do grace_period = Keyword.get(opts, :grace_period, Config.get([:instance, :activity_expire_days], 365)) expiration_date = DateTime.add(DateTime.utc_now(), grace_period * -3600) activities_to_keep = Keyword.get( opts, :activity_keep_number, Config.get([:instance, :activity_keep_number], 100) ) actor_ids = Actor |> where(type: :Group) |> join(:inner, [ac], a in Activity, on: a.group_id == ac.id) |> group_by([ac], ac.id) |> having([_ac, a], count(a.id) > ^activities_to_keep) |> select([ac], ac.id) |> Repo.all() query = Activity |> where([a], a.inserted_at < ^expiration_date) |> where([a], a.group_id in ^actor_ids) {query, length(actor_ids)} end end