• 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

89.09
/iznik-batch/app/Console/Commands/Chat/NotifyUser2UserCommand.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 NotifyUser2UserCommand 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:user2user
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 User2User chat messages';
34

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

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

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

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

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

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

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

84
        $this->info('Processing User2User chat notifications...');
6✔
85
        $totalNotified = 0;
6✔
86
        $iteration = 0;
6✔
87

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

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

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

106
            $totalNotified += $count;
6✔
107
            $iteration++;
6✔
108

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

117
        $this->newLine();
6✔
118
        $this->info("User2User notification complete. Total notifications sent: {$totalNotified}");
6✔
119

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

125
        return Command::SUCCESS;
6✔
126
    }
127
}
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