Packages
phoenix_kit
1.7.82
1.7.211
1.7.210
1.7.209
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/phoenix_kit.cleanup_orphaned_files.ex
defmodule Mix.Tasks.PhoenixKit.CleanupOrphanedFiles do
@moduledoc """
Finds and optionally deletes orphaned media files in PhoenixKit Storage.
An orphaned file is one not referenced by any known entity (products, posts,
categories, users, publishing content, etc.).
By default this task runs in dry-run mode and only reports what would be deleted.
Use `--delete` to queue the actual deletion via Oban.
## Usage
$ mix phoenix_kit.cleanup_orphaned_files
$ mix phoenix_kit.cleanup_orphaned_files --delete
## Options
* `--delete` - Queue orphaned files for deletion (default: dry-run)
## Examples
# Dry-run: show orphaned files without deleting
mix phoenix_kit.cleanup_orphaned_files
# Queue all orphaned files for deletion
mix phoenix_kit.cleanup_orphaned_files --delete
"""
use Mix.Task
alias PhoenixKit.Modules.Storage
@shortdoc "Find and optionally delete orphaned media files"
@switches [delete: :boolean]
@impl Mix.Task
@spec run([String.t()]) :: :ok
def run(argv) do
Mix.Task.run("app.start")
{opts, _argv, _errors} = OptionParser.parse(argv, switches: @switches)
do_delete = opts[:delete] || false
Mix.shell().info("\nPhoenixKit Storage — Orphaned Files Cleanup")
Mix.shell().info(String.duplicate("─", 50))
count = Storage.count_orphaned_files()
if count == 0 do
Mix.shell().info("✓ No orphaned files found.")
:ok
else
orphans = Storage.find_orphaned_files()
if do_delete do
Mix.shell().info("Found #{count} orphaned file(s). Queuing for deletion...\n")
else
Mix.shell().info("Found #{count} orphaned file(s) (dry-run — use --delete to remove):\n")
end
Enum.each(orphans, fn file ->
size = format_size(file.size || 0)
name = file.original_file_name || file.file_name || "unknown"
Mix.shell().info(" #{file.uuid} #{name} (#{size})")
end)
if do_delete do
uuids = Enum.map(orphans, & &1.uuid)
Storage.queue_file_cleanup(uuids)
Mix.shell().info("\n✓ #{count} file(s) queued for deletion (60s delay).")
else
Mix.shell().info("\nRun with --delete to queue these files for deletion.")
end
:ok
end
end
defp format_size(bytes) when bytes >= 1_000_000,
do: "#{Float.round(bytes / 1_000_000, 2)} MB"
defp format_size(bytes) when bytes >= 1_000,
do: "#{Float.round(bytes / 1_000, 2)} KB"
defp format_size(bytes), do: "#{bytes} B"
end