-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathenroll_learners_into_class.py
198 lines (171 loc) · 7.47 KB
/
enroll_learners_into_class.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
import kolibri # noqa F401
import django
import sys
import uuid
import csv
import argparse
from colors import *
from django.contrib.auth.hashers import make_password
from django.core.exceptions import ObjectDoesNotExist
django.setup()
from kolibri.core.auth.models import (
Facility,
FacilityDataset,
FacilityUser,
Classroom,
LearnerGroup,
Membership,
) # noqa E402
# Initalize argparse and define command line args that can be passed to this module
argParser = argparse.ArgumentParser()
argParser.add_argument("--file", "-f", help="File to create users from")
argParser.add_argument(
"--centre",
"-c",
help="Name of Facility( centre_id) in the case of multiple facilities on 1 device",
)
argParser.add_argument(
"--delete",
"-d",
action="store_true",
default=False,
help="Delete existing memberships for each user before memberships. The default value is False",
)
# Get the name of the default facility on the device
# used as the default value in case facility is not passed in
def_facility = str(Facility.get_default_facility().name)
def enroll_learners_into_class(
input_file, facilityname=def_facility, delete_existing_memberships=False
):
"""Function to enroll learners into classes using a csv file
The file is expected to have columns user_id, centre, and grade. All other columns are ignored
The grade column represents the name of the classroom the learner should be enrolled into.
It is assumed that the classrooms have already been created
Args:
input_file (string): Path to the csv file containing the users
facility (string): Name of the facility which contains the classrooms(default facility if not specified)
Returns:
None
"""
# Initialize variable for number of users created
num_enrolled = 0
# Check if the Facility supplied exists
try:
# Attempt to get a reference to the Facility supplied if it exists
facility_obj = Facility.objects.get(name=facilityname)
facility_id = facility_obj.id
dataset_id = facility_obj.dataset_id
# Catch the exception when the Facility does not exist
except ObjectDoesNotExist:
# Print out the name of the Facility that does not exist and terminate the script
print_colored(
"Error: Facility with the name {} does not exist".format(facility),
colors.fg.red,
)
# exit in an error state
sys.exit("Learners were not enrolled successfully. Check the error(s) above")
# Use csv dictreader to get the contents of the file
with open(input_file) as f:
reader = csv.DictReader(f)
users = [r for r in reader]
# Loop through the list of users read from the input file
for user in users:
try:
# Attempt to get a reference to the user object supplied if it exists in the supplied centre(facility)
user_obj = FacilityUser.objects.get(
id=user["user_id"],
facility_id=Facility.objects.get(name=user["centre"]).id,
)
# Catch the exception when the user does not exist
except ObjectDoesNotExist:
# Print out the user id that does not exist in the facility and terminate the script
print_colored(
"Error: User with id {} does not exist in Facility {}".format(
user["user_id"], user["centre"]
),
colors.fg.red,
)
continue
try:
# Attempt to get a reference to the grade(classroom) supplied if it exists
classroom_for_user = Classroom.objects.get(
name=user["grade"], parent_id=facility_id
)
# Catch the exception when the grade(classroom) does not exist
except ObjectDoesNotExist:
# Print out the name of the grade(classroom) that does not exist and terminate the script
print_colored(
"Error: Classroom with the name {} does not exist".format(
user["grade"]
),
colors.fg.red,
)
# exit in an error state
continue
# If the delete flag is supplied, delete all existing memberships for the user
if delete_existing_memberships:
print_colored(
"Deleting Memberships for user: {}....".format(
str(user_obj.full_name)
),
colors.fg.yellow,
)
Membership.objects.filter(user_id=user_obj.id).delete()
if not user_obj.is_member_of(classroom_for_user):
Membership.objects.create(user=user_obj, collection=classroom_for_user)
# Print out a message confirming the membership has been created
print_colored(
"Created Membership for user: {} in Classroom {}".format(
str(user_obj.full_name), str(classroom_for_user.name)
),
colors.fg.green,
)
num_enrolled += 1
else:
print_colored(
"User : {} is already enrolled in Classroom {}. Skipping...".format(
str(user_obj.full_name), str(classroom_for_user.name)
),
colors.fg.yellow,
)
continue
# Print out the total number of users that were created
if num_enrolled == 0:
# If not learners were enrolled, something is wrong and there will be errors displayed in the console
print_colored(
"No learners were enrolled. Kindly check the errors/messages above",
colors.fg.red,
)
elif num_enrolled != len(users):
print_colored(
"{} user(s) were enrolled into their classes. Some learners were not enrolled successfully or were skipped. Kindly check the errors/messages above".format(
num_enrolled
),
colors.fg.lightcyan,
)
else:
print_colored(
"{} user(s) were enrolled into their classes".format(num_enrolled),
colors.fg.lightgreen,
)
# Main function called when script is run
if __name__ == "__main__":
args = argParser.parse_args()
# If the file is supplied and facility is not supplied
# Enroll learners into classes based on the defualt facility
if args.file and not (args.centre):
open_file = args.file
enroll_learners_into_class(open_file, delete_existing_memberships=args.delete)
# If both the file and the facility are supplied
# Enroll learners into classes based on the supplied
elif args.file and args.centre:
open_file = args.file
facility = args.centre
enroll_learners_into_class(
open_file, facility, delete_existing_memberships=args.delete
)
# If neither the file nor the facility are passed in, stop the script in an error state
else:
sys.exit(
"No arguments passed in. Please pass in the path to the file, centre_id (optional) and delete_existing_memberships(optional)"
)