16
16
17
17
use core \context \user ;
18
18
use core_course \external \course_summary_exporter ;
19
+ use local_assess_type \assess_type ; // UCL plugin.
19
20
use mod_quiz \question \display_options ;
20
21
21
22
/**
@@ -35,9 +36,10 @@ class block_my_feedback extends block_base {
35
36
public function init () {
36
37
global $ USER ;
37
38
38
- // If $USER->firstname is not set yet do not try to use it.
39
39
if (!isset ($ USER ->firstname )) {
40
40
$ this ->title = get_string ('pluginname ' , 'block_my_feedback ' );
41
+ } else if (self ::is_teacher ()) {
42
+ $ this ->title = get_string ('markingfor ' , 'block_my_feedback ' ).' ' .$ USER ->firstname ;
41
43
} else {
42
44
$ this ->title = get_string ('feedbackfor ' , 'block_my_feedback ' ).' ' .$ USER ->firstname ;
43
45
}
@@ -59,35 +61,233 @@ public function get_content(): stdClass {
59
61
$ this ->content ->footer = '' ;
60
62
61
63
$ template = new stdClass ();
62
- $ template ->feedback = $ this ->fetch_feedback ($ USER );
63
64
64
- // Hide the block when no content.
65
- if (!$ template ->feedback ) {
66
- return $ this ->content ;
65
+ if (self ::is_teacher ()) {
66
+ // Teacher content.
67
+ $ template ->mods = self ::fetch_marking ($ USER );
68
+ } else {
69
+ // Student content.
70
+ $ template ->mods = $ this ->fetch_feedback ($ USER );
71
+ $ template ->showfeedbacktrackerlink = true ;
72
+ }
73
+
74
+ if (isset ($ template ->mods )) {
75
+ $ this ->content ->text = $ OUTPUT ->render_from_template ('block_my_feedback/content ' , $ template );
67
76
}
68
77
69
- $ this ->content ->text = $ OUTPUT ->render_from_template ('block_my_feedback/content ' , $ template );
70
78
return $ this ->content ;
71
79
}
72
80
81
+ /**
82
+ * Return if user has archetype editingteacher.
83
+ *
84
+ */
85
+ public static function is_teacher (): bool {
86
+ global $ DB , $ USER ;
87
+ // Get id's from role where archetype is editingteacher.
88
+ $ roles = $ DB ->get_fieldset ('role ' , 'id ' , ['archetype ' => 'editingteacher ' ]);
89
+
90
+ // Check if user has editingteacher role on any courses.
91
+ list ($ roles , $ params ) = $ DB ->get_in_or_equal ($ roles , SQL_PARAMS_NAMED );
92
+ $ params ['userid ' ] = $ USER ->id ;
93
+ $ sql = "SELECT id
94
+ FROM {role_assignments}
95
+ WHERE userid = :userid
96
+ AND roleid $ roles " ;
97
+ return $ DB ->record_exists_sql ($ sql , $ params );
98
+ }
99
+
100
+ /**
101
+ * Return marking for a user.
102
+ *
103
+ * @param stdClass $user
104
+ */
105
+ public static function fetch_marking (stdClass $ user ): ?array {
106
+ // User courses.
107
+ $ courses = enrol_get_all_users_courses ($ user ->id , false , ['enddate ' ]);
108
+ // Marking.
109
+ $ marking = [];
110
+
111
+ foreach ($ courses as $ course ) {
112
+ // Skip hidden courses.
113
+ if (!$ course ->visible ) {
114
+ continue ;
115
+ }
116
+ // Skip none current course.
117
+ if (!self ::is_course_current ($ course )) {
118
+ continue ;
119
+ }
120
+ // Skip if no summative assessments.
121
+ if (!$ summatives = assess_type::get_assess_type_records_by_courseid ($ course ->id , assess_type::ASSESS_TYPE_SUMMATIVE )) {
122
+ continue ;
123
+ }
124
+
125
+ $ modinfo = get_fast_modinfo ($ course ->id );
126
+ $ mods = $ modinfo ->get_cms ();
127
+ // Mod ids array to check cmid exists.
128
+ $ cmids = [];
129
+ foreach ($ mods as $ mod ) {
130
+ $ cmids [] = $ mod ->id ;
131
+ }
132
+
133
+ // Loop through assessments for this course.
134
+ foreach ($ summatives as $ summative ) {
135
+
136
+ // Check this is a course mod.
137
+ if ($ summative ->cmid != 0 ) {
138
+ // Skip mods where cmid is not in the course.
139
+ if (!in_array ($ summative ->cmid , $ cmids )) {
140
+ continue ;
141
+ }
142
+
143
+ // Begin to build mod data for template.
144
+ $ cmid = $ summative ->cmid ;
145
+ $ mod = $ modinfo ->get_cm ($ cmid );
146
+
147
+ // Skip hidden mods.
148
+ if (!$ mod ->visible ) {
149
+ continue ;
150
+ }
151
+
152
+ // Template.
153
+ $ assess = new stdClass ;
154
+ $ assess ->cmid = $ cmid ;
155
+ $ assess ->modname = $ mod ->modname ;
156
+ // Get due date and require marking.
157
+ $ assess = self ::get_mod_data ($ mod , $ assess );
158
+
159
+ // Check mod has require marking (only set when there is a due date).
160
+ if (isset ($ assess ->requiremarking )) {
161
+ // TODO - what is expensive here that we can do after sort and limit?
162
+ $ assess ->name = $ mod ->name ;
163
+ $ assess ->coursename = $ course ->fullname ;
164
+ $ assess ->url = new moodle_url ('/mod/ ' . $ mod ->modname . '/view.php ' , ['id ' => $ cmid ]);
165
+ $ assess ->icon = course_summary_exporter::get_course_image ($ course );
166
+ $ marking [] = $ assess ;
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ // Sort and return data.
173
+ if ($ marking ) {
174
+ usort ($ marking , function ($ a , $ b ) {
175
+ return $ a ->unixtimestamp <=> $ b ->unixtimestamp ;
176
+ });
177
+
178
+ return array_slice ($ marking , 0 , 5 );
179
+ }
180
+ return null ;
181
+ }
182
+
183
+ /**
184
+ * Return mod data - due date & require marking.
185
+ *
186
+ * TODO - turnitin, quiz.
187
+ *
188
+ * @param cm_info $mod
189
+ * @param stdClass $assess
190
+ */
191
+ public static function get_mod_data ($ mod , $ assess ): ?stdClass {
192
+ global $ CFG ;
193
+ // Mods have different fields for due date, and require marking.
194
+ switch ($ mod ->modname ) {
195
+ case 'assign ' :
196
+
197
+ // Check mod due date is relevant.
198
+ $ duedate = self ::duedate_in_range ($ mod ->customdata ['duedate ' ]);
199
+ if (!$ duedate ) {
200
+ return null ;
201
+ }
202
+
203
+ // Add dates.
204
+ $ assess ->unixtimestamp = $ duedate ;
205
+ $ assess ->duedate = date ('jS M ' , $ duedate );
206
+
207
+ // Require marking.
208
+ require_once ($ CFG ->dirroot .'/mod/assign/locallib.php ' );
209
+ $ context = context_module::instance ($ mod ->id );
210
+ $ assignment = new assign ($ context , $ mod , $ mod ->course );
211
+ $ assess ->requiremarking = $ assignment ->count_submissions_need_grading ();
212
+ if (!$ assess ->requiremarking ) {
213
+ return null ;
214
+ }
215
+ $ assess ->markingurl = new moodle_url ('/mod/ ' . $ mod ->modname . '/view.php ' ,
216
+ ['id ' => $ assess ->cmid , 'action ' => 'grader ' ]
217
+ );
218
+
219
+ // Return template data.
220
+ return $ assess ;
221
+
222
+ // TODO - quiz - 'timeclose' ?.
223
+ case 'quiz ' :
224
+ return null ;
225
+ // TODO - turnitin.
226
+ default :
227
+ return null ;
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Return if course has started (startdate) and has not ended (enddate).
233
+ *
234
+ * @param stdClass $course
235
+ */
236
+ public static function is_course_current (stdClass $ course ): bool {
237
+ // Start date.
238
+ if ($ course ->startdate > time ()) {
239
+ return false ; // Before the start date.
240
+ }
241
+
242
+ // End date.
243
+ if (isset ($ course ->enddate )) {
244
+ if ($ course ->enddate == 0 ) {
245
+ return true ; // Enddate is set to 0 when no end date, show course.
246
+ }
247
+ // Past course enddate.
248
+ // Note - UCL add 3 mouths for late summer assessments, so course can end before assessments are due.
249
+ if (time () > strtotime ('+3 month ' , $ course ->enddate )) {
250
+ return false ;
251
+ }
252
+ }
253
+ return true ; // All good, show course.
254
+ }
255
+
256
+ /**
257
+ * Return if a due date in the date range.
258
+ *
259
+ * @param int $duedate
260
+ */
261
+ public static function duedate_in_range (int $ duedate ): ?int {
262
+ // Only show dates within UCL limits for marking.
263
+ $ startdate = strtotime ('-2 month ' ); // Longer time to try retain overdue marking at the top.
264
+ $ cutoffdate = strtotime ('+1 month ' );
265
+ // If duedate is beyond cutoff.
266
+ if ($ duedate > $ cutoffdate ) {
267
+ return false ;
268
+ }
269
+ // If duedate is too far in the past.
270
+ if ($ duedate < $ startdate ) {
271
+ return false ;
272
+ }
273
+ return $ duedate ;
274
+ }
275
+
73
276
/**
74
277
* Get my feedback call for a user.
75
278
*
76
279
* Return users 5 most recent feedbacks.
77
280
* @param stdClass $user
78
281
* @return array feedback items.
79
- * @throws coding_exception
80
- * @throws dml_exception
81
- * @throws moodle_exception
82
282
*/
83
- public function fetch_feedback ($ user ): array {
283
+ public function fetch_feedback ($ user ): ? array {
84
284
global $ DB ;
85
285
86
286
$ submissions = $ this ->get_submissions ($ user );
87
287
88
288
// No feedback.
89
289
if (!$ submissions ) {
90
- return [] ;
290
+ return null ;
91
291
}
92
292
93
293
// Template data for mustache.
@@ -108,9 +308,9 @@ public function fetch_feedback($user): array {
108
308
109
309
$ feedback = new stdClass ();
110
310
$ feedback ->id = $ f ->gradeid ;
111
- $ feedback ->date = date ('jS F ' , $ f ->lastmodified );
112
- $ feedback ->activityname = $ f ->name ;
113
- $ feedback ->link = new moodle_url ('/mod/ ' .$ f ->modname .'/view.php ' , ['id ' => $ f ->cmid ]);
311
+ $ feedback ->releaseddate = date ('jS M ' , $ f ->lastmodified );
312
+ $ feedback ->name = $ f ->name ;
313
+ $ feedback ->url = new moodle_url ('/mod/ ' .$ f ->modname .'/view.php ' , ['id ' => $ f ->cmid ]);
114
314
115
315
// Course.
116
316
$ course = $ DB ->get_record ('course ' , ['id ' => $ f ->course ]);
@@ -138,7 +338,8 @@ public function fetch_feedback($user): array {
138
338
139
339
$ template ->feedback [] = $ feedback ;
140
340
}
141
- return $ template ->feedback ;
341
+
342
+ return $ template ->feedback ?: null ;
142
343
}
143
344
144
345
/**
0 commit comments