def save_exercise_log(request): """ Receives an exercise_id and relevant data, saves it to the currently authorized user. """ # Form does all data validation, including of the exercise_id form = ExerciseLogForm(data=simplejson.loads(request.raw_post_data)) if not form.is_valid(): raise Exception(form.errors) data = form.data # More robust extraction of previous object user = request.session["facility_user"] (exerciselog, was_created) = ExerciseLog.get_or_initialize( user=user, exercise_id=data["exercise_id"]) previously_complete = exerciselog.complete exerciselog.attempts = data[ "attempts"] # don't increment, because we fail to save some requests exerciselog.streak_progress = data["streak_progress"] exerciselog.points = data["points"] exerciselog.language = data.get("language") or request.language try: exerciselog.full_clean() exerciselog.save() except ValidationError as e: return JsonResponseMessageError( _("Could not save ExerciseLog") + u": %s" % e) if "points" in request.session: del request.session["points"] # will be recomputed when needed # Special message if you've just completed. # NOTE: it's important to check this AFTER calling save() above. if not previously_complete and exerciselog.complete: exercise = get_node_cache("Exercise").get(data["exercise_id"], [None])[0] junk, next_exercise = get_neighbor_nodes( exercise, neighbor_kind="Exercise") if exercise else None if not next_exercise: return JsonResponseMessageSuccess( _("You have mastered this exercise and this topic!")) else: return JsonResponseMessageSuccess( _("You have mastered this exercise! Please continue on to <a href='%(href)s'>%(title)s</a>" ) % { "href": next_exercise["path"], "title": _(next_exercise["title"]), }) # Return no message in release mode; "data saved" message in debug mode. return JsonResponse({})
def update_all_distributed_callback(request): """ """ if request.method != "POST": raise PermissionDenied("Only POST allowed to this URL endpoint.") videos = json.loads(request.POST["video_logs"]) exercises = json.loads(request.POST["exercise_logs"]) user = FacilityUser.objects.get(id=request.POST["user_id"]) node_cache = get_node_cache() # Save videos n_videos_uploaded = 0 for video in videos: video_id = video['video_id'] youtube_id = video['youtube_id'] # Only save video logs for videos that we recognize. if video_id not in node_cache["Video"]: logging.warn("Skipping unknown video %s" % video_id) continue try: (vl, _) = VideoLog.get_or_initialize(user=user, video_id=video_id) # has to be that video_id, could be any youtube_id for key,val in video.iteritems(): setattr(vl, key, val) logging.debug("Saving video log for %s: %s" % (video_id, vl)) vl.save() n_videos_uploaded += 1 except KeyError: # logging.error("Could not save video log for data with missing values: %s" % video) except Exception as e: error_message = _("Unexpected error importing videos: %(err_msg)s") % {"err_msg": e} return JsonResponseMessageError(error_message) # Save exercises n_exercises_uploaded = 0 for exercise in exercises: # Only save video logs for videos that we recognize. if exercise['exercise_id'] not in node_cache['Exercise']: logging.warn("Skipping unknown video %s" % exercise['exercise_id']) continue try: (el, _) = ExerciseLog.get_or_initialize(user=user, exercise_id=exercise["exercise_id"]) for key,val in exercise.iteritems(): setattr(el, key, val) logging.debug("Saving exercise log for %s: %s" % (exercise['exercise_id'], el)) el.save() n_exercises_uploaded += 1 except KeyError: logging.error("Could not save exercise log for data with missing values: %s" % exercise) except Exception as e: error_message = _("Unexpected error importing exercises: %(err_msg)s") % {"err_msg": e} return JsonResponseMessageError(error_message) return JsonResponseMessageSuccess(_("Uploaded %(num_exercises)d exercises and %(num_videos)d videos") % { "num_exercises": n_exercises_uploaded, "num_videos": n_videos_uploaded, })
def delete_users(request): users = simplejson.loads(request.raw_post_data or "{}").get("users", []) users_to_delete = FacilityUser.objects.filter(id__in=users) users_to_delete.delete() return JsonResponseMessageSuccess( _("Deleted %(num_users)d users successfully.") % {"num_users": users_to_delete.count()})
def retry_video_download(request): """ Clear any video still accidentally marked as in-progress, and restart the download job. """ VideoFile.objects.filter(download_in_progress=True).update(download_in_progress=False, percent_complete=0) force_job("videodownload", _("Download Videos"), locale=request.language) return JsonResponseMessageSuccess(_("Launched video download process successfully."))
def cancel_update_progress(request, process_log): """ API endpoint for getting progress data on downloads. """ process_log.cancel_requested = True process_log.save() return JsonResponseMessageSuccess(_("Cancelled update progress successfully."))
def group_delete(request, group_id=None): groups = [group_id] if group_id else simplejson.loads( request.body or "{}").get("groups", []) groups_to_delete = FacilityGroup.objects.filter(id__in=groups) count = groups_to_delete.count() groups_to_delete.soft_delete() return JsonResponseMessageSuccess( _("Deleted %(num_groups)d group(s) successfully.") % {"num_groups": count})
def start_update_kalite(request): try: data = json.loads(request.raw_post_data) mechanism = data['mechanism'] except KeyError: raise KeyError(_("You did not select a valid choice for an update mechanism.")) call_command_async('update', mechanism, old_server_pid=os.getpid(), in_proc=True) return JsonResponseMessageSuccess(_("Launched software update process successfully."))
def start_languagepack_download(request): if not request.POST: raise Exception(_("Must call API endpoint with POST verb.")); data = json.loads(request.raw_post_data) # Django has some weird post processing into request.POST, so use raw_post_data lang_code = lcode_to_ietf(data['lang']) force_job('languagepackdownload', _("Language pack download"), lang_code=lang_code, locale=request.language) return JsonResponseMessageSuccess(_("Started language pack download for language %(lang_code)s successfully.") % {"lang_code": lang_code})
def cancel_video_download(request): # clear all download in progress flags, to make sure new downloads will go through VideoFile.objects.all().update(download_in_progress=False) # unflag all video downloads VideoFile.objects.filter(flagged_for_download=True).update(cancel_download=True, flagged_for_download=False, download_in_progress=False) force_job("videodownload", stop=True, locale=request.language) return JsonResponseMessageSuccess(_("Cancelled video download process successfully."))
def facility_delete(request, facility_id=None): if not request.is_django_user: raise PermissionDenied("Teachers cannot delete facilities.") if request.method != 'POST': return JsonResponseMessageError(_("Method is not allowed.")) facility_id = facility_id or simplejson.loads(request.body or "{}").get("facility_id") fac = get_object_or_404(Facility, id=facility_id) fac.soft_delete() return JsonResponseMessageSuccess(_("Deleted facility %(facility_name)s successfully.") % {"facility_name": fac.name})
def facility_delete(request, facility_id=None): if not request.is_django_user: raise PermissionDenied("Teachers cannot delete facilities.") facility_id = facility_id or simplejson.loads(request.raw_post_data or "{}").get("facility_id") fac = get_object_or_404(Facility, id=facility_id) if not fac.is_deletable(): return JsonResponseMessageError( _("Facility %(facility_name)s is not deletable.") % {"facility_name": fac.name}) fac.delete() return JsonResponseMessageSuccess( _("Deleted facility %(facility_name)s successfully.") % {"facility_name": fac.name})
def move_to_group(request): users = simplejson.loads(request.body or "{}").get("users", []) group_id = simplejson.loads(request.body or "{}").get("group", "") group_update = get_object_or_None(FacilityGroup, id=group_id) users_to_move = FacilityUser.objects.filter(id__in=users) for user in users_to_move: # can't do update for syncedmodel user.group = group_update user.save() if group_update: group_name = group_update.name else: group_name = group_id return JsonResponseMessageSuccess(_("Moved %(num_users)d users to group %(group_name)s successfully.") % { "num_users": users_to_move.count(), "group_name": group_name, })
def delete_videos(request): """ API endpoint for deleting videos. """ youtube_ids = simplejson.loads(request.raw_post_data or "{}").get("youtube_ids", []) num_deleted = 0 for id in youtube_ids: # Delete the file on disk delete_downloaded_files(id) # Delete the file in the database found_videos = VideoFile.objects.filter(youtube_id=id) num_deleted += found_videos.count() found_videos.delete() return JsonResponseMessageSuccess(_("Deleted %(num_videos)s video(s) successfully.") % {"num_videos": num_deleted})
def start_update_kalite(request): try: data = json.loads(request.body) mechanism = data['mechanism'] except KeyError: raise KeyError( _("You did not select a valid choice for an update mechanism.")) # Clear any preexisting logs if UpdateProgressLog.objects.count(): UpdateProgressLog.objects.all().delete() call_command_async('update', mechanism, old_server_pid=os.getpid(), in_proc=True) return JsonResponseMessageSuccess( _("Launched software update process successfully."))
def start_video_download(request): """ API endpoint for launching the videodownload job. """ youtube_ids = OrderedSet(simplejson.loads(request.raw_post_data or "{}").get("youtube_ids", [])) # One query per video (slow) video_files_to_create = [id for id in youtube_ids if not get_object_or_None(VideoFile, youtube_id=id)] # OK to do bulk_create; cache invalidation triggered via save download for lang_code, lang_youtube_ids in divide_videos_by_language(video_files_to_create).iteritems(): VideoFile.objects.bulk_create([VideoFile(youtube_id=id, flagged_for_download=True, language=lang_code) for id in lang_youtube_ids]) # OK to update all, since we're not setting all props above. # One query per chunk for chunk in break_into_chunks(youtube_ids): video_files_needing_model_update = VideoFile.objects.filter(download_in_progress=False, youtube_id__in=chunk).exclude(percent_complete=100) video_files_needing_model_update.update(percent_complete=0, cancel_download=False, flagged_for_download=True) force_job("videodownload", _("Download Videos"), locale=request.language) return JsonResponseMessageSuccess(_("Launched video download process successfully."))