@@ -49,27 +49,81 @@ public function get_name() {
49
49
public function execute () {
50
50
global $ DB ;
51
51
52
+ // Get the certificatesperrun, includeinnotvisiblecourses, and certificateexecutionperiod configurations.
53
+ $ certificatesperrun = (int )get_config ('customcert ' , 'certificatesperrun ' );
54
+ $ includeinnotvisiblecourses = (bool )get_config ('customcert ' , 'includeinnotvisiblecourses ' );
55
+ $ certificateexecutionperiod = (int )get_config ('customcert ' , 'certificateexecutionperiod ' );
56
+
57
+ // Get the last processed batch and total certificates to process.
58
+ $ taskprogress = $ DB ->get_record ('customcert_task_progress ' , ['taskname ' => 'email_certificate_task ' ]);
59
+ $ lastprocessed = $ taskprogress ->last_processed ;
60
+
52
61
// Get all the certificates that have requested someone get emailed.
53
62
$ emailotherslengthsql = $ DB ->sql_length ('c.emailothers ' );
54
63
$ sql = "SELECT c.*, ct.id as templateid, ct.name as templatename, ct.contextid, co.id as courseid,
55
- co.fullname as coursefullname, co.shortname as courseshortname
56
- FROM {customcert} c
57
- JOIN {customcert_templates} ct
64
+ co.fullname as coursefullname, co.shortname as courseshortname
65
+ FROM {customcert} c
66
+ JOIN {customcert_templates} ct
58
67
ON c.templateid = ct.id
59
- JOIN {course} co
60
- ON c.course = co.id
61
- WHERE (c.emailstudents = :emailstudents
62
- OR c.emailteachers = :emailteachers
63
- OR $ emailotherslengthsql >= 3) " ;
64
- if (!$ customcerts = $ DB ->get_records_sql ($ sql , ['emailstudents ' => 1 , 'emailteachers ' => 1 ])) {
68
+ JOIN {course} co
69
+ ON c.course = co.id " ;
70
+
71
+ // Add JOIN with mdl_course_categories to exclude certificates from hidden courses.
72
+ $ sql .= " JOIN {course_categories} cat ON co.category = cat.id " ;
73
+
74
+ // Add conditions to exclude certificates from hidden courses.
75
+ $ sql .= " WHERE (c.emailstudents = :emailstudents
76
+ OR c.emailteachers = :emailteachers
77
+ OR $ emailotherslengthsql >= 3) " ;
78
+
79
+ // Check the includeinnotvisiblecourses configuration.
80
+ if (!$ includeinnotvisiblecourses ) {
81
+ // Exclude certificates from hidden courses.
82
+ $ sql .= " AND co.visible = 1 AND cat.visible = 1 " ;
83
+ }
84
+
85
+ // Add condition based on certificate execution period.
86
+ if ($ certificateexecutionperiod > 0 ) {
87
+ // Include courses with no end date or end date greater than the specified period.
88
+ $ sql .= " AND (co.enddate = 0 OR co.enddate > :enddate) " ;
89
+ $ params ['enddate ' ] = time () - $ certificateexecutionperiod ;
90
+ }
91
+
92
+ // Execute the SQL query.
93
+ if (!$ customcerts = $ DB ->get_records_sql ($ sql , ['emailstudents ' => 1 , 'emailteachers ' => 1 ] + $ params )) {
65
94
return ;
66
95
}
67
96
68
97
// The renderers used for sending emails.
69
98
$ page = new \moodle_page ();
70
99
$ htmlrenderer = $ page ->get_renderer ('mod_customcert ' , 'email ' , 'htmlemail ' );
71
100
$ textrenderer = $ page ->get_renderer ('mod_customcert ' , 'email ' , 'textemail ' );
72
- foreach ($ customcerts as $ customcert ) {
101
+
102
+ // Store the total count of certificates in the database.
103
+ $ totalcertificatestoprocess = count ($ customcerts );
104
+ $ DB ->set_field ('customcert_task_progress ' , 'total_certificate_to_process ' , $ totalcertificatestoprocess , [
105
+ 'taskname ' => 'email_certificate_task ' ,
106
+ ]);
107
+
108
+ // Check if we need to reset and start from the beginning.
109
+ if ($ lastprocessed >= count ($ customcerts )) {
110
+ $ lastprocessed = 0 ; // Reset to the beginning.
111
+ }
112
+
113
+ if ($ certificatesperrun <= 0 ) {
114
+ // Process all certificates in a single run.
115
+ $ certificates = $ customcerts ;
116
+ } else {
117
+ // Process certificates in batches, starting from the last processed batch.
118
+ $ certificates = array_slice ($ customcerts , $ lastprocessed , $ certificatesperrun );
119
+ }
120
+
121
+ foreach ($ certificates as $ customcert ) {
122
+ // Check if the certificate is hidden, quit early.
123
+ $ fastmoduleinfo = get_fast_modinfo ($ customcert ->courseid )->instances ['customcert ' ][$ customcert ->id ];
124
+ if (!$ fastmoduleinfo ->visible ) {
125
+ continue ;
126
+ }
73
127
// Do not process an empty certificate.
74
128
$ sql = "SELECT ce.*
75
129
FROM {customcert_elements} ce
@@ -111,27 +165,28 @@ public function execute() {
111
165
WHERE ci.customcertid = :customcertid " ;
112
166
$ issuedusers = $ DB ->get_records_sql ($ sql , ['customcertid ' => $ customcert ->id ]);
113
167
114
- // Now, get a list of users who can access the certificate but have not yet.
115
- $ enrolledusers = get_enrolled_users (\context_course::instance ($ customcert ->courseid ), 'mod/customcert:view ' );
116
- foreach ($ enrolledusers as $ enroluser ) {
117
- // Check if the user has already been issued.
118
- if (in_array ($ enroluser ->id , array_keys ((array ) $ issuedusers ))) {
119
- continue ;
120
- }
168
+ // Now, get a list of users who can Manage the certificate.
169
+ $ userswithmanage = get_users_by_capability ($ context , 'mod/customcert:manage ' , 'id ' );
121
170
122
- // Now check if the certificate is not visible to the current user.
123
- $ cm = get_fast_modinfo ($ customcert ->courseid , $ enroluser ->id )->instances ['customcert ' ][$ customcert ->id ];
124
- if (!$ cm ->uservisible ) {
125
- continue ;
126
- }
171
+ // Get the context of the Custom Certificate module.
172
+ $ cm = get_coursemodule_from_instance ('customcert ' , $ customcert ->id , $ customcert ->course );
173
+ $ context = \context_module::instance ($ cm ->id );
127
174
128
- // Don't want to email those with the capability to manage the certificate.
129
- if (has_capability ('mod/customcert:manage ' , $ context , $ enroluser ->id )) {
175
+ // Now, get a list of users who can Issue the certificate but have not yet.
176
+ // Get users with the specified capability in the Custom Certificate module context.
177
+ $ userwithissue = get_users_by_capability ($ context , 'mod/customcert:receiveissue ' , 'id, firstname, lastname, email ' );
178
+ $ infomodule = new \core_availability \info_module ($ fastmoduleinfo );
179
+ // Filter who can't access due to availability restriction, from the full list.
180
+ $ userscanissue = $ infomodule ->filter_user_list ($ userwithissue );
181
+
182
+ foreach ($ userscanissue as $ enroluser ) {
183
+ // Check if the user has already been issued.
184
+ if (in_array ($ enroluser ->id , array_keys ((array )$ issuedusers ))) {
130
185
continue ;
131
186
}
132
187
133
- // Only email those with the capability to receive the certificate.
134
- if (! has_capability ( ' mod/customcert:receiveissue ' , $ context , $ enroluser ->id )) {
188
+ // Don't want to email those with the capability to manage the certificate.
189
+ if (in_array ( $ enroluser ->id , array_keys (( array ) $ userswithmanage ) )) {
135
190
continue ;
136
191
}
137
192
@@ -164,7 +219,7 @@ public function execute() {
164
219
}
165
220
}
166
221
167
- // If there are no users to email we can return early.
222
+ // If there are no users to email, we can return early.
168
223
if (!$ issuedusers ) {
169
224
continue ;
170
225
}
@@ -175,6 +230,7 @@ public function execute() {
175
230
return ;
176
231
}
177
232
233
+ $ issueids = [];
178
234
// Now, email the people we need to.
179
235
foreach ($ issuedusers as $ user ) {
180
236
// Set up the user.
@@ -248,8 +304,18 @@ public function execute() {
248
304
}
249
305
250
306
// Set the field so that it is emailed.
251
- $ DB ->set_field ('customcert_issues ' , 'emailed ' , 1 , ['id ' => $ user ->issueid ]);
307
+ $ issueids [] = $ user ->issueid ;
308
+ }
309
+ if (!empty ($ issueids )) {
310
+ $ DB ->set_field_select ('customcert_issues ' , 'emailed ' , 1 , 'id IN ( ' . implode (', ' , $ issueids ) . ') ' );
252
311
}
253
312
}
313
+ // Update the last processed position, if run in batches.
314
+ if ($ certificatesperrun > 0 ) {
315
+ $ newlastprocessed = $ lastprocessed + count ($ certificates );
316
+ $ DB ->set_field ('customcert_task_progress ' , 'last_processed ' , $ newlastprocessed , [
317
+ 'taskname ' => 'email_certificate_task ' ,
318
+ ]);
319
+ }
254
320
}
255
321
}
0 commit comments