def setup(conf_file): global api, sess with open(conf_file, "r") as f: CONF.update(json.load(f)) api = AplusTokenClient(CONF['api_token']) api.set_base_url_from(CONF['base_url']) sess = requests.Session() logging.basicConfig()
def handle(self, *args, **options): token = options['token'] wait = options['wait'] / 1000 courses = get_courses(self, site_domain=options['site'], course_code=options['course']) client = AplusTokenClient(token, debug_enabled=True) if not options['no_students']: if courses: students = Student.objects.get_students_on_courses(courses) else: students = Student.objects.all() for student in students: self.stdout.write( self.style.NOTICE("Working on {}, {}".format( student, student.url))) student.update_using(client) student.save() if not options['no_taggings']: for course in courses: self.stdout.write( self.style.NOTICE("Updating tags for course {}, {}".format( course, course.url))) tag_summary = StudentTag.update_from_api(client, course) self.stdout.write( self.style.SUCCESS( " Tags updated. {} new, {} updated, {} deleted.". format( len(tag_summary['new']), len(tag_summary['updated']), len(tag_summary['deleted']), )))
def handle(self, *args, **options): token = options['token'] wait = options['wait'] / 1000 courses = get_courses(self, site_domain=options['site'], course_code=options['course']) if courses: students = Student.objects.get_students_on_courses(courses) else: students = Student.objects.all() client = AplusTokenClient(token, debug_enabled=True) for student in students: self.stdout.write( self.style.NOTICE("Working on {}, {}".format( student, student.url))) student.update_using(client) student.save() for course in courses: self.stdout.write( self.style.NOTICE("Updating tags for course {}, {}".format( course, course.url))) StudentTag.update_from_api(client, course)
def get_api_client(self, site): try: token = self.tokens.get(site=site) except Token.DoesNotExist: return None return AplusTokenClient(token.token)
'englanti': 'en', }, } p = ArgumentParser() p.add_argument('-v', '--verbose', action='store_true', help="Print logging messages") p.add_argument('-t', '--token', help='Token for A+ API') args = p.parse_args() if args.verbose: logging.basicConfig(level=logging.DEBUG) api = AplusTokenClient(args.token) api.set_base_url_from(CONFIG['base_url']) def get_submission(submission_id): return api.load_data('{submissions_url}{submission_id}/'.format( **CONFIG, submission_id=submission_id)) def add_tagging(exercise_id, submission_id): if exercise_id not in CONFIG['exercise_ids']: return submission = get_submission(submission_id) submitters = submission['submitters'] submission_data = submission['submission_data']
def download(destination, courses, users): # domain and token domain = config.get('main', 'domain') if not domain: raise RuntimeError("no domain, run `set-fomain` first") token = config.get(domain, 'api-token') if not token: raise RuntimeError("no api token, run `set-domain` first") # api client api = AplusTokenClient(token, cache=FilesystemCache( os.path.join(CACHE_DIR, domain))) base_url = config.get(domain, 'api-url', fallback='https://%s/api/v2' % (domain, )) api.set_base_url_from(base_url) me = api.load_data('/me/', skip_cache=True) # courses if not courses: courses = me['enrolled_courses'] else: course_ids = set() course_urls = set() for filter_ in courses: key, value = filter_.split('=', 1) if key == 'id': course_ids.add(int(value)) elif key == 'url': course_urls.add(value.strip('/')) else: raise ValueError( "Unsupported course filter %r. id= and url= are supported" % (key, )) courses = [api.load_data('/courses/%d/' % i) for i in course_ids] course_urls -= set(get_course_url(c) for c in courses) if course_urls: for course in api.load_data('/courses/'): url = get_course_url(course) if url in course_urls: courses.append(course) course_urls.remove(url) if not course_urls: break if course_urls: raise ValueError("Course urls %s were not found" % (course_urls, )) if not courses: raise ValueError("No courses selected") print("Selected courses:") for course in courses: print( " {c.code} - {c.name} ({c.instance_name}) <{c.html_url}>".format( c=course)) # users if not users: users = [me] else: user_ids = set() user_sids = set() for filter_ in users: key, value = filter_.split('=', 1) if key == 'id': user_ids.add(int(value)) elif key == 'sid': user_sids.add(value.strip().lower()) else: raise ValueError( "Unsupported course filter %r. id and sid are supported" % (key, )) users = [api.load_data('/users/%d/' % i) for i in user_ids] user_sids -= set(u.student_id.lower() for u in users) if user_sids: for course in courses: for student in course.students: if student.student_id and student.student_id.lower( ) in user_sids: users.append(student) user_sids.remove(student.student_id.lower()) if not user_sids: break if not user_sids: break if user_sids: raise ValueError("Student ids %s were not found on any courses" % (user_sids, )) if not users: raise ValueError("No users selected") print("Selected users:") for user in users: print(" {u.student_id}: {u.full_name} <{u.email}> (id={u.id})".format( u=user)) # crawl submissions using points cache submission_count = 0 for course in courses: course_dir = "{c.code} - {c.name} ({c.instance_name}) (id={c.id})".format( c=course) for user in users: points = api.load_data('/courses/%d/points/%d/' % (course.id, user.id)) name = ("{u.last_name}, {u.first_name} ({u.student_id})" if user.get('student_id') else "{u.last_name}, {u.first_name} (id={u.id})").format(u=user) if not points: raise ValueError("User %s is not enrolled on the course %s" % (name, course_dir)) user_dir = os.path.join(destination, course_dir, name) user_data = dict_from_api(points, 'student_id', 'full_name', 'first_name', 'last_name', 'email', ('api_url', 'url')) user_data['tags'] = [(t.name, t.description) for t in points['tags']] user_data.update( dict_from_api(points, 'submission_count', 'points', 'points_by_difficulty')) write_yaml(user_dir, 'user.yaml', user_data) for module in points['modules']: exercises = module['exercises'] if not exercises: continue module_name = "{} (id={})".format(module.name[:40], module.id) module_dir = os.path.join(user_dir, module_name) module_data = dict_from_api(module, 'id', 'name', 'submission_count', 'passed', 'max_points', 'points_to_pass', 'points', 'points_by_difficulty') write_yaml(module_dir, 'module.yaml', module_data) for exercise in exercises: exercise_name = "{} (id={})".format( exercise.name[:40], exercise.id) exercise_dir = os.path.join(module_dir, exercise_name) exercise_data = dict_from_api(exercise, 'id', ('api_url', 'url'), 'name', 'difficulty', 'submission_count', 'passed', 'max_points', 'points_to_pass', 'points') submissions = exercise['submissions'] if not submissions: write_yaml(module_dir, exercise_name + '.yaml', exercise_data) else: write_yaml(exercise_dir, 'exercise.yaml', exercise_data) best_url = exercise['best_submission'] for submission_url in submissions: best = submission_url == best_url submission = api.load_data(submission_url) download_submission(api, submission, exercise_dir, best=best) submission_count += 1 print("DONE. Downloaded %d submissions" % submission_count) return # OLD METHOD # find all submission API points data = {} for course in courses: info = "{c.code} - {c.name} ({c.instance_name}) (id={c.id})".format( c=course) subs = [] data[info] = subs for module in course['exercises']: for exercise in module['exercises']: if 'submissions' not in exercise: continue url = exercise.get_item('submissions') if not url.endswith('/'): url += '/' subs.append(url) from pprint import pprint pprint(data) # download all submissions for all users in all endpoints for info, submission_urls in data.items(): for user in users: name = user['student_id'] or ('aplus_%d' % user.id) user_data = dict_from_api(user, 'student_id', 'email', 'first_name', 'last_name', 'full_name') for url in submission_urls: for submission in api.load_data('%s%d/' % (url, user.id)) or []: ename = get_exercise_fn(submission.exercise, dirs=1) path = os.path.join(destination, info, name, ename) if not os.path.exists(path): os.makedirs(path) download_submission(api, submission, path)
from aplus_client.client import AplusTokenClient from flask import current_app as app api = AplusTokenClient(None)