-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcourse_get_courses_by_field.py
110 lines (82 loc) · 3.75 KB
/
course_get_courses_by_field.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
"""Get Moodle course data from API.
Usage:
course_get_courses_by_field.py [--json] <shortname>
Options:
<shortname> a CCA section code formatted like {department code}-
{course number}-{section number}-{semester code} e.g.
ANIMA-1000-1-2021SP.
-h --help Show this screen.
--version Show version.
--json JSON output.
"""
import json
from docopt import docopt
import requests
import config
# https://moodle.cca.edu/webservice/rest/server.php?wstoken=...&wsfunction=core_course_get_courses_by_field&moodlewsrestformat=json&field=shortname&value=EXCHG-3740-1-2019FA
def get_mdl_course(shortname):
"""find out Moodle's internal ID for a course (so you can link to it)
returns: a string composed of numbers e.g. "8452"
`shortname` is a string structured like so:
{section code}-{any cross-listed section codes}-{term}
e.g. for an unlisted section from Fall 2019 it looks like:
EXCHG-3740-1-2019FA
For a once-crosslisted section it looks like:
LITPA-2000-15-WRLIT-2100-13-2019FA
For a multi-crosslisted section, sections _appear_ (@TODO confirm) to be
listed in first alphabetical order by department and within department by
ascending numerical order, thus a triple-crosslisted section across two
(CERAM & CRAFT) departments looks like:
CERAM-1000-1-CERAM-2700-2-CERAM-3700-2-CRAFT-2700-3-2019FA
"""
url = config.url
params = {
# found at https://moodle.cca.edu/admin/settings.php?section=webservicetokens
"wstoken": config.token,
"wsfunction": "core_course_get_courses_by_field",
"moodlewsrestformat": "json",
# theoretically we can search using ID, a list of IDs, idnumber,
# or category but in reality shortname is only viable option
"field": "shortname",
"value": shortname,
}
response = requests.get(url, params=params)
data = response.json()
courses = data.get("courses")
if type(courses) == list:
if len(courses) > 0:
# theoretically this is always a single-entry array
return courses[0]
"""
If no course matches the shortname, there's no "exception" in the response
and we receive a pair of empty arrays:
{ courses: [ ], warnings: [ ] }
For now, we return empty string but Portal may want some specific
handling for this situation (which will definitely occur).
"""
return ""
else:
"""
Moodle sends an HTTP 200 response back on errors with details in the JSON.
Below are just a few examples I've run into.
If it doesn't recognize the structure of the criteria parameter in the URL,
you get this error message:
{ exception: "invalid_parameter_exception", errorcode: "invalidparameter",
message: "Invalid parameter value detected" }
If the web service being specified doesn't exist, you get:
{ exception: "dml_missing_record_exception", errorcode: "invalidrecord",
message: "Can not find data record in database table external_functions."}
If the token you're using is related to a Service that doesn't have the
necessary permissions you get:
{ exception: "webservice_access_exception", errorcode: "accessexception",
message: "Access control exception" }
"""
return "Error: {}".format(data["message"])
return data
def main(arguments):
if arguments.get("--json"):
return print(json.dumps(get_mdl_course(arguments["<shortname>"])))
return print(get_mdl_course(arguments["<shortname>"]))
# CLI use: pass shortname on the command line
if __name__ == "__main__":
main(docopt(__doc__, version="course_get_courses_by_field 1.0")) # type: ignore