1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Console\Commands;
7
8use App\Jobs\UserNotificationDigest;
9use App\Models\Count;
10use App\Models\User;
11use App\Models\UserNotification;
12use Illuminate\Console\Command;
13
14class NotificationsSendMail extends Command
15{
16 /**
17 * The console command name.
18 *
19 * @var string
20 */
21 protected $signature = 'notifications:send-mail {--chunk-size=} {--from=} {--to=}';
22
23 /**
24 * The console command description.
25 *
26 * @var string
27 */
28 protected $description = 'Send mail notifications';
29
30 /**
31 * Execute the console command.
32 *
33 * @return mixed
34 */
35 public function handle()
36 {
37 $lastIdRow = Count::lastMailUserNotificationIdSent();
38
39 $fromId = get_int($this->option('from')) ?? $lastIdRow->count;
40 $toId = get_int($this->option('to')) ?? optional(UserNotification::last())->getKey();
41
42 $chunkSize = get_int($this->option('chunk-size')) ?? 1000;
43
44 if ($toId === null) {
45 $this->warn('No notifications to send!');
46
47 return;
48 }
49
50 $this->line("Sending user notifications > {$fromId} <= {$toId}");
51
52 // TODO: this query needs more investigation with larger dataset
53 // on whether an index over (notification_id, delivery) would actually be useful;
54 // currently getting inconsistent results...
55 $userIds = UserNotification
56 ::where('id', '>', $fromId)
57 ->where('id', '<=', $toId)
58 ->groupBy('user_id')
59 ->pluck('user_id');
60
61 foreach ($userIds->chunk($chunkSize) as $chunk) {
62 $users = User::whereIn('user_id', $chunk)->get();
63 foreach ($users as $user) {
64 $job = new UserNotificationDigest($user, $fromId, $toId);
65 try {
66 $job->handle();
67 } catch (\Exception $e) {
68 // catch exception and queue job to be rerun to avoid job exploding and preventing other notifications from being processed.
69 log_error($e);
70 dispatch($job);
71 }
72 }
73 }
74
75 if ($toId > $lastIdRow->count) {
76 $lastIdRow->count = $toId;
77 $lastIdRow->save();
78 }
79 }
80}