66
77use Baka \Enums \StateEnums ;
88use Baka \Traits \KanvasJobsTrait ;
9+ use Baka \Validations \Date ;
910use Exception ;
1011use Illuminate \Console \Command ;
12+ use Illuminate \Contracts \Database \Query \Builder ;
1113use Illuminate \Support \Facades \DB ;
1214use Illuminate \Support \Facades \Notification ;
1315use Kanvas \Apps \Models \Apps ;
@@ -32,66 +34,100 @@ class MailAllAppUsersCommand extends Command
3234 {subject : The subject of the email}
3335 {--test-email= : Email address to send a test email instead of sending to all users}
3436 {--production : Flag to confirm sending to all users in production}
35- {--delay=500 : Delay in milliseconds between each email} ' ;
37+ {--delay=500 : Delay in milliseconds between each email}
38+ {--created-after= : Filter users created after this date (Y-m-d H:i:s format)}
39+ {--created-before= : Filter users created before this date (Y-m-d H:i:s format)} ' ;
3640
3741 /**
3842 * The console command description.
3943 *
4044 * @var string
4145 */
42- protected $ description = 'Send specific email to all users of an app or to a test email address ' ;
46+ protected $ description = 'Send specific email to all users of an app or to a test email address with optional date filtering ' ;
4347
4448 /**
4549 * Execute the console command.
4650 */
47- public function handle ()
51+ public function handle (): void
4852 {
4953 $ app = Apps::getById ((int ) $ this ->argument ('apps_id ' ));
5054 $ this ->app = $ app ;
5155 $ this ->overwriteAppService ($ app );
52- $ emailTemplateName = $ this ->argument ('email_template_name ' );
53- $ emailSubject = $ this ->argument ('subject ' );
56+ $ emailTemplateName = ( string ) $ this ->argument ('email_template_name ' );
57+ $ emailSubject = ( string ) $ this ->argument ('subject ' );
5458 $ testEmail = $ this ->option ('test-email ' );
5559 $ isProduction = $ this ->option ('production ' );
5660 $ delayMs = (int ) $ this ->option ('delay ' );
61+ $ createdAfter = $ this ->option ('created-after ' ) ?? '' ;
62+ $ createdBefore = $ this ->option ('created-before ' ) ?? '' ;
63+
64+ // Validate date format if provided
65+ if ($ createdAfter !== '' && ! Date::isValid ($ createdAfter , 'Y-m-d H:i:s ' )) {
66+ $ this ->error ('Invalid created-after date format. Use Y-m-d H:i:s format (e.g., 2024-01-01 00:00:00) ' );
67+
68+ return ;
69+ }
70+
71+ if ($ createdBefore !== '' && ! Date::isValid ($ createdBefore , 'Y-m-d H:i:s ' )) {
72+ $ this ->error ('Invalid created-before date format. Use Y-m-d H:i:s format (e.g., 2024-12-31 23:59:59) ' );
73+
74+ return ;
75+ }
5776
5877 // Check if we're just testing to a single email
59- if ($ testEmail ) {
78+ if (is_string ( $ testEmail) && ! empty ( $ testEmail ) ) {
6079 try {
6180 $ userModelEntity = Users::getByEmail ($ testEmail );
6281 $ this ->sendEmailToUser ($ userModelEntity , $ emailTemplateName , $ emailSubject );
6382 $ this ->info ('Test email successfully sent to: ' . $ userModelEntity ->getId () . ' on app: ' . $ app ->getId ());
6483 } catch (Exception $ e ) {
6584 $ this ->error ('Failed to send test email: ' . $ e ->getMessage ());
6685
67- return 1 ;
86+ return ;
6887 }
6988
70- return 0 ;
89+ return ;
7190 }
7291
7392 // Check if we're in production mode and have the production flag
7493 if (! app ()->isProduction () || ! $ isProduction ) {
7594 $ this ->error ('This command can only send emails to all users in production with the --production flag. ' );
7695 $ this ->
info (
'Use [email protected] to send a test email instead. ' );
7796
78- return 1 ;
97+ return ;
7998 }
8099
100+ // Build the base query for counting and processing users
101+ $ baseQuery = $ this ->buildUserQuery ($ app ->getId (), $ createdAfter , $ createdBefore );
102+
81103 // Count total users to process for progress bar
82- $ totalUsers = DB ::table ('users_associated_apps ' )
83- ->where ('apps_id ' , $ app ->id )
84- ->where ('is_deleted ' , StateEnums::NO ->getValue ())
85- ->where ('companies_id ' , AppEnums::GLOBAL_COMPANY_ID ->getValue ())
86- ->count ();
104+ $ totalUsers = $ baseQuery ->count ();
87105
88106 if ($ totalUsers === 0 ) {
89- $ this ->warn ('No users found for this app. ' );
107+ $ this ->warn ('No users found for this app with the given criteria. ' );
108+ if ($ createdAfter !== '' || $ createdBefore !== '' ) {
109+ $ this ->info ('Date filters applied: ' );
110+ if ($ createdAfter !== '' ) {
111+ $ this ->info (' - Created after: ' . $ createdAfter );
112+ }
113+ if ($ createdBefore !== '' ) {
114+ $ this ->info (' - Created before: ' . $ createdBefore );
115+ }
116+ }
90117
91- return 0 ;
118+ return ;
92119 }
93120
94121 $ this ->info ("Found {$ totalUsers } users to process. " );
122+ if ($ createdAfter !== '' || $ createdBefore !== '' ) {
123+ $ this ->info ('Date filters applied: ' );
124+ if ($ createdAfter !== '' ) {
125+ $ this ->info (' - Created after: ' . $ createdAfter );
126+ }
127+ if ($ createdBefore !== '' ) {
128+ $ this ->info (' - Created before: ' . $ createdBefore );
129+ }
130+ }
95131
96132 // Initialize counters
97133 $ successCount = 0 ;
@@ -103,10 +139,7 @@ public function handle()
103139 $ progressBar ->start ();
104140
105141 // Only runs if we're in production and have the production flag
106- DB ::table ('users_associated_apps ' )
107- ->where ('apps_id ' , $ app ->id )
108- ->where ('is_deleted ' , StateEnums::NO ->getValue ())
109- ->where ('companies_id ' , AppEnums::GLOBAL_COMPANY_ID ->getValue ())
142+ $ this ->buildUserQuery ($ app ->getId (), $ createdAfter , $ createdBefore )
110143 ->orderBy ('users_id ' )
111144 ->chunk (100 , function ($ users ) use (
112145 $ app ,
@@ -154,12 +187,10 @@ public function handle()
154187 if ($ failCount > 0 ) {
155188 $ this ->error (" - Failed: {$ failCount }" );
156189
157- return 1 ;
190+ return ;
158191 }
159192
160193 $ this ->info ('All emails have been sent successfully. ' );
161-
162- return 0 ;
163194 }
164195
165196 /**
@@ -182,4 +213,32 @@ private function sendEmailToUser(Users $user, string $emailTemplateName, string
182213 $ notification ->setSubject ($ emailSubject );
183214 Notification::route ('mail ' , $ user ->email )->notify ($ notification );
184215 }
216+
217+ /**
218+ * Build the user query with optional date filters
219+ */
220+ private function buildUserQuery (
221+ int $ appId ,
222+ ?string $ createdAfter = null ,
223+ ?string $ createdBefore = null
224+ ): Builder {
225+ $ query = DB ::table ('users_associated_apps ' )
226+ ->join ('users ' , 'users_associated_apps.users_id ' , '= ' , 'users.id ' )
227+ ->selectRaw ('users_associated_apps.*, users.email ' )
228+ ->where ('users_associated_apps.apps_id ' , $ appId )
229+ ->where ('users_associated_apps.is_deleted ' , StateEnums::NO ->getValue ())
230+ ->where ('users_associated_apps.companies_id ' , AppEnums::GLOBAL_COMPANY_ID ->getValue ())
231+ ->where ('users.is_deleted ' , StateEnums::NO ->getValue ());
232+
233+ // Apply created_at filters if provided
234+ if ($ createdAfter !== null && ! empty ($ createdAfter )) {
235+ $ query ->where ('users.created_at ' , '>= ' , $ createdAfter );
236+ }
237+
238+ if ($ createdBefore !== null && ! empty ($ createdBefore )) {
239+ $ query ->where ('users.created_at ' , '<= ' , $ createdBefore );
240+ }
241+
242+ return $ query ;
243+ }
185244}
0 commit comments