-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.py
208 lines (166 loc) · 7.45 KB
/
config.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import json
import os
from Canvas import Canvas
from Bartik.Bartik import Bartik
from sys import exit
from UI import uiHelpers
# This file needs some work, esp with handling user input.
def locateConfigFiles():
"""
This function reads the config files from the './config/' directory.
It filters out any non files and any files that don't end in .json
Returns the number of found files and a list of the files
"""
configFileName = [f"./config/{f}" for f in os.listdir("./config/") if
os.path.isfile(f"./config/{f}") and f[len(f) - 4:] == "json"]
return len(configFileName), configFileName
def readConfig(_configFileName):
"""
This function reads the config from the disk and converts it to a python dictionary.
PARAMS:
_configFileName - The file name to load
"""
with open(_configFileName, "r") as jsonDataFile:
configFile = json.load(jsonDataFile)
return configFile
def createNewConfig():
"""
Creates a new config file.
Config file must contain an api key,
the course ID, the user ID, and the canvas endpoint.
It also must contain the assignment list.
This function walks the user through the creation, and builds a new config file to be saved and loaded.
"""
apiKey = str(input("Enter your Canvas api key: "))
userId = str(input("Enter your Canvas user id: "))
endpoint = str(input("Enter your Canvas endpoint: "))
canvas = Canvas(_API_KEY=apiKey, _USER_ID=userId, _ENDPOINT=endpoint)
tenantId = str(input("Enter your Azure AD Tenant Id: "))
bartikUrl = str(input("Enter bartik url"))
bartikUserName = str(input("Enter bartik username"))
bartikPassword = str(input("Enter bartik password"))
bartik = Bartik(bartikUrl, bartikUserName, bartikPassword)
bartikCourseNumber = str(input("Enter course number"))
bartik.openSession()
bartikCourse = bartik.getCourseId(bartikCourseNumber)
bartik.closeSession()
print("Retrieving eligible courses...", end="\n\t")
courses = canvas.getCourseList()
print("...Done")
print("Please select your course")
for i, course in enumerate(courses):
print(f"{i + 1}: {course['name']}\t{course['enrollment_type']}\t{course['id']}")
usrIn = int(input(f"(1 - {len(courses)}): "))
selectedCourse = courses[usrIn - 1]
canvas.COURSE_ID = str(selectedCourse['id'])
print("Retrieving assignment groups...", end="\n\t")
assignmentGroups = list(canvas.getAssignmentGroupsFromCanvas().items())
print("...Done")
print("Enter the assignment groups that you would like to include")
for i, element in enumerate(assignmentGroups):
print(f"{i + 1}: {element[0]}\t{element[1]}")
print("When done entering values, type \'done\'")
usrIn = ""
groupsToUse = []
while type(usrIn) is int or usrIn.lower() != "done":
usrIn = str(input(f"(done or 1 - {len(assignmentGroups)}): "))
if not usrIn.isdigit():
continue
usrIn = int(usrIn)
groupsToUse.append(assignmentGroups[usrIn - 1][1])
print(f"Downloading assignments from {len(groupsToUse)} assignment groups...", end="\n\t")
assignments = canvas.getAssignmentsFromCanvas(groupsToUse)
print("...Done")
print("Enter Common Name for status assignments (they must be already downloaded).")
selectedAssignment: str = ""
statusAssignment: dict = {}
statusAssignments: list[dict] = []
while selectedAssignment.lower() != "done":
selectedAssignment = input("(Common name or done): ")
if selectedAssignment.lower() != "done":
# The way that this is currently being done means that if there are multiple matches then we will be unable
# to actually select it.
for i in range(len(assignments)):
if assignments[i]['common_name'] == selectedAssignment:
statusAssignment = assignments[i]
break
if not statusAssignment:
print(f"Unable to identify assignment with common name {selectedAssignment}")
continue
print(f"Identified {statusAssignment['name']}")
print("Is this correct?")
usrYN = str(input("(y/n): "))
if usrYN.lower() == 'y':
# The trigger is the word in extension type that will trigger a status assignment update for a student
statusAssignment['trigger'] = str(input("Enter trigger: "))
statusAssignment.pop('points')
statusAssignments.append(statusAssignment)
statusAssignment = {}
selectedAssignment = ""
latePenalties: list[float] = []
correct = False
while not correct:
print("Enter how many days for the late penalty: ")
lateDays = uiHelpers.getUserInput(allowedLowerRange=1, allowedUpperRange=7)
for i in range(lateDays):
print(f"Enter max percentage for {i + 1} days late: ")
percentage: int = uiHelpers.getUserInput(allowedLowerRange=0, allowedUpperRange=100)
latePenalties.append(percentage / 100)
print("Is the following information correct?")
print("Late penalties per day: ", latePenalties)
userYN = uiHelpers.getUserInput(allowedUserInput="y/n")
if userYN.lower() == "y":
correct = True
latePenalties.insert(0, 1)
latePenalties.append(0)
input("Press any key to write the config file...")
output = dict()
print("Writing...")
print("\tWriting course metadate...", end='')
output['class'] = str(selectedCourse['name'])
output['course_id'] = str(selectedCourse['id'])
output['API_key'] = apiKey
output['user_id'] = userId
output['endpoint'] = endpoint
output['tenant_id'] = tenantId
output['late_penalties'] = latePenalties
output['tenant_id'] = tenantId
output['bartik_url'] = bartikUrl
output['bartik_username'] = bartikUserName
# security is my passion
output['bartik_password'] = bartikPassword
output['bartik_course'] = bartikCourse
print("Done.")
print("\tWriting assignments...", end='')
output['assignments'] = assignments
output['status_assignments'] = statusAssignments
print("Done.")
print("\tWriting to file...", end='')
# TODO Move to a file handler call
with open(f"./config/{selectedCourse['name'].replace(' ', '-')}-config.json", 'w') as jsonOutput:
json.dump(output, jsonOutput)
print("Done.")
print("...Done")
return output
def loadConfig():
"""
This function gets the list of available config files and prompts the user to create a new file if none exist
or choose file to open from a list. If only one file exists then it will load that file by default.
Returns the loaded config file. (unless one isn't created, in which case it exits the program)
"""
configFileCount, configFiles = locateConfigFiles()
if configFileCount == 1:
return readConfig(configFiles[0])
if configFileCount == 0:
print("No config files exist! Would you like to create one? (y/n): ", end="")
usrIn = str(input(""))
if usrIn.lower() == 'y':
return createNewConfig()
else:
exit()
print("Multiple config files found. Please select the one you'd like to load")
for i, el in enumerate(configFiles):
print(f"{i + 1}: {el}")
# todo validate this input
usrIn = int(input(f"(1 - {configFileCount}): "))
return readConfig(configFiles[usrIn - 1])