2 * Copyright (c) 2016-2018 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 */
34 static void write_out_everything(char *course_id
, map
*students
, map
**grades
,
35 map
*totals
, map
*partials
, size_t
36 assignments_num
, char **assignment_ids
,
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]);
148 int main(int argc
, char **argv
)
152 char *auth_token
= 0;
154 const char *fn_students
[] = { "sortable_name", "id", 0 };
155 const char *fn_scores
[] = { "user_id", "score", "excused", 0 };
156 const char *fn_totals
[] = { "user_id", "final_score", "final_grade",
157 "current_score", "current_grade", 0 };
158 const char *fn_assignments
[] = { "id", "name", 0 };
159 uint_fast8_t fetch_all_arg
= 0;
160 uint_fast8_t totals_arg
= 0;
161 uint_fast8_t partials_arg
= 0;
162 char **assignment_ids
= 0;
163 map students
= { 0 };
165 map aggregates
= { 0 };
166 map assignments
= { 0 };
168 size_t assignments_num
= 0;
173 setlocale(LC_ALL
, "");
175 if (!(assignment_ids
= calloc((argc
/ 2), sizeof *assignment_ids
))) {
181 while ((opt
= getopt(argc
, argv
, "c:a:Atp")) != -1) {
187 assignment_ids
[assignments_num
++] = optarg
;
205 fprintf(stderr
, "both -A and -a provided, ignoring -a\n");
210 fprintf(stderr
, "course-id is mandatory\n");
214 if (!fetch_all_arg
&&
219 fprintf(stderr
, "one of -a, -A, -t, -p is mandatory\n");
223 if (!(grades
= calloc(assignments_num
, sizeof *grades
))) {
229 curl_global_init(CURL_GLOBAL_DEFAULT
);
231 if (!(url_base
= get_url_base())) {
232 /* Error should have already been printed */
237 if (!(auth_token
= get_auth_token())) {
238 /* Error should have already been printed */
243 /* Get a list of all students, so we can find out their names */
244 len
= snprintf(0, 0, "%s/api/v1/courses/%s/students?per_page=9999",
245 url_base
, course_id
);
248 ret
= errno
= EOVERFLOW
;
253 if (!(built_uri
= malloc(len
+ 1))) {
259 sprintf(built_uri
, "%s/api/v1/courses/%s/students?per_page=9999",
260 url_base
, course_id
);
262 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_students
, 0,
267 /* Get a list of all assignments, so we can find out their names */
269 len
= snprintf(0, 0, "%s/api/v1/courses/%s/assignments?per_page=9999",
270 url_base
, course_id
);
273 ret
= errno
= EOVERFLOW
;
278 if (!(built_uri
= malloc(len
+ 1))) {
284 sprintf(built_uri
, "%s/api/v1/courses/%s/assignments?per_page=9999",
285 url_base
, course_id
);
287 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_assignments
, 0,
294 free(assignment_ids
);
298 map_get_keys(&assignments
, &assignment_ids
, &assignments_num
);
300 if (!assignments_num
) {
302 perror(L("map_get_keys"));
306 if (!(grades
= calloc(assignments_num
, sizeof *grades
))) {
313 for (j
= 0; j
< assignments_num
; ++j
) {
315 len
= snprintf(0, 0, "%s/api/v1/courses/%s/assignments/%s/"
316 "submissions?per_page=9999", url_base
,
321 ret
= errno
= EOVERFLOW
;
326 if (!(built_uri
= malloc(len
+ 1))) {
332 sprintf(built_uri
, "%s/api/v1/courses/%s/assignments/%s/"
333 "submissions?per_page=9999", url_base
,
337 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_scores
,
347 "%s/api/v1/courses/%s/enrollments?per_page=9999",
352 ret
= errno
= EOVERFLOW
;
357 if (!(built_uri
= malloc(len
+ 1))) {
364 "%s/api/v1/courses/%s/enrollments?per_page=9999",
368 if ((ret
= key_value_extract(built_uri
, auth_token
, fn_totals
,
374 write_out_everything(course_id
, &students
, &grades
, (totals_arg
?
376 (partials_arg
? &aggregates
: 0), assignments_num
,
377 assignment_ids
, &assignments
);
383 curl_global_cleanup();
384 free(assignment_ids
);
385 map_clean(&students
);
386 map_clean(&assignments
);
387 map_clean(&aggregates
);
389 if (assignments_num
) {
391 map_clean(&grades
[--assignments_num
]);
392 } while (assignments_num
);