Skip to content

Commit c7bcd57

Browse files
committed
Add delete-and-notify command for manual cleanup.
1 parent db4e4a5 commit c7bcd57

File tree

4 files changed

+190
-0
lines changed

4 files changed

+190
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Mail\FeedDeleted;
6+
use App\Models\Feed;
7+
use Illuminate\Console\Command;
8+
use Illuminate\Support\Facades\Mail;
9+
10+
class DeleteFeedAndNotify extends Command
11+
{
12+
/**
13+
* The name and signature of the console command.
14+
*
15+
* @var string
16+
*/
17+
protected $signature = 'app:delete-feed-and-notify';
18+
19+
/**
20+
* The console command description.
21+
*
22+
* @var string
23+
*/
24+
protected $description = 'Delete a feed and notify the owner with a custom reason';
25+
26+
/**
27+
* Execute the console command.
28+
*/
29+
public function handle(): void
30+
{
31+
// Step 1: Prompt for feed identifier (ID or URL)
32+
$identifier = $this->ask('Enter feed ID or URL');
33+
34+
// Step 2: Find feed by ID or URL
35+
$feed = $this->findFeed($identifier);
36+
37+
if (! $feed) {
38+
$this->error('Feed not found.');
39+
40+
return;
41+
}
42+
43+
// Step 3: Display feed information for confirmation
44+
$this->newLine();
45+
$this->line('Feed found:');
46+
$this->table(
47+
['ID', 'URL', 'Email', 'Status', 'Confirmed'],
48+
[[$feed->id, $feed->url, $feed->email, $feed->status, $feed->confirmed ? 'Yes' : 'No']]
49+
);
50+
51+
// Step 4: Prompt for deletion reason
52+
$reason = $this->ask('Enter deletion reason (will be sent to feed owner)');
53+
54+
if (empty($reason)) {
55+
$this->error('Deletion reason is required.');
56+
57+
return;
58+
}
59+
60+
// Step 5: Final confirmation
61+
$this->newLine();
62+
if (! $this->confirm('Are you sure you want to delete this feed and notify the owner?', false)) {
63+
$this->info('Deletion cancelled.');
64+
65+
return;
66+
}
67+
68+
// Step 6: Send notification email
69+
$this->line('Sending notification email...');
70+
try {
71+
Mail::send(new FeedDeleted($feed, $reason));
72+
$this->info('Notification sent to '.$feed->email);
73+
} catch (\Exception $e) {
74+
$this->error('Failed to send notification: '.$e->getMessage());
75+
if (! $this->confirm('Continue with deletion anyway?', false)) {
76+
$this->info('Deletion cancelled.');
77+
78+
return;
79+
}
80+
}
81+
82+
// Step 7: Delete the feed (cascade will handle checks and connection_failures)
83+
$feedUrl = $feed->url;
84+
$feedEmail = $feed->email;
85+
86+
$this->line('Deleting feed...');
87+
$feed->delete();
88+
89+
$this->newLine();
90+
$this->info('Feed deleted successfully.');
91+
$this->line('URL: '.$feedUrl);
92+
$this->line('Owner: '.$feedEmail);
93+
}
94+
95+
/**
96+
* Find feed by ID (UUID) or URL
97+
*/
98+
private function findFeed(string $identifier): ?Feed
99+
{
100+
// Try to find by ID first (UUID format)
101+
if (strlen($identifier) === 36 && str_contains($identifier, '-')) {
102+
$feed = Feed::find($identifier);
103+
if ($feed) {
104+
return $feed;
105+
}
106+
}
107+
108+
// Try to find by URL
109+
return Feed::where('url', $identifier)->first();
110+
}
111+
}

app/Mail/FeedDeleted.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace App\Mail;
4+
5+
use App\Models\Feed;
6+
use Illuminate\Bus\Queueable;
7+
use Illuminate\Mail\Mailable;
8+
use Illuminate\Mail\Mailables\Content;
9+
use Illuminate\Mail\Mailables\Envelope;
10+
use Illuminate\Queue\SerializesModels;
11+
12+
class FeedDeleted extends Mailable
13+
{
14+
use Queueable, SerializesModels;
15+
16+
public Feed $feed;
17+
18+
public string $reason;
19+
20+
/**
21+
* Create a new message instance.
22+
*/
23+
public function __construct(Feed $feed, string $reason)
24+
{
25+
$this->feed = $feed;
26+
$this->reason = $reason;
27+
}
28+
29+
/**
30+
* Get the message envelope.
31+
*/
32+
public function envelope(): Envelope
33+
{
34+
return new Envelope(
35+
to: [$this->feed->email],
36+
subject: 'Feed Monitor Removed',
37+
);
38+
}
39+
40+
/**
41+
* Get the message content definition.
42+
*/
43+
public function content(): Content
44+
{
45+
return new Content(
46+
view: 'mail.feed-deleted',
47+
text: 'mail.feed-deleted-text',
48+
with: [
49+
'feed' => $this->feed,
50+
'reason' => $this->reason,
51+
],
52+
);
53+
}
54+
55+
/**
56+
* Get the attachments for the message.
57+
*
58+
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
59+
*/
60+
public function attachments(): array
61+
{
62+
return [];
63+
}
64+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Your check for {{ $feed->url }} has been manually removed.
2+
3+
Reason:
4+
{{ $reason }}
5+
6+
Please get in touch if this seems like a mistake, and feel free to re-add your feed!
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@extends('mail.layouts.default')
2+
3+
@section('content')
4+
<p>Your check for <strong>{{ $feed->url }}</strong> has been manually removed.</p>
5+
6+
<p><strong>Reason:</strong> {{ $reason }}</p>
7+
8+
<p>Please get in touch if this seems like a mistake, and feel free to re-add your feed!</p>
9+
@endsection

0 commit comments

Comments
 (0)