· 5 years ago · Oct 02, 2020, 07:24 PM
1<?php
2
3/**
4 * Entrada [ http://www.entrada-project.org ]
5 *
6 * Cron job responsible for generating course syllabi.
7 *
8 * @author Organisation: Queen's University
9 * @author Unit: School of Medicine
10 * @author Developer: Ryan Warner <ryan.warner@queensu.ca>
11 * @copyright Copyright 2013 Queen's University. All Rights Reserved.
12 *
13*/
14
15set_time_limit(0);
16set_include_path(implode(PATH_SEPARATOR, array(
17 dirname(__FILE__) . "/../core",
18 dirname(__FILE__) . "/../core/includes",
19 dirname(__FILE__) . "/../core/library",
20 dirname(__FILE__) . "/../core/library/vendor",
21 get_include_path(),
22)));
23
24require_once("init.inc.php");
25
26$org_id = 0;
27
28if (isset($argv[1])) {
29 $org_id = (int) $argv[1];
30}
31
32if ($org_id && is_dir(CACHE_DIRECTORY) && is_writable(CACHE_DIRECTORY)) {
33 /**
34 * Lock present: application busy: quit
35 */
36 if (!file_exists(CACHE_DIRECTORY."/generate_syllabi.lck")) {
37 if (file_put_contents(CACHE_DIRECTORY."/generate_syllabi.lck", "L_O_C_K")) {
38 application_log("notice", "Syllabus generation lock file created.");
39
40 $org_courses = Models_Course::fetchAllByOrg($org_id);
41 if ($org_courses) {
42 foreach ($org_courses as $org_course) {
43 $g_start = time();
44 $syllabus = Models_Syllabus::fetchRowByCourseID($org_course->getID(), 1);
45 echo "\n---------------------------------------------------------------------\n";
46 echo "Starting syllabus generation for course: [".$org_course->getCourseCode()."-".$syllabus->getID()."]\n";
47 if (!is_null($syllabus->getID())) {
48 unset($pages_html);
49 $ENTRADA_USER = new User();
50 $ENTRADA_USER->setActiveOrganisation($org_id);
51 $cperiods = Models_Curriculum_Period::fetchAllByOrgID($org_id);
52
53 if (!empty($cperiods)) {
54 foreach ($cperiods as $cperiod) {
55
56 if ($cperiod) {
57 $course = $syllabus->getCourse();
58 $unique_id = $course->getID() . '-' . $cperiod->getCperiodID();
59
60 $community_course_cperiod = Models_Community_CourseGroup::fetchRowByCourseIDCperiodID($course->getID(), $cperiod->getCperiodID());
61 if (!$community_course_cperiod) {
62 continue;
63 }
64
65 $course_contacts = $course->getContacts();
66 $enrolment_period = !empty($cperiod->getCurriculumPeriodTitle()) ? $cperiod->getCurriculumPeriodTitle() : date("F jS, Y", $cperiod->getStartDate()) . " to " . date("F jS, Y", $cperiod->getFinishDate());
67
68 if(file_exists($ENTRADA_TEMPLATE->absolute()."/syllabus/cover.html")) {
69 $cover_template = file_get_contents($ENTRADA_TEMPLATE->absolute()."/syllabus/cover.html");
70 $cover_search_terms = array(
71 "%COURSE_CODE%",
72 "%COURSE_NAME%",
73 "%E_PERIOD%",
74 "%AGENT_CONTACT_NAME%",
75 "%AGENT_CONTACT_EMAIL%",
76 "%YEAR%",
77 "%ENTRADA_URL%",
78 "%GENERATED%"
79 );
80 $cover_replace_values = array(
81 $course->getCourseCode(),
82 $course->getCourseName(),
83 $enrolment_period,
84 $AGENT_CONTACTS["general-contact"]["name"],
85 $AGENT_CONTACTS["general-contact"]["email"],
86 date("Y"),
87 ENTRADA_URL,
88 date(DEFAULT_FULLDATE_FORMAT)
89 );
90 file_put_contents(SYLLABUS_STORAGE."/cover-".$unique_id.".html", str_replace($cover_search_terms, $cover_replace_values, $cover_template));
91 }
92 $search_terms = array();
93 include $ENTRADA_TEMPLATE->absolute()."/syllabus/page-whitelist.inc.php";
94 if(file_exists($ENTRADA_TEMPLATE->absolute()."/syllabus/".$syllabus->getTemplate().".php")) {
95 $template = file_get_contents($ENTRADA_TEMPLATE->absolute()."/syllabus/".$syllabus->getTemplate().".php");
96 if (!empty($page_whitelist[$course->getOrganisationID()][$syllabus->getTemplate()])) {
97 $whitelist = array_keys($page_whitelist[$course->getOrganisationID()][$syllabus->getTemplate()]);
98 $cc_key = array_search("course_calendar", $whitelist);
99 if ($cc_key) {
100 unset($whitelist[$cc_key]);
101 }
102 $search_terms = $page_whitelist[$course->getOrganisationID()][$syllabus->getTemplate()];
103 } else {
104 $whitelist = $page_whitelist[$course->getOrganisationID()]["default"];
105 }
106 }
107
108 $pages = $course->getPages(NULL, $community_course_cperiod->getCommunityID(), $whitelist);
109 $pages_html = array();
110 foreach ($pages as $page) {
111 if (strlen(trim($page["page_content"])) > 0) {
112 $pages_html[$page["page_url"]] = "";
113 $pages_html[$page["page_url"]] .= "<div class=\"page ".($level == 1 ? "break" : "")."\">";
114 $pages_html[$page["page_url"]] .= "<h1>".$page["page_title"]."</h1>";
115 $pages_html[$page["page_url"]] .= "<div class=\"page-content\">".$page["page_content"]."</div>";
116 $pages_html[$page["page_url"]] .= "</div>";
117 }
118 }
119
120 $contact_types = array(
121 "director" => "Director",
122 "ccoordinator" => "Curricular Coordinator",
123 "pcoordinator" => "Program Coordinator"
124 );
125
126 $contacts_html = "";
127
128 if (is_array($course_contacts) && !empty($course_contacts)) {
129 $contacts_html .= "<h1>Course Contacts</h1>";
130 foreach ($course_contacts as $contact_type => $contacts) {
131 $contacts_html .= "<p><strong>". $contact_types[$contact_type] . (count($contacts) > 1 ? "s" : "") . "</strong></p>";
132 foreach ($contacts as $contact_id => $contact) {
133 $contacts_html .= "<div class=\"contact\">";
134 $contacts_html .= "<p><strong>" . ($contact->getPrefix() ? $contact->getPrefix() . " " : "") . $contact->getFullName()."</strong></p>";
135 if ($contact_type != "director") {
136 $contacts_html .= "<p>".
137 ($contact->getTelephone() ? "Telephone: " . $contact->getTelephone() : "").
138 ($contact->getFax() ? ($contact->getTelephone() ? "<br />" : "") . "Fax: ".$contact->getFax() : "").
139 ($contact->getOfficeHours() ? ($contact->getFax() || $contact->getTelephone() ? "<br /><br />" : "") . "Office Hours: " . $contact->getOfficeHours() : "").
140 "</p>";
141 }
142 $contacts_html .= "<p><a href=\"mailto:".$contact->getEmail()."\">".$contact->getEmail()."</a></p>";
143 $contacts_html .= "</div>";
144 }
145 }
146 }
147
148 if (is_null($pages_html["course_contacts"]) && in_array("%COURSE_CONTACTS%", $search_terms)) {
149 $pages_html["course_contacts"] = $contacts_html;
150 }
151
152 $events = $course->getEvents($cperiod->getStartDate(), $cperiod->getFinishDate());
153 $calendar_html = "";
154 if (is_array($events) && !empty($events)) {
155 foreach ($events as $event) {
156 $calendar_html .= "<div class=\"event\">";
157 $calendar_html .= "<p><strong>".$event["event_title"]."</strong></p>";
158 $calendar_html .= "<p><small>".date("l, F jS, Y, g:i A", $event["event_start"])." to ".date(date("z", $event["event_finish"]) == date("z", $event["event_start"]) ? "g:i A" : "l, F jS, Y, g:i A", $event["event_finish"])."</small></p>";
159 $calendar_html .= "<p>".$event["event_description"]."</p>";
160
161 if ($event["objectives"]) {
162 $calendar_html .= "<p style=\"margin:0px 30px;\">Event Objectives: <em>" . html_encode(implode(", ", $event["objectives"]))."</em>";
163 }
164
165 $calendar_html .= "</div>";
166 }
167 }
168
169 // Event Types By Course Report Start
170 $output = array();
171 $appendix = array();
172
173 $courses_included = array();
174 $eventtype_legend = array();
175
176 $event_types = Models_EventType::fetchAllByOrganisationID($course->getOrganisationID());
177 if ($event_types) {
178 foreach ($event_types as $event_type) {
179 $eventtype_legend[$event_type->getID()] = $event_type->getEventTypeTitle();
180
181 $results = $course->getEventsByEventTypeID($event_type->getID(), $cperiod->getStartDate(), $cperiod->getFinishDate());
182 $course_id = $course->getID();
183 if ($results) {
184 $courses_included[$course_id] = $course_list[$course_id]["code"] . " - " . $course_list[$course_id]["name"];
185
186 foreach ($results as $result) {
187 $output[$course_id]["events"][$event_type->getID()]["duration"] += $result["duration"];
188 $output[$course_id]["events"][$event_type->getID()]["events"] += 1;
189
190 $appendix[$course_id][$result["event_id"]][] = $result;
191 }
192
193 $output[$course_id]["total_duration"] += $output[$course_id]["events"][$event_type->getID()]["duration"];
194 $output[$course_id]["total_events"] += $output[$course_id]["events"][$event_type->getID()]["events"];
195 }
196 }
197 }
198
199 if (count($output)) {
200 $eventtypes_html = "<h1>" . $translate->_("Learning Event Types") . "</h1>";
201 // @todo: move this to external api call
202 // $eventtypes_html .= "<div class=\"center\"><img src=\"".str_replace("https","http",ENTRADA_URL)."/cron/syllabus_gen.php?mode=graph&course_id=".$course->getID()."&start_date=".strtotime($start_string)."&end_date=".strtotime($end_string)."\" /></div>";
203 foreach ($output as $course_id => $result) {
204 $STATISTICS = array();
205 $STATISTICS["labels"] = array();
206 $STATISTICS["legend"] = array();
207 $STATISTICS["results"] = array();
208
209 $eventtypes_html .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">";
210 $eventtypes_html .= "<thead>";
211 $eventtypes_html .= "<tr>";
212 $eventtypes_html .= "<th style=\"text-align:left;\"><strong>" . $translate->_("Event Type") . "</strong></td>";
213 $eventtypes_html .= "<th style=\"text-align:left;\"><strong>Event Count</strong></td>";
214 $eventtypes_html .= "<th style=\"text-align:left;\"><strong>Hour Count</strong></td>";
215 $eventtypes_html .= "</tr>";
216 $eventtypes_html .= "</thead>";
217 $eventtypes_html .= "<tbody>";
218
219 foreach ($result["events"] as $eventtype_id => $event) {
220 $STATISTICS["labels"][$eventtype_id] = $eventtype_legend[$eventtype_id];
221 $STATISTICS["legend"][$eventtype_id] = $eventtype_legend[$eventtype_id];
222 $STATISTICS["display"][$eventtype_id] = $event["events"];
223
224 $all_events[] = $event["events"];
225 $all_labels[] = $eventtype_legend[$eventtype_id];
226
227 if ($result["total_events"] > 0) {
228 $percent_events = round((($event["events"] / $result["total_events"]) * 100));
229 } else {
230 $percent_events = 0;
231 }
232
233 if ($result["total_duration"] > 0) {
234 $percent_duration = round((($event["duration"] / $result["total_duration"]) * 100));
235 } else {
236 $percent_duration = 0;
237 }
238
239 $eventtypes_html .= "<tr>";
240 $eventtypes_html .= "<td>".html_encode($eventtype_legend[$eventtype_id])."</td>";
241 $eventtypes_html .= "<td class=\"report-hours large\" style=\"text-align: left\">".$event["events"]." (~ ".$percent_events."%)</td>";
242 $eventtypes_html .= "<td class=\"report-hours large\" style=\"text-align: left\">".display_hours($event["duration"])." hrs (~ ".$percent_duration."%)</td>";
243 $eventtypes_html .= "</tr>";
244 }
245 $eventtypes_html .= "</tbody>";
246 $eventtypes_html .= "<tfoot>";
247 $eventtypes_html .= "<tr>";
248 $eventtypes_html .= "<td><strong>Totals</strong></td>";
249 $eventtypes_html .= "<td><strong>".$result["total_events"]."</strong></td>";
250 $eventtypes_html .= "<td><strong>".display_hours($result["total_duration"])." hrs</strong></td>";
251 $eventtypes_html .= "</tr>";
252 $eventtypes_html .= "</tfoot>";
253 $eventtypes_html .= "</table>";
254 }
255 } else {
256 $eventtypes_html = '';
257 }
258
259 list($objectives,$top_level_id) = courses_fetch_objectives($org_id, array($course->getID()), -1, 1, false);
260 $pages_html["course_objectives"] = course_objectives_in_list($objectives, $top_level_id, $top_level_id, false, false, 1, false);
261 if ($objectives) {
262 $pages_html["course_objectives"] = "<h1>Course Objectives</h1>" . $pages_html["course_objectives"];
263 } else {
264 unset($pages_html["course_objectives"]);
265 }
266
267 /* Gradebook */
268 $results = $course->getGradebookByCperiodID($cperiod->getCperiodID());
269 $gradebook_html = "";
270 if ($results) {
271 $gradebook_html = "<h1>Gradebook</h1>";
272
273 $course_lists = Models_Group::fetchAllByCourseID($course->getID(), "course_list", 1, "group_name");
274
275 if ($course_lists) {
276 $cohorts = $course_lists;
277 if (count($course_lists) == 1) {
278 $output_cohort = $course_lists[0];
279 $selected_cohort = $output_cohort->getID();
280 } else {
281 $output_cohort = false;
282 $classlist_found = false;
283 foreach ($course_lists as $key => $course_list) {
284 if (!$classlist_found) {
285 $output_cohort = $course_list;
286 if (isset($selected_classlist) && $selected_classlist && $selected_classlist == $course_list->getID()) {
287 $_SESSION[APPLICATION_IDENTIFIER][$MODULE]["course_list"] = $selected_classlist;
288 $classlist_found = true;
289 }
290 if ($key == (count($course_lists) - 1) && !$classlist_found) {
291 $selected_classlist = $course_list->getID();
292 }
293 }
294 }
295 }
296 } else {
297 $cohorts = $course->getCourseLists($ENTRADA_USER->getActiveOrganisation());
298
299 $output_cohort = false;
300 $cohort_found = false;
301 if ($cohorts) {
302 foreach ($cohorts as $key => $cohort) {
303 if (!$cohort_found) {
304 $output_cohort = $cohort;
305 if (isset($selected_cohort) && $selected_cohort && $selected_cohort == $cohort["group_id"]) {
306 $_SESSION[APPLICATION_IDENTIFIER][$MODULE]["cohort"] = $selected_cohort;
307 $cohort_found = true;
308 }
309 if ($key == (count($cohorts) - 1) && !$cohort_found) {
310 $selected_cohort = $cohort["group_id"];
311 }
312 }
313 }
314 }
315 }
316
317 $assessments = Models_Gradebook_Assessment::fetchAllByCourseIDCperiodID($course->getID(), $cperiod->getCperiodID());
318 $total_grade_weight = 0;
319
320 foreach ($assessments as $assessment) {
321 $result = $assessment->toArray();
322
323 $objectives = $assessment->getObjectives();
324 if ($objectives) {
325 foreach ($objectives as $objective) {
326 $flat_objectives[$objective["objective_type"]][] = $objective["objective_name"];
327 }
328 }
329
330 $gradebook_html .= "<div><strong>".$result["name"]."</strong></div>";
331 $gradebook_html .= "<div>Grade Weight: ".$result["grade_weighting"]. "%</div>";
332 $gradebook_html .= "<div>Assessment Type: ".$result["title"]."</div>";
333
334 if (!empty($flat_objectives["curricular_objective"])) {
335 $gradebook_html .= "<div>Objectives: ";
336 $gradebook_html .= implode(", ", $flat_objectives["curricular_objective"]);
337 $gradebook_html .= "</div>";
338 }
339
340 if (!empty($flat_objectives["clinical_presentation"])) {
341 $gradebook_html .= "<div>MCC Presentations: ";
342 $gradebook_html .= implode(", ", $flat_objectives["clinical_presentation"]);
343 $gradebook_html .= "</div>";
344 }
345
346 $gradebook_html .= "<br />";
347
348 $total_grade_weight += $result["grade_weighting"];
349
350 unset($flat_objectives);
351 unset($objectives);
352 }
353
354 if (isset($total_grade_weight)) {
355 if ($total_grade_weight < '100') {
356 $gradebook_html .= "<div><strong>Total Grade Weight:</strong> <font color=\"#ff2431\">" . $total_grade_weight . "%</font></div>";
357 } else {
358 $gradebook_html .= "<div><strong>Total Grade Weight:</strong> " . $total_grade_weight . "%</div>";
359 }
360 }
361 }
362
363 if (is_null($pages_html["gradebook"]) && in_array("%GRADEBOOK%", $search_terms)) {
364 $pages_html["gradebook"] = $gradebook_html;
365 }
366
367 // Event Types by Course Report End
368 if (is_null($pages_html["learning_event_types"]) && in_array("%LEARNING_EVENT_TYPES%", $search_terms)) {
369 $pages_html["learning_event_types"] = $eventtypes_html;
370 }
371
372 $pages_html["course_calendar"] = "";
373 if (!empty($calendar_html) && in_array("%COURSE_CALENDAR%", $search_terms)) {
374 if ($calendar_html) {
375 $pages_html["course_calendar"] .= "<div class=\"page ".($level == 1 ? "break" : "")."\">";
376 $pages_html["course_calendar"] .= "<h1>Course Calendar</h1>";
377 $pages_html["course_calendar"] .= $calendar_html;
378 $pages_html["course_calendar"] .= "</div>";
379 }
380 }
381
382 echo "pages_html is :" . count($pages_html)."\n";
383 $replacement_values = $pages_html;
384
385 if (file_exists(SYLLABUS_STORAGE."/syllabus-".$unique_id.".html")) {
386 if (!is_dir(SYLLABUS_STORAGE."/archive/")) {
387 mkdir(SYLLABUS_STORAGE."/archive/");
388 }
389 copy(SYLLABUS_STORAGE."/cover-".$unique_id.".html", SYLLABUS_STORAGE."/archive/cover-".$unique_id."-".time().".html");
390 copy(SYLLABUS_STORAGE."/syllabus-".$unique_id.".html", SYLLABUS_STORAGE."/archive/syllabus-".$unique_id."-".time().".html");
391 }
392
393 file_put_contents(SYLLABUS_STORAGE."/syllabus-".$unique_id.".html", str_replace($search_terms, $replacement_values, $template));
394 $command = $APPLICATION_PATH["wkhtmltopdf"]." cover ".SYLLABUS_STORAGE."/cover-".$unique_id.".html toc page ".SYLLABUS_STORAGE."/syllabus-".$unique_id.".html --footer-left \"[section]\" --footer-right \"[page]\" ".SYLLABUS_STORAGE."/".clean_input($course->getCourseCode(), "alphanumeric")."-syllabus-".$unique_id.".pdf";
395 exec($command);
396
397 application_log("success", "Generated syllabus: ".clean_input($course->getCourseCode(), "alphanumeric"). " - " . $course->getCourseName() . " syllabus in ".(time() - $g_start)." seconds.");
398 }
399 }
400 }
401 }
402
403 echo "Syllabus generation for course: [".$org_course->getCourseCode()."] finished\n";
404 echo "---------------------------------------------------------------------\n\n";
405 }
406 } else {
407 application_log("notice", "No syllabi found, no syllabi generated.");
408 }
409 } else {
410 application_log("error", "Could not write syllabus generation lock file, exiting.");
411 }
412
413 /*
414 * Remove the lock file.
415 */
416 if (file_exists(CACHE_DIRECTORY."/generate_syllabi.lck")) {
417 if (!unlink(CACHE_DIRECTORY."/generate_syllabi.lck")) {
418 application_log("error", "Unable to delete syllabus generation lock file: ".CACHE_DIRECTORY."/generate_syllabi.lck");
419 }
420 }
421 } else {
422 application_log("error", "Syllabus generation lock file found, exiting.");
423 }
424} else {
425 application_log("error", "Error with cache directory [".CACHE_DIRECTORY."], not found or not writable.");
426}
427