2 * Copyright (c) 2016-2019 S. Gilles <sgilles@math.umd.edu>
4 * Permission to use, copy, modify, and/or distribute this software
5 * for any purpose with or without fee is hereby granted, provided
6 * that the above copyright notice and this permission notice appear
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 #include <curl/curl.h>
28 #include <yajl_parse.h>
33 /* Write output to stdout */
35 write_out_everything(char *course_id
, map
*students
, map
**grades
, map
*totals
,
36 map
*partials
, size_t assignments_num
,
37 char **assignment_ids
, map
*assignments
)
41 char **student_names
= 0;
48 map_get_keys(students
, &student_names
, &students_num
);
49 printf("\"Name\",\"ID\"");
51 for (j
= 0; j
< assignments_num
; ++j
) {
52 printf(",\"%s:%s (", course_id
, assignment_ids
[j
]);
53 res
= map_get(assignments
, assignment_ids
[j
]);
57 print_esc_0x22(res
[0]);
64 printf(",\"Total\",\"Letter Grade\"");
68 printf(",\"Partial\",\"Partial Letter Grade\"");
73 for (j
= 0; j
< students_num
; ++j
) {
74 name
= student_names
[j
];
75 id
= map_get(students
, name
);
84 printf("\",\"%s\"", id
[0]);
86 for (k
= 0; k
< assignments_num
; ++k
) {
87 score
= map_get(&((*grades
)[k
]), id
[0]);
92 !strcasecmp(score
[1], "true")) {
96 print_esc_0x22(score
[0]);
103 score
= map_get(totals
, id
[0]);
108 print_esc_0x22(score
[0]);
115 print_esc_0x22(score
[1]);
122 score
= map_get(partials
, id
[0]);
128 print_esc_0x22(score
[2]);
136 print_esc_0x22(score
[3]);
149 main(int argc
, char **argv
)
153 char *auth_token
= 0;
155 const char *fn_students
[] = { "sortable_name", "id", 0 };
156 const char *fn_scores
[] = { "user_id", "score", "excused", 0 };
157 const char *fn_totals
[] = { "user_id", "final_score", "final_grade",
158 "current_score", "current_grade", 0 };
159 const char *fn_assignments
[] = { "id", "name", 0 };
160 uint_fast8_t fetch_all_arg
= 0;
161 uint_fast8_t totals_arg
= 0;
162 uint_fast8_t partials_arg
= 0;
163 char **assignment_ids
= 0;
164 map students
= { 0 };
166 map aggregates
= { 0 };
167 map assignments
= { 0 };
169 size_t assignments_num
= 0;
174 setlocale(LC_ALL
, "");
176 if (!(assignment_ids
= calloc((argc
/ 2), sizeof *assignment_ids
))) {
182 while ((opt
= getopt(argc
, argv
, "c:a:Atp")) != -1) {
188 assignment_ids
[assignments_num
++] = optarg
;
206 fprintf(stderr
, "both -A and -a provided, ignoring -a\n");
211 fprintf(stderr
, "course-id is mandatory\n");
215 if (!fetch_all_arg
&&
220 fprintf(stderr
, "one of -a, -A, -t, -p is mandatory\n");
224 if (!(grades
= calloc(assignments_num
, sizeof *grades
))) {
230 curl_global_init(CURL_GLOBAL_DEFAULT
);
232 if (!(url_base
= get_url_base())) {
233 /* Error should have already been printed */
238 if (!(auth_token
= get_auth_token())) {
239 /* Error should have already been printed */
244 /* Get a list of all students, so we can find out their names */
245 len
= snprintf(0, 0, "%s/api/v1/courses/%s/students?per_page=9999",
246 url_base
, course_id
);
249 ret
= errno
= EOVERFLOW
;
254 if (!(built_uri
= malloc(len
+ 1))) {
260 sprintf(built_uri
, "%s/api/v1/courses/%s/students?per_page=9999",
261 url_base
, course_id
);
263 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_students
, 0,
268 /* Get a list of all assignments, so we can find out their names */
270 len
= snprintf(0, 0, "%s/api/v1/courses/%s/assignments?per_page=9999",
271 url_base
, course_id
);
274 ret
= errno
= EOVERFLOW
;
279 if (!(built_uri
= malloc(len
+ 1))) {
285 sprintf(built_uri
, "%s/api/v1/courses/%s/assignments?per_page=9999",
286 url_base
, course_id
);
288 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_assignments
, 0,
295 free(assignment_ids
);
299 map_get_keys(&assignments
, &assignment_ids
, &assignments_num
);
301 if (!assignments_num
&&
304 perror(L("map_get_keys"));
308 if (!(grades
= calloc(assignments_num
, sizeof *grades
))) {
315 for (j
= 0; j
< assignments_num
; ++j
) {
317 len
= snprintf(0, 0, "%s/api/v1/courses/%s/assignments/%s/"
318 "submissions?per_page=9999", url_base
,
323 ret
= errno
= EOVERFLOW
;
328 if (!(built_uri
= malloc(len
+ 1))) {
334 sprintf(built_uri
, "%s/api/v1/courses/%s/assignments/%s/"
335 "submissions?per_page=9999", url_base
,
339 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_scores
,
349 "%s/api/v1/courses/%s/enrollments?per_page=9999",
354 ret
= errno
= EOVERFLOW
;
359 if (!(built_uri
= malloc(len
+ 1))) {
366 "%s/api/v1/courses/%s/enrollments?per_page=9999",
370 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_totals
,
376 write_out_everything(course_id
, &students
, &grades
, (totals_arg
?
378 (partials_arg
? &aggregates
: 0), assignments_num
,
379 assignment_ids
, &assignments
);
385 curl_global_cleanup();
386 free(assignment_ids
);
387 map_clean(&students
);
388 map_clean(&assignments
);
389 map_clean(&aggregates
);
391 if (assignments_num
) {
393 map_clean(&grades
[--assignments_num
]);
394 } while (assignments_num
);