• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Freegle / Iznik / 3988

15 Apr 2026 08:41AM UTC coverage: 70.846% (-0.09%) from 70.939%
3988

push

circleci

web-flow
Merge pull request #104 from Freegle/feature/batch-jobs-dry-run-and-fixes

feat: batch jobs dry-run, feature flags, List-Unsubscribe, and user cleanup

13102 of 20045 branches covered (65.36%)

Branch coverage included in aggregate %.

520 of 900 new or added lines in 34 files covered. (57.78%)

34 existing lines in 15 files now uncovered.

92779 of 129408 relevant lines covered (71.69%)

17.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.5
/iznik-batch/app/Console/Commands/Chat/NotifyUser2ModCommand.php
1
<?php
2

3
namespace App\Console\Commands\Chat;
4

5
use App\Console\Concerns\PreventsOverlapping;
6
use App\Models\ChatRoom;
7
use App\Services\ChatNotificationService;
8
use App\Services\EmailSpoolerService;
9
use App\Traits\GracefulShutdown;
10
use Illuminate\Console\Command;
11
use Illuminate\Support\Facades\Log;
12

13
class NotifyUser2ModCommand extends Command
14
{
15
    use GracefulShutdown;
16
    use PreventsOverlapping;
17

18
    /**
19
     * The name and signature of the console command.
20
     */
21
    protected $signature = 'mail:chat:user2mod
22
                            {--chat= : Process only a specific chat ID}
23
                            {--delay=30 : Delay in seconds before sending notification}
24
                            {--since=4 : How many hours back to look for messages}
25
                            {--force : Force sending even for already mailed messages}
26
                            {--max-iterations=120 : Maximum iterations before exiting}
27
                            {--spool : Spool emails instead of sending directly}
28
                            {--dry-run : Show what would be sent without actually sending}';
29

30
    /**
31
     * The console command description.
32
     */
33
    protected $description = 'Send email notifications for unread User2Mod chat messages';
34

35
    /**
36
     * Execute the console command.
37
     */
38
    public function handle(ChatNotificationService $notificationService, EmailSpoolerService $spooler): int
2✔
39
    {
40
        if (!$this->acquireLock()) {
2✔
41
            $this->info('Already running, exiting.');
×
42
            return Command::SUCCESS;
×
43
        }
44

45
        try {
46
            return $this->doHandle($notificationService, $spooler);
2✔
47
        } finally {
48
            $this->releaseLock();
2✔
49
        }
50
    }
51

52
    /**
53
     * The actual command logic.
54
     */
55
    protected function doHandle(ChatNotificationService $notificationService, EmailSpoolerService $spooler): int
2✔
56
    {
57
        $chatId = $this->option('chat') ? (int) $this->option('chat') : null;
2✔
58
        $delay = (int) $this->option('delay');
2✔
59
        $sinceHours = (int) $this->option('since');
2✔
60
        $forceAll = (bool) $this->option('force');
2✔
61
        $maxIterations = (int) $this->option('max-iterations');
2✔
62
        $spool = (bool) $this->option('spool');
2✔
63
        $dryRun = (bool) $this->option('dry-run');
2✔
64

65
        if ($dryRun) {
2✔
NEW
66
            $this->info('DRY RUN — no emails will be sent.');
×
67
        }
68

69
        // Inject spooler if spooling is enabled.
70
        if ($spool) {
2✔
71
            $notificationService->setSpooler($spooler);
×
72
        }
73

74
        $this->registerShutdownHandlers();
2✔
75

76
        Log::info('Starting User2Mod chat notification', [
2✔
77
            'chat_id' => $chatId,
2✔
78
            'delay' => $delay,
2✔
79
            'since_hours' => $sinceHours,
2✔
80
            'force' => $forceAll,
2✔
81
            'spool' => $spool,
2✔
82
            'dry_run' => $dryRun,
2✔
83
        ]);
2✔
84

85
        $this->info('Processing User2Mod chat notifications...');
2✔
86
        $totalNotified = 0;
2✔
87
        $iteration = 0;
2✔
88

89
        do {
90
            if ($this->shouldAbort()) {
2✔
91
                $this->warn('Aborting due to shutdown signal.');
×
92
                break;
×
93
            }
94

95
            $startTime = now();
2✔
96
            $this->line('Starting iteration ' . ($iteration + 1) . ' at ' . $startTime->format('Y-m-d H:i:s'));
2✔
97

98
            $count = $notificationService->notifyByEmail(
2✔
99
                ChatRoom::TYPE_USER2MOD,
2✔
100
                $chatId,
2✔
101
                $delay,
2✔
102
                $sinceHours,
2✔
103
                $forceAll,
2✔
104
                $dryRun
2✔
105
            );
2✔
106

107
            $totalNotified += $count;
2✔
108
            $iteration++;
2✔
109

110
            if ($count > 0) {
2✔
111
                $this->info("Sent {$count} notifications.");
×
112
            } else {
113
                // No messages to process, sleep before next iteration.
114
                sleep(1);
2✔
115
            }
116
        } while ($iteration < $maxIterations);
2✔
117

118
        $this->newLine();
2✔
119
        $this->info("User2Mod notification complete. Total notifications sent: {$totalNotified}");
2✔
120

121
        Log::info('User2Mod chat notification complete', [
2✔
122
            'total_notified' => $totalNotified,
2✔
123
            'iterations' => $iteration,
2✔
124
        ]);
2✔
125

126
        return Command::SUCCESS;
2✔
127
    }
128
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc