Skip to content

Commit 1a0f03f

Browse files
authored
Merge pull request #8 from ssddanbrown/pruning
Post pruning
2 parents d9f007c + b29e1c7 commit 1a0f03f

File tree

14 files changed

+674
-749
lines changed

14 files changed

+674
-749
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The following features are built into the application:
2020
- Post title/description search.
2121
- Ready-to-use docker image.
2222
- Mobile screen compatible.
23+
- Built-in support to prune old post data.
2324

2425
## Limitations
2526

@@ -156,6 +157,13 @@ APP_LOAD_POST_THUMBNAILS=true
156157
# therefore should be updated upon request.
157158
# This effectively has a minimum of 5 minutes in the docker setup.
158159
APP_FEED_UPDATE_FREQUENCY=60
160+
161+
# The number of days to wait before a post should be pruned.
162+
# Uses the post published_at time to determine lifetime.
163+
# Setting this to false disables any auto-pruning.
164+
# If active, pruning will auto-run daily.
165+
# Defaults to false (No pruning)
166+
APP_PRUNE_POSTS_AFTER_DAYS=30
159167
```
160168

161169
## Usage Behind a Reverse Proxy
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Rss\PostPruner;
6+
use Illuminate\Console\Command;
7+
8+
class PrunePostsCommand extends Command
9+
{
10+
/**
11+
* The name and signature of the console command.
12+
*
13+
* @var string
14+
*/
15+
protected $signature = 'rss:prune-posts
16+
{--days= : Number of days\' worth of posts to keep}';
17+
18+
/**
19+
* The console command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Prune old posts, and their thumbnails, from the system';
24+
25+
/**
26+
* Execute the console command.
27+
*
28+
* @return int
29+
*/
30+
public function handle(PostPruner $pruner)
31+
{
32+
$days = $this->option('days', null);
33+
34+
if (!is_null($days)) {
35+
$retention = intval($days);
36+
} else {
37+
$configuredPruneDays = config('app.prune_posts_after_days');
38+
39+
if (!$configuredPruneDays) {
40+
$this->line("No prune retention time set therefore no posts will be pruned.");
41+
return 0;
42+
}
43+
44+
$retention = intval($configuredPruneDays);
45+
}
46+
47+
$acceptsRisk = $this->confirm("This will delete all posts older than {$retention} day(s). Do you want to continue?", true);
48+
49+
if ($acceptsRisk) {
50+
$deleteCount = $pruner->prune($retention);
51+
$this->line("Deleted {$deleteCount} posts from the system");
52+
}
53+
54+
return 0;
55+
}
56+
}

app/Console/Kernel.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Console;
44

5+
use App\Console\Commands\PrunePostsCommand;
56
use App\Console\Commands\UpdateFeedsCommand;
67
use Illuminate\Console\Scheduling\Schedule;
78
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -17,6 +18,7 @@ class Kernel extends ConsoleKernel
1718
protected function schedule(Schedule $schedule)
1819
{
1920
$schedule->command(UpdateFeedsCommand::class)->everyFiveMinutes();
21+
$schedule->command(PrunePostsCommand::class, ['-n'])->daily();
2022
}
2123

2224
/**

app/Http/Kernel.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ class Kernel extends HttpKernel
4040
],
4141

4242
'api' => [
43-
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
4443
'throttle:api',
4544
\Illuminate\Routing\Middleware\SubstituteBindings::class,
4645
],

app/Rss/PostPruner.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace App\Rss;
4+
5+
use App\Models\Post;
6+
use Illuminate\Database\Eloquent\Collection;
7+
use Illuminate\Support\Facades\Storage;
8+
9+
class PostPruner
10+
{
11+
/**
12+
* Prune all posts older than the given number of days.
13+
* Returns the number of posts deleted.
14+
*/
15+
public function prune(int $retentionDays): int
16+
{
17+
$day = 86400;
18+
$oldestAcceptable = time() - ($retentionDays * $day);
19+
$ids = [];
20+
21+
Post::query()
22+
->where('published_at', '<', $oldestAcceptable)
23+
->select(['id', 'thumbnail'])
24+
->chunk(250, function (Collection $posts) use (&$ids) {
25+
array_push($ids, ...$posts->pluck('id')->all());
26+
$this->deletePostsThumbnails($posts);
27+
});
28+
29+
foreach (array_chunk($ids, 250) as $idChunk) {
30+
Post::query()
31+
->whereIn('id', $idChunk)
32+
->delete();
33+
}
34+
35+
return count($ids);
36+
}
37+
38+
/**
39+
* @param Collection<Post> $posts
40+
*/
41+
protected function deletePostsThumbnails(Collection $posts)
42+
{
43+
$storage = Storage::disk('public');
44+
45+
foreach ($posts as $post) {
46+
if ($post->thumbnail && $storage->exists($post->thumbnail)) {
47+
$storage->delete($post->thumbnail);
48+
}
49+
}
50+
}
51+
}

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"guzzlehttp/guzzle": "^7.2",
1212
"inertiajs/inertia-laravel": "^0.6.2",
1313
"laravel/framework": "^9.19",
14-
"laravel/sanctum": "^2.14.1",
1514
"laravel/tinker": "^2.7"
1615
},
1716
"require-dev": {

0 commit comments

Comments
 (0)