-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathgetUserReport.py
276 lines (217 loc) · 9.52 KB
/
getUserReport.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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# -*- coding: utf-8 -*-
from operator import itemgetter
import requests
import sys
import shelve
import os.path
import time
import argparse
import string
dir_path = os.path.dirname(os.path.realpath(__file__))
SECRETS_PATH = dir_path + '/secrets.py'
if os.path.exists(SECRETS_PATH):
from secrets import username, password, site_url
else:
print 'Missing secrets.py file with login data'
sys.exit(1)
#### teachable urls
URL_COURSES = site_url + '/api/v1/courses'
URL_FIND_USER = site_url + '/api/v1/users?name_or_email_cont='
URL_REPORT_CARD = site_url + '/api/v1/users/USER_ID/report_card'
URL_COURSE_REPORT = site_url + '/api/v1/users/USER_ID/course_report'
URL_CURRICULUM = site_url + '/api/v1/courses/COURSE_ID/curriculum'
URL_COURSE_PRICE = site_url + '/api/v1/courses/COURSE_ID/products'
CACHE_PATH = dir_path + '/teachable_cache.out'
MAXIMUM_CACHE_DURATION = 60 * 60 * 24 * 7 # One week
#####
course_list = {}
curriculum = {}
course_curriculum = {}
parser = argparse.ArgumentParser(description='''Get your student status in Teachable. ''', epilog="""---""")
parser.add_argument('--hidefree', type=int, default=1, help='0: show/1: hide free courses ')
parser.add_argument('emails', type=str, nargs=1, default='',
help='list of emails (separated with commas and without spaces)')
parser.add_argument('output_file', nargs='?', default='', help='Output file')
args = parser.parse_args()
HIDE_FREE_COURSES = args.hidefree # set to 0 to show all
# process position variables
output_file = ''
if args.output_file:
output_file = args.output_file
print 'Output will be saved to ' + output_file
users_mails = string.split(args.emails[0], ',')
def find(lst, key, value):
for i, dic in enumerate(lst):
if dic[key] == value:
return i
return -1
def get_course_list():
global course_list
if 'courses' in cached_data:
course_list = cached_data['courses']
else:
course_info = s.get(URL_COURSES).json()
if course_info.get('error'):
print 'Check Teachable credentials'
sys.exit(1)
else:
course_list = course_info.get('courses')
cached_data['courses'] = course_list
print 'Courses were not previously in cache'
def get_course_price(course_id):
url_course_price = URL_COURSE_PRICE.replace('COURSE_ID', course_id)
course = s.get(url_course_price).json()
try:
course.get('products')[0].get('price')
except IndexError:
return 0
return course.get('products')[0].get('price')
def get_user_name(user_mail):
users = s.get(URL_FIND_USER + user_mail).json()
if users.get('error'):
print 'Check Teachable credentials'
sys.exit(1)
if not users.get('users'):
print 'There is no user with that email'
sys.exit(1)
else:
return users.get('users')[0].get('name').strip()
def get_user_id(user_mail):
users = s.get(URL_FIND_USER + user_mail).json()
if users.get('error'):
print 'Check Teachable credentials'
sys.exit(1)
if not users.get('users'):
print 'There is no user with that email'
sys.exit(1)
else:
return str(users.get('users')[0].get('id'))
def get_user_report_card():
users = s.get(URL_FIND_USER + user_mail).json()
if users.get('error'):
print 'Check Teachable credentials'
sys.exit(1)
if not users.get('users'):
print 'There is no user with that email'
sys.exit(1)
else:
user_id = str(users.get('users')[0].get('id'))
url_user_report_card = URL_REPORT_CARD.replace('USER_ID', user_id)
return s.get(url_user_report_card).json()
def get_course_quiz(user_id, course_id):
course_quiz = ''
url_courses_report = URL_COURSE_REPORT.replace('USER_ID', user_id)
courses_report = s.get(url_courses_report).json()
try:
for lecture in courses_report['report']['lecture_progresses']:
if lecture['course_id'] == int(course_id):
for quiz in courses_report['report']['quiz_responses']['responses']:
if quiz['custom_form']['topic']['attachable_id'] == lecture['lecture_id']:
course_quiz = str(quiz['grade']['correct']) + '/' + str(quiz['grade']['total'])
except IndexError:
print 'error in quiz'
return course_quiz
def get_course_curriculum(course_id):
global curriculum, course_curriculum
url_course_curriculum = URL_CURRICULUM.replace('COURSE_ID', course_id)
course_curriculum = s.get(url_course_curriculum).json().get('lecture_sections')
if 'curriculum' in cached_data:
curriculum = cached_data['curriculum']
if course_id in curriculum:
course_curriculum = curriculum.get('course_id')
else:
get_new_course_curriculum(course_id)
print 'Curriculum of this course was not previously in cache'
else:
get_new_course_curriculum(course_id)
print 'Curriculum was not previously in cache'
def get_new_course_curriculum(course_id):
global curriculum, course_curriculum
url_course_curriculum = URL_CURRICULUM.replace('COURSE_ID', course_id)
course_curriculum = s.get(url_course_curriculum).json()
curriculum.update({course_id: course_curriculum})
cached_data['curriculum'] = curriculum
def get_latest_viewed_title(course, course_id):
global course_curriculum
ordered_id_list = []
if course.get('completed_lecture_ids'):
course_curriculum = curriculum.get(course_id)
sections = course_curriculum.get('lecture_sections')
for section in sections:
for lecture in section.get('lectures'):
ordered_id_list.append(lecture.get('id'))
completed_lectures = course.get('completed_lecture_ids')
# this function to order the completed_lectures looks,
# but will fail if one of the lectures gets deleted (and won't appear in ordered_id_list)
# ordered_completed_lectures = sorted(completed_lectures, key=ordered_id_list.index)
ordered_completed_lectures = sorted(completed_lectures,
key=lambda k: (ordered_id_list.index(k) if k in ordered_id_list else -1))
for section in sections:
lecture_id = find(section.get('lectures'), 'id', ordered_completed_lectures[-1])
if lecture_id >= 0:
lecture_name = section.get('lectures')[lecture_id].get('name')
section_name = section.get('name')
return lecture_name, section_name
return '', ''
def expire_cache():
if os.path.isfile(CACHE_PATH):
cache_antiquity = time.time() - os.path.getctime(CACHE_PATH)
if cache_antiquity > MAXIMUM_CACHE_DURATION:
os.remove(CACHE_PATH)
print('Cache file dumped!')
def generate_student_progress_list(user_id, course, course_id, output):
get_course_curriculum(course_id)
if course_id != 'None':
course_data = find(course_list, 'id', int(course_id))
current_lecture_title, current_section_title = get_latest_viewed_title(course, course_id)
course_quiz = get_course_quiz(user_id, course_id)
output.append({'course_id': course_id, 'course_name': course_list[course_data].get('name'),
'course_percentage': course.get('percent_complete'),
'course_current_lecture': current_lecture_title,
'course_current_section': current_section_title,
'course_quiz': course_quiz})
def generate_output(users_mail):
output = []
user_name = get_user_name(users_mail)
user_id = get_user_id(users_mail)
user_report_card = get_user_report_card()
for key, course in user_report_card.iteritems():
course_id = str(course.get('course_id'))
if HIDE_FREE_COURSES:
if get_course_price(course_id) > 0:
generate_student_progress_list(user_id, course, course_id, output)
else:
generate_student_progress_list(user_id, course, course_id, output)
user_ordered_list = sorted(output, key=itemgetter('course_percentage'), reverse=True)
if output_file:
f = open(output_file, 'a')
sys.stdout = f
print '###### Report of ' + user_name.encode('utf-8') + ' (' + user_mail.encode('utf-8') + ') #########'
counter = 1
for item in user_ordered_list:
if item.get('course_percentage') == 0:
print str(counter) + ' - Curso: ' + item.get('course_name').encode('utf-8') + ' - ' + str(
item.get('course_percentage')).encode('utf-8') + '%'
else:
print str(counter) + ' - Curso: ' + item.get('course_name').encode('utf-8') + ' - ' + \
str(item.get('course_percentage')).encode('utf-8') + '%' + ' - ' + 'Sección: ' + \
item.get('course_current_section').encode('utf-8') + ' - ' + 'Lectura: ' + \
item.get('course_current_lecture').encode('utf-8')
if item.get('course_quiz'):
print ' -- Quiz result: ' + item.get('course_quiz')
counter += 1
print '###### End Report of ' + user_name.encode('utf-8') + ' (' + user_mail.encode('utf-8') + ') #########'
if output_file:
print ' '
f.close()
cached_data = shelve.open(CACHE_PATH)
s = requests.Session()
# get username and password from the secrets.py file
s.auth = (username, password)
s.headers.update({'x-test': 'true'})
get_course_list()
for user_mail in users_mails:
# ignore white spaces
user_mail = user_mail.strip()
generate_output(user_mail)
cached_data.close()