These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | #!/usr/bin/env php |
||
2 | <?php |
||
3 | |||
4 | define('DEBUGGING', DEBUGGING_LOG); |
||
5 | define('IGNORE_LTI', true); |
||
6 | |||
7 | require_once __DIR__ . '/../common.inc.php'; |
||
8 | require_once __DIR__ . '/../constants.inc.php'; |
||
9 | |||
10 | // http://stackoverflow.com/a/21896310 |
||
11 | function hoursRange($lower = 0, $upper = 86400, $step = 3600, $keyFormat = '', $value = '', $valueIsFormat = false) |
||
12 | { |
||
13 | $times = array(); |
||
14 | |||
15 | if (empty( $value ) && $valueIsFormat) { |
||
16 | $value = 'g:i a'; |
||
17 | } |
||
18 | |||
19 | if (empty($keyFormat)) { |
||
20 | $keyFormat = 'g:i a'; |
||
21 | } |
||
22 | |||
23 | foreach (range( $lower, $upper, $step ) as $increment) { |
||
24 | $increment = gmdate( $keyFormat, $increment ); |
||
25 | |||
26 | list( $hour, $minutes ) = explode( ':', $increment ); |
||
27 | |||
28 | $date = new DateTime( $hour . ':' . $minutes ); |
||
29 | |||
30 | $times[(string) $increment] = ($valueIsFormat ? $date->format( $value ) : $value); |
||
31 | } |
||
32 | |||
33 | return $times; |
||
34 | } |
||
35 | |||
36 | function collectStatistics($term, $api, $sql, $metadata) |
||
37 | { |
||
38 | // TODO make this configurable |
||
39 | $courses = $api->get( |
||
40 | '/accounts/132/courses', |
||
41 | array( |
||
42 | 'with_enrollments' => 'true', |
||
43 | 'enrollment_term_id' => $term |
||
44 | ) |
||
45 | ); |
||
46 | |||
47 | // so that everything has a consistent benchmark |
||
48 | $timestamp = time(); |
||
49 | |||
50 | foreach ($courses as $course) { |
||
51 | $statistic = array( |
||
52 | 'timestamp' => date(DATE_ISO8601, $timestamp), |
||
53 | 'course[id]' => $course['id'], |
||
54 | 'course[name]' => $course['name'], |
||
55 | 'course[account_id]' => $course['account_id'], |
||
56 | 'gradebook_url' => 'https://' . parse_url($metadata['CANVAS_API_URL'], PHP_URL_HOST) . "/courses/{$course['id']}/gradebook2", |
||
57 | 'assignments_due_count' => 0, |
||
58 | 'dateless_assignment_count' => 0, |
||
59 | 'created_after_due_count' => 0, |
||
60 | 'gradeable_assignment_count' => 0, |
||
61 | 'graded_assignment_count' => 0, |
||
62 | 'zero_point_assignment_count' => 0, |
||
63 | 'analytics_page' => $metadata['APP_URL'] . "/course-summary.php?course_id={$course['id']}" |
||
64 | ); |
||
65 | |||
66 | $teacherIds = array(); |
||
67 | $teacherNames = array(); |
||
68 | $teachers = $api->get( |
||
69 | "/courses/{$course['id']}/enrollments", |
||
70 | array( |
||
71 | 'type[]' => 'TeacherEnrollment' |
||
72 | ) |
||
73 | ); |
||
74 | foreach ($teachers as $teacher) { |
||
75 | $teacherIds[] = $teacher['user']['id']; |
||
76 | $teacherNames[] = $teacher['user']['sortable_name']; |
||
77 | } |
||
78 | $statistic['teacher[id]s'] = serialize($teacherIds); |
||
79 | $statistic['teacher[sortable_name]s'] = serialize($teacherNames); |
||
80 | |||
81 | $account = $api->get("/accounts/{$course['account_id']}"); |
||
82 | $statistic['account[name]'] = $account['name']; |
||
83 | |||
84 | // ignore classes with no teachers (how do they even exist? weird.) |
||
85 | if (count($teacherIds) != 0) { |
||
86 | $statistic['student_count'] = 0; |
||
87 | $students = $api->get( |
||
88 | "/courses/{$course['id']}/enrollments", |
||
89 | array( |
||
90 | 'type[]' => 'StudentEnrollment' |
||
91 | ) |
||
92 | ); |
||
93 | $statistic['student_count'] = $students->count(); |
||
94 | |||
95 | // ignore classes with no students |
||
96 | if ($statistic['student_count'] != 0) { |
||
97 | $assignments = $api->get( |
||
98 | "/courses/{$course['id']}/assignments" |
||
99 | ); |
||
100 | |||
101 | $gradedSubmissionsCount = 0; |
||
102 | $turnAroundTimeTally = 0; |
||
103 | $leadTimeTally = 0; |
||
104 | $createdModifiedHistogram = array( |
||
105 | HISTOGRAM_CREATED => hoursRange(0, 86400, 3600, '', 0), |
||
106 | HISTOGRAM_MODIFIED => hoursRange(0, 86400, 3600, '', 0) |
||
107 | ); |
||
108 | |||
109 | foreach ($assignments as $assignment) { |
||
110 | // ignore unpublished assignments |
||
111 | if ($assignment['published'] == true) { |
||
112 | // check for due dates |
||
113 | $dueDate = new DateTime($assignment['due_at']); |
||
114 | $dueDate->setTimeZone(new DateTimeZone(SCHOOL_TIME_ZONE)); |
||
115 | if (($timestamp - $dueDate->getTimestamp()) > 0) { |
||
116 | $statistic['assignments_due_count']++; |
||
117 | |||
118 | // update created_modified_histogram |
||
119 | $createdAt = new DateTime($assignment['created_at']); |
||
120 | $createdAt->setTimeZone(new DateTimeZone(SCHOOL_TIME_ZONE)); |
||
121 | $updatedAt = new DateTime($assignment['updated_at']); |
||
122 | $updatedAt->setTimeZone(new DateTimeZone(SCHOOL_TIME_ZONE)); |
||
123 | $createdModifiedHistogram[HISTOGRAM_CREATED][$createdAt->format('g:00 a')]++; |
||
124 | if ($createdAt != $updatedAt) { |
||
125 | $createdModifiedHistogram[HISTOGRAM_MODIFIED][$updatedAt->format('g:00 a')]++; |
||
126 | } |
||
127 | |||
128 | // tally lead time on the assignment |
||
129 | $leadTimeTally += strtotime($assignment['due_at']) - strtotime($assignment['created_at']); |
||
130 | |||
131 | // was the assignment created after it was due? |
||
132 | if (strtotime($assignment['due_at']) < strtotime($assignment['created_at'])) { |
||
133 | $statistic['created_after_due_count']++; |
||
134 | } |
||
135 | |||
136 | // ignore ungraded assignments |
||
137 | if ($assignment['grading_type'] != 'not_graded') { |
||
138 | $statistic['gradeable_assignment_count']++; |
||
139 | $hasBeenGraded = false; |
||
140 | |||
141 | // tally zero point assignments |
||
142 | if ($assignment['points_possible'] == '0') { |
||
143 | $statistic['zero_point_assignment_count']++; |
||
144 | } |
||
145 | |||
146 | // build submission statistic |
||
147 | $submissions = $api->get( |
||
148 | "/courses/{$course['id']}/assignments/{$assignment['id']}/submissions" |
||
149 | ); |
||
150 | foreach ($submissions as $submission) { |
||
151 | if ($submission['workflow_state'] == 'graded') { |
||
152 | if ($hasBeenGraded == false) { |
||
153 | $hasBeenGraded = true; |
||
154 | $statistic['graded_assignment_count']++; |
||
155 | } |
||
156 | $gradedSubmissionsCount++; |
||
157 | $turnAroundTimeTally += max( |
||
158 | 0, |
||
159 | strtotime($submission['graded_at']) - strtotime($assignment['due_at']) |
||
160 | ); |
||
161 | } |
||
162 | } |
||
163 | |||
164 | if (!$hasBeenGraded) { |
||
165 | if (array_key_exists('oldest_ungraded_assignment_due_date', $statistic)) { |
||
166 | if (strtotime($assignment['due_at']) < strtotime($statistic['oldest_ungraded_assignment_due_date'])) { |
||
167 | $statistic['oldest_ungraded_assignment_due_date'] = $assignment['due_at']; |
||
168 | $statistic['oldest_ungraded_assignment_url'] = $assignment['html_url']; |
||
169 | $statistic['oldest_ungraded_assignment_name'] = $assignment['name']; |
||
170 | } |
||
171 | } else { |
||
172 | $statistic['oldest_ungraded_assignment_due_date'] = $assignment['due_at']; |
||
173 | $statistic['oldest_ungraded_assignment_url'] = $assignment['html_url']; |
||
174 | $statistic['oldest_ungraded_assignment_name'] = $assignment['name']; |
||
175 | } |
||
176 | } |
||
177 | } |
||
178 | } else { |
||
179 | $statistic['dateless_assignment_count']++; |
||
180 | } |
||
181 | } |
||
182 | } |
||
183 | |||
184 | $statistic['created_modified_histogram'] = serialize($createdModifiedHistogram); |
||
185 | |||
186 | // calculate average submissions graded per assignment (if non-zero) |
||
187 | if ($statistic['gradeable_assignment_count'] && $statistic['student_count']) { |
||
188 | $statistic['average_submissions_graded'] = $gradedSubmissionsCount / ($statistic['gradeable_assignment_count'] * $statistic['student_count']); |
||
189 | } |
||
190 | |||
191 | // calculate the average lead-time on assignments |
||
192 | if ($statistic['assignments_due_count']) { |
||
193 | $statistic['average_assignment_lead_time'] = $leadTimeTally / $statistic['assignments_due_count'] / 60 / 60 / 24; |
||
194 | } |
||
195 | |||
196 | // calculate average grading turn-around per submission |
||
197 | if ($gradedSubmissionsCount) { |
||
198 | $statistic['average_grading_turn_around'] = $turnAroundTimeTally / $gradedSubmissionsCount / 60 / 60 / 24; |
||
199 | } |
||
200 | |||
201 | $query = "INSERT INTO `course_statistics`"; |
||
202 | $fields = array(); |
||
203 | $values = array(); |
||
204 | while (list($field, $value) = each($statistic)) { |
||
205 | $fields[] = $field; |
||
206 | $values[] = $value; |
||
207 | } |
||
208 | $query .= ' (`' . implode('`, `', $fields) . "`) VALUES ('" . implode("', '", $values) . "')"; |
||
209 | $result = $sql->query($query); |
||
210 | /* displayError( |
||
0 ignored issues
–
show
|
|||
211 | array( |
||
212 | 'gradedSubmissionsCount' => $gradedSubmissionsCount, |
||
213 | 'turnAroundTimeTally' => $turnAroundTimeTally, |
||
214 | 'statistic' => $statistic, |
||
215 | 'query' => $query, |
||
216 | 'result' => $result |
||
217 | ), |
||
218 | true |
||
219 | ); */ |
||
220 | } |
||
221 | } |
||
222 | } |
||
223 | } |
||
224 | |||
225 | //debugFlag('START'); |
||
226 | |||
227 | /* create an API connector if not already extant */ |
||
228 | if (empty($api)) { |
||
229 | $api = new CanvasPest($metadata['CANVAS_API_URL'], $metadata['CANVAS_API_TOKEN']); |
||
230 | } |
||
231 | |||
232 | /* collect data on terms currently in session */ |
||
233 | $terms = $api->get('accounts/1/terms'); |
||
234 | $now = strtotime('now'); |
||
235 | foreach ($terms['enrollment_terms'] as $term) { |
||
236 | if (isset($term['start_at']) && isset($term['end_at'])) { |
||
237 | if ((strtotime($term['start_at']) <= $now) && ($now <= strtotime($term['end_at']))) { |
||
238 | collectStatistics($term['id'], $api, $sql, $metadata); |
||
239 | } |
||
240 | } |
||
241 | } |
||
242 | |||
243 | /* check to see if this data collection has been scheduled. If it hasn't, |
||
244 | schedule it to run nightly. */ |
||
245 | /* thank you http://stackoverflow.com/a/4421284 ! */ |
||
246 | $crontab = DATA_COLLECTION_CRONTAB . ' ' . realpath('.') . '/data-collection.sh'; |
||
247 | $crontabs = shell_exec('crontab -l'); |
||
248 | if (strpos($crontabs, $crontab) === false) { |
||
249 | $filename = md5(time()) . '.txt'; |
||
250 | file_put_contents("/tmp/$filename", $crontabs . $crontab . PHP_EOL); |
||
251 | shell_exec("crontab /tmp/$filename"); |
||
252 | debugFlag("added new scheduled data-collection to crontab"); |
||
253 | } |
||
254 | |||
255 | //debugFlag('FINISH'); |
||
256 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.