def read(request, key): if 'user' in request.GET: user = get_user_id(request) else: user = None item = int(request.GET['item']) if 'item' in request.GET else None item_secondary = int(request.GET['item_secondary'] ) if 'item_secondary' in request.GET else None time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) value = environment.read(key, user=user, item=item, item_secondary=item_secondary) if value is None: return render_json(request, {'error': 'value with key "%s" not found' % key}, template='models_json.html', status=404) else: return render_json(request, { 'object_type': 'value', 'key': key, 'item_primary_id': item, 'item_secondary_id': item_secondary, 'user_id': user, 'value': value }, template='models_json.html')
def read(request, key): if 'user' in request.GET: user = get_user_id(request) else: user = None item = int(request.GET['item']) if 'item' in request.GET else None item_secondary = int(request.GET['item_secondary']) if 'item_secondary' in request.GET else None time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) value = environment.read(key, user=user, item=item, item_secondary=item_secondary) if value is None: return render_json( request, {'error': 'value with key "%s" not found' % key}, template='models_json.html', status=404) else: return render_json( request, { 'object_type': 'value', 'key': key, 'item_primary_id': item, 'item_secondary_id': item_secondary, 'user_id': user, 'value': value }, template='models_json.html' )
def session(request): """ Get the information about the current session or modify the current session. GET parameters: html turn on the HTML version of the API POST parameters: locale: client's locale time_zone: client's time zone display_width: width of the client's display display_height height of the client's display """ if request.user.id is None: # Google Bot return render_json( request, { 'error': _('There is no user available to create a session.'), 'error_type': 'user_undefined' }, status=400, template='user_json.html') if request.method == 'GET': return render_json(request, Session.objects.get_current_session(), template='user_session.html', help_text=session.__doc__) elif request.method == 'POST': current_session = Session.objects.get_current_session() if current_session is None: return HttpResponseBadRequest( "there is no current session to modify") data = json_body(request.body.decode("utf-8")) locale = data.get('locale', None) time_zone = data.get('time_zone', None) display_width = data.get('display_width', None) display_height = data.get('display_height', None) if locale: current_session.locale = locale if time_zone: current_session.time_zone = TimeZone.objects.from_content( time_zone) if display_width: current_session.display_width = display_width if display_height: current_session.display_height = display_height current_session.save() return HttpResponse('ok', status=202) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def login_student(request): """ Log in student POST parameters (JSON): student: profile id of the student """ if not get_config('proso_user', 'allow_login_students', default=False): return render_json(request, { 'error': _('Log in as student is not allowed.'), 'error_type': 'login_student_not_allowed' }, template='class_create_student.html', help_text=login_student.__doc__, status=403) if request.method == 'GET': return render(request, 'class_login_student.html', {}, help_text=login_student.__doc__) elif request.method == 'POST': if not request.user.is_authenticated() or not hasattr( request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in.'), 'error_type': 'user_unauthorized' }, template='class_create_student.html', status=401) data = json_body(request.body.decode("utf-8")) try: student = User.objects.get( userprofile=data.get('student'), userprofile__classes__owner=request.user.userprofile) except User.DoesNotExist: return render_json(request, { 'error': _('Student not found'), 'error_type': 'student_not_found' }, template='class_login_student.html', status=401) if not student.is_active: return render_json( request, { 'error': _('The account has not been activated.'), 'error_type': 'account_not_activated' }, template='class_login_student.html', status=401) student.backend = 'django.contrib.auth.backends.ModelBackend' login(request, student) request.method = "GET" return profile(request) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def to_practice(request): practice_filter = get_filter(request) item_ids = Item.objects.filter_all_reachable_leaves(practice_filter, get_language(request)) if len(item_ids) == 0: return render_json(request, { 'error': _('There is no item for the given filter to practice.'), 'error_type': 'empty_practice' }, status=404, template='models_json.html') result = [Item.objects.item_id_to_json(item_id) for item_id in item_ids] return render_json(request, result, template='models_json.html', help_text=to_practice.__doc__)
def classes(request): """Get all classes of current user""" if not request.user.is_authenticated() or not hasattr(request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in'), 'error_type': 'user_unauthorized' }, template='user_json.html', status=401) clss = [c.to_json() for c in Class.objects.filter(owner=request.user.userprofile)] return render_json(request, clss, status=200, template='user_json.html', help_text=classes.__doc__)
def create_class(request): """Create new class POST parameters (JSON): name: Human readable name of class code (optional): unique code of class used for joining to class """ if request.method == 'GET': return render(request, 'classes_create.html', {}, help_text=create_class.__doc__) if request.method == 'POST': if not request.user.is_authenticated() or not hasattr( request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in.'), 'error_type': 'user_unauthorized' }, template='classes_create.html', status=401) data = json_body(request.body.decode("utf-8")) if 'code' in data and Class.objects.filter(code=data['code']).exists(): return render_json( request, { 'error': _('A class with this code already exists.'), 'error_type': 'class_with_code_exists' }, template='classes_create.html', status=400) if 'name' not in data or not data['name']: return render_json(request, { 'error': _('Class name is missing.'), 'error_type': 'missing_class_name' }, template='classes_create.html', status=400) cls = Class(name=data['name'], owner=request.user.userprofile) if 'code' in data: cls.code = data['code'] cls.save() return render_json(request, cls.to_json(), template='classes_create.html', status=201) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def answer_question(request): if request.method == 'GET': return render(request, 'user_answer.html', {}, help_text=answer_question.__doc__) elif request.method == 'POST': with transaction.atomic(): user_id = get_user_id(request) to_save = json_body(request.body.decode("utf-8")) for answer in to_save['answers']: question = get_object_or_404(UserQuestion, pk=answer['question']) if 'open_answer' in answer and 'closed_answer' in answer: return render_json(request, { 'error': _('The answer can not contain both open and closed part'), 'error_type': 'answer_closed_open_both' }, template='user_json.html', status=400) if 'open_answer' not in answer and 'closed_answer' not in answer: return render_json(request, { 'error': _('The answer has to contain either open, or closed part.'), 'error_type': 'answer_closed_open_missing' }, template='user_json.html', status=400) if question.answer_type == UserQuestion.TYPE_CLOSED and 'closed_answer' not in answer: return render_json(request, { 'error': _('The answer has to contain closed part.'), 'error_type': 'answer_closed_missing' }, template='user_json.html', status=400) if question.answer_type == UserQuestion.TYPE_OPEN and 'open_answer' not in answer: return render_json(request, { 'error': _('The answer has to contain open part.'), 'error_type': 'answer_open_missing' }, template='user_json.html', status=400) user_answer = None if not question.repeat: user_answer = UserQuestionAnswer.objects.filter(user_id=user_id, question__identifier=question.identifier).first() status = 202 if user_answer is None: status = 201 user_answer = UserQuestionAnswer(user_id=user_id, question=question) if 'closed_answer' in answer: user_answer.closed_answer = get_object_or_404(UserQuestionPossibleAnswer, pk=answer['closed_answer']) if user_answer.closed_answer.question_id != question.id: return render_json(request, { 'error': _('The given question and question for the given closed answer does not match.'), 'error_type': 'closed_answer_no_match' }, template='user_json.html', status=400) else: user_answer.closed_answer = None user_answer.open_answer = answer['open_answer'] if 'open_answer' in answer else None user_answer.save() return HttpResponse('ok', status=status) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def session(request): """ Get the information about the current session or modify the current session. GET parameters: html turn on the HTML version of the API POST parameters: locale: client's locale time_zone: client's time zone display_width: width of the client's display display_height height of the client's display """ if request.user.id is None: # Google Bot return render_json(request, { 'error': _('There is no user available to create a session.'), 'error_type': 'user_undefined' }, status=400, template='user_json.html') if request.method == 'GET': return render_json( request, Session.objects.get_current_session(), template='user_session.html', help_text=session.__doc__) elif request.method == 'POST': current_session = Session.objects.get_current_session() if current_session is None: return HttpResponseBadRequest("there is no current session to modify") data = json_body(request.body.decode("utf-8")) locale = data.get('locale', None) time_zone = data.get('time_zone', None) display_width = data.get('display_width', None) display_height = data.get('display_height', None) if locale: current_session.locale = locale if time_zone: current_session.time_zone = TimeZone.objects.from_content(time_zone) if display_width: current_session.display_width = display_width if display_height: current_session.display_height = display_height current_session.save() return HttpResponse('ok', status=202) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def user_stats_bulk(request): """ Get statistics for selected users and concepts since: time as timestamp - get stats changed since users: list of identifiers of users concepts (Optional): list of identifiers of concepts language: language of concepts """ language = get_language(request) users = load_query_json(request.GET, "users") if request.user.is_staff: if not hasattr(request.user, 'userprofile') or User.objects.filter( pk__in=users, userprofile__classes__owner=request.user. userprofile).count() < len(users): return render_json( request, { 'error': _('Some requested users are not in owned classes'), 'error_type': 'permission_denied' }, template='concepts_json.html', status=401) since = None if 'since' in request.GET: since = datetime.datetime.fromtimestamp(int(request.GET['since'])) concepts = None if "concepts" in request.GET: concepts = Concept.objects.filter(lang=language, active=True, identifier__in=load_query_json( request.GET, "concepts")) stats = UserStat.objects.get_user_stats(users, language, concepts=concepts, since=since) data = {"users": []} for user, s in stats.items(): data["users"].append({ "user_id": user, "concepts": s, }) return render_json(request, data, template='concepts_json.html', help_text=user_stats_bulk.__doc__)
def join_class(request): """Join a class POST parameters (JSON): code: code of the class """ if request.method == 'GET': return render(request, 'classes_join.html', {}, help_text=join_class.__doc__) if request.method == 'POST': if not request.user.is_authenticated() or not hasattr( request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in.'), 'error_type': 'user_unauthorized' }, template='classes_join.html', status=401) data = json_body(request.body.decode("utf-8")) if 'code' not in data or not data['code']: return render_json(request, { 'error': _('Class code is missing.'), 'error_type': 'missing_class_code' }, template='classes_join.html', status=400) try: cls = Class.objects.get(code=data['code']) except Class.DoesNotExist: return render_json(request, { 'error': _('Class with given code not found.'), 'error_type': 'class_not_found', }, template='classes_join.html', status=404) cls.members.add(request.user.userprofile) return render_json(request, cls.to_json(), template='classes_join.html', status=200) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def signup(request): """ Create a new user with the given credentials. GET parameters: html turn on the HTML version of the API POST parameters (JSON): username: user's name email: user's e-mail password: user's password password_check: user's password again to check it first_name (optional): user's first name last_name (optional): user's last name """ if request.method == 'GET': return render(request, 'user_signup.html', {}, help_text=signup.__doc__) elif request.method == 'POST': if request.user.is_authenticated() and hasattr(request.user, "userprofile"): return render_json(request, { 'error': _('User already logged in'), 'error_type': 'username_logged' }, template='user_json.html', status=400) credentials = json_body(request.body.decode("utf-8")) error = _save_user(request, credentials, new=True) if error is not None: return render_json(request, error, template='user_json.html', status=400) else: auth.login(request, request.user) request.method = "GET" return profile(request, status=201) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def user_stats_api(request, provider): """ Get statistics for selected Edookit users key: api key since: time as timestamp - get stats changed since """ if 'key' not in request.GET or provider not in settings.USER_STATS_API_KEY \ or request.GET['key'] != settings.USER_STATS_API_KEY[provider]: return HttpResponse('Unauthorized', status=401) since = None if 'since' in request.GET: since = datetime.datetime.fromtimestamp(int(request.GET['since'])) social_users = list(UserSocialAuth.objects.filter(provider=provider).select_related('user')) user_map = {u.user.id: u for u in social_users} stats = UserStat.objects.get_user_stats([u.user for u in social_users], lang=None, since=since, recalculate=False) data = {"users": []} for user, s in stats.items(): data["users"].append({ "user_id": user_map[user].uid, "concepts": s, }) return render_json(request, data, template='concepts_json.html', help_text=user_stats_bulk.__doc__)
def _csv_list(request): apps = defaultdict(dict) for app, app_data in get_tables_allowed_to_export().items(): apps[app]['tables'] = list(map(lambda d: {'name': d[1], 'url': reverse('csv_table', kwargs={'filename': d[1]})}, app_data)) for app, app_data in get_custom_exports().items(): apps[app]['custom_exports'] = list(map(lambda name: {'name': name, 'url': reverse('csv_table', kwargs={'filename': name})}, app_data)) return render_json(request, apps, template='common_json.html')
def learning_curve(request): ''' Shows a learning curve based on the randomized testing. GET parameters: length: length of the learning curve context: JSON representing the practice context all_users: if present stop filtering users based on the minimal number of testing answers (=length) ''' context = PracticeContext.objects.from_content(get_filter(request)) length = int(request.GET.get('length', 10)) if 'all_users' in request.GET: user_length = 1 else: user_length = None return render_json(request, models_learning_curve(length, context=context.id, user_length=user_length), template='models_json.html', help_text=learning_curve.__doc__)
def discount_code_view(request, code): return render_json(request, get_object_or_404( DiscountCode, code=DiscountCode.objects.prepare_code(code), active=True).to_json(), template='subscription_json.html')
def user_stats_bulk(request): """ Get statistics for selected users and concepts since: time as timestamp - get stats changed since users: list of identifiers of users concepts (Optional): list of identifiers of concepts language: language of concepts """ language = get_language(request) users = load_query_json(request.GET, "users") since = None if 'since' in request.GET: since = datetime.datetime.fromtimestamp(int(request.GET['since'])) concepts = None if "concepts" in request.GET: concepts = Concept.objects.filter(lang=language, active=True, identifier__in=load_query_json(request.GET, "concepts")) stats = UserStat.objects.get_user_stats(users, language, concepts=concepts, since=since) data = {"users": []} for user, s in stats.items(): data["users"].append({ "user_id": user, "concepts": s, }) return render_json(request, data, template='concepts_json.html', help_text=user_stats_bulk.__doc__)
def answer(request): """ Save the answer. GET parameters: html: turn on the HTML version of the API BODY json in following format: { "answer": #answer, -- for one answer "answers": [#answer, #answer, #answer ...] -- for multiple answers } answer = { "answer_class": str, -- class of answer to save (e.g., flashcard_answer) "response_time": int, -- response time in milliseconds "meta": "str" -- optional information "time_gap": int -- waiting time in frontend in seconds ... -- other fields depending on aswer type (see from_json method of Django model class) } """ if request.method == 'GET': return render(request, 'models_answer.html', {}, help_text=answer.__doc__) elif request.method == 'POST': practice_filter = get_filter(request) practice_context = PracticeContext.objects.from_content(practice_filter) saved_answers = _save_answers(request, practice_context) return render_json(request, saved_answers, status=200, template='models_answer.html') else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def audit(request, key): if 'user' in request.GET: user = get_user_id(request) else: user = None limit = 100 if request.user.is_staff: limit = request.GET.get('limit', limit) item = int(request.GET['item']) if 'item' in request.GET else None item_secondary = int(request.GET['item_secondary']) if 'item_secondary' in request.GET else None time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) values = environment.audit( key, user=user, item=item, item_secondary=item_secondary, limit=limit) def _to_json_audit(audit): (time, value) = audit return { 'object_type': 'value', 'key': key, 'item_primary_id': item, 'item_secondary_id': item_secondary, 'user_id': user, 'value': value, 'time': time.strftime('%Y-%m-%d %H:%M:%S') } return render_json(request, list(map(_to_json_audit, values)), template='models_json.html')
def custom_config(request): """ Save user-specific configuration property. POST parameters (JSON keys): app_name: application name for which the configuration property is valid (e.g., proso_models) key: name of the property (e.g., predictive_model.class) value: value of the property (number, string, boolean, ..., e.g, proso.models.prediction.PriorCurrentPredictiveModel) condition_key (optional): name of the condition which is used to filter the property (e.g., practice_filter) condition_value (optional): value for the condition filtering the property (e.g., [["context/world"],["category/state"]]) """ if request.method == 'POST': config_dict = json_body(request.body.decode('utf-8')) CustomConfig.objects.try_create( config_dict['app_name'], config_dict['key'], config_dict['value'], request.user.id, config_dict.get('condition_key') if config_dict.get('condition_key') else None, urllib.parse.unquote(config_dict.get('condition_value')) if config_dict.get('condition_value') else None) return config(request) else: return render_json(request, {}, template='common_custom_config.html', help_text=custom_config.__doc__)
def user_stats(request): """ JSON of user stats of the user GET parameters: html (bool): turn on the HTML version of the API, defaults to false user (int): identifier of the user, defaults to logged user concepts (list): list of identifiers of concepts, defaults to all concepts lang (str): language of requested concepts, defaults to language from django """ user = get_user_id(request) language = get_language(request) concepts = None # meaning all concept if "concepts" in request.GET: concepts = Concept.objects.filter(lang=language, active=True, identifier__in=load_query_json( request.GET, "concepts")) data = UserStat.objects.get_user_stats(user, language, concepts) return render_json(request, data, template='concepts_json.html', help_text=user_stats.__doc__)
def log(request): """ Log an event from the client to the server. POST parameters (JSON keys): message: description (str) of the logged event level: debug|info|warn|error data: additional data (JSON) describing the logged event """ if request.method == "POST": log_dict = json_body(request.body.decode("utf-8")) if 'message' not in log_dict: return HttpResponseBadRequest('There is no message to log!') levels = { 'debug': JAVASCRIPT_LOGGER.debug, 'info': JAVASCRIPT_LOGGER.info, 'warn': JAVASCRIPT_LOGGER.warn, 'error': JAVASCRIPT_LOGGER.error, } log_fun = JAVASCRIPT_LOGGER.info if 'level' in log_dict: log_fun = levels[log_dict['level']] log_fun(log_dict['message'], extra={ 'request': request, 'user': request.user.id if request.user.is_authenticated() else None, 'client_data': json_lib.dumps(log_dict.get('data', {})), }) return HttpResponse('ok', status=201) else: return render_json(request, {}, template='common_log_service.html', help_text=log.__doc__)
def user_stats_api(request, provider): """ Get statistics for selected Edookit users key: api key since: time as timestamp - get stats changed since """ if 'key' not in request.GET or provider not in settings.USER_STATS_API_KEY \ or request.GET['key'] != settings.USER_STATS_API_KEY[provider]: return HttpResponse('Unauthorized', status=401) since = None if 'since' in request.GET: since = datetime.datetime.fromtimestamp(int(request.GET['since'])) social_users = list( UserSocialAuth.objects.filter( provider=provider).select_related('user')) user_map = {u.user.id: u for u in social_users} stats = UserStat.objects.get_user_stats([u.user for u in social_users], lang=None, since=since, recalculate=False) data = {"users": []} for user, s in stats.items(): data["users"].append({ "user_id": user_map[user].uid, "concepts": s, }) return render_json(request, data, template='concepts_json.html', help_text=user_stats_bulk.__doc__)
def survival_curve(request, metric): ''' Shows a learning curve based on the randomized testing. GET parameters: length: length of the learning curve context: JSON representing the practice context all_users: if present stop filtering users based on the minimal number of testing answers (=length) ''' practice_filter = get_filter(request, force=False) context = None if practice_filter is None else PracticeContext.objects.from_content( practice_filter).id if metric == 'answers': length = int(request.GET.get('length', 100)) models_survival_curve_answers(length, context=context) else: length = int(request.GET.get('length', 600)) models_survival_curve_time(length, context=context) return render_json(request, models_learning_curve(length, context=context), template='models_json.html', help_text=learning_curve.__doc__)
def rating(request): """ Rate the current practice. GET parameters: html turn on the HTML version of the API POST parameters (JSON): value: one of the following numbers: (1) too easy, (2) appropriate, (3) too difficult """ if request.method == 'GET': return render(request, 'feedback_rating.html', {}, help_text=rating.__doc__) if request.method == 'POST': data = json_body(request.body.decode("utf-8")) if data['value'] not in list(range(1, 4)): return render_json( request, {'error': _('The given value is not valid.'), 'error_type': 'invalid_value'}, template='feedback_json.html', status=400 ) rating_object = Rating( user=request.user, value=data['value'], ) rating_object.save() return HttpResponse('ok', status=201) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def my_referrals(request): return render_json(request, [ s.to_json(confidential=True) for s in request.user.referred_subscriptions.order_by( '-created').filter(payment__state=PaymentStatus.PAID) ], template='subscription_json.html')
def _csv_table(request, filename): if filename not in [x[1] for xs in get_tables_allowed_to_export().values() for x in xs] and \ filename not in [x for xs in get_custom_exports().values() for x in xs.keys()]: response = { "error": "the requested file '%s' is not valid" % filename } return render_json(request, response, status=400, template='common_json.html') download_file = settings.DATA_DIR + '/' + filename + ".csv" if not os.path.exists(download_file): response = { "error": "there is no data for the given table" } return render_json(request, response, status=204, template='common_json.html') response = HttpResponse(FileWrapper(open(download_file)), content_type='application/csv') response['Content-Length'] = os.path.getsize(download_file) response['Content-Disposition'] = 'attachment; filename=' + filename + '.csv' return response
def process_exception(self, request, exception): if isinstance(exception, HttpError): return render_json(request, { 'error': str(exception), 'error_type': 'bad_request' }, template='common_json.html', status=exception.http_status)
def to_practice(request): practice_filter = get_filter(request) item_ids = Item.objects.filter_all_reachable_leaves( practice_filter, get_language(request)) if len(item_ids) == 0: return render_json( request, { 'error': _('There is no item for the given filter to practice.'), 'error_type': 'empty_practice' }, status=404, template='models_json.html') result = [Item.objects.item_id_to_json(item_id) for item_id in item_ids] return render_json(request, result, template='models_json.html', help_text=to_practice.__doc__)
def subscribe(request, description_id): return_url = request.GET.get('return_url', request.META['HTTP_HOST']) description = get_object_or_404(SubscriptionPlanDescription, id=description_id) discount_code = get_discount_code(request) subscription = Subscription.objects.subscribe( request.user, description, discount_code, get_referral_user(request), return_url ) return render_json(request, subscription.to_json(), template='subscription_json.html', status=202)
def csv(request, filename=None): if not request.user.is_staff: response = { "error": "Permission denied: you need to be staff member. If you think you should be able to access logs, contact admins."} return render_json(request, response, status=401, template='common_json.html') if filename: return _csv_table(request, filename) else: return _csv_list(request)
def to_practice_counts(request): """ Get number of items available to practice. filters: -- use this or body json as in BODY language: language of the items BODY json in following format: { "#identifier": [] -- custom identifier (str) and filter ... } """ data = None if request.method == "POST": data = json.loads(request.body.decode("utf-8"))["filters"] if "filters" in request.GET: data = load_query_json(request.GET, "filters") if data is None or len(data) == 0: return render_json(request, {}, template='models_json.html', help_text=to_practice_counts.__doc__) language = get_language(request) timer('to_practice_counts') filter_names, filter_filters = list(zip(*sorted(data.items()))) reachable_leaves = Item.objects.filter_all_reachable_leaves_many( filter_filters, language) response = { group_id: { 'filter': data[group_id], 'number_of_items': len(items), } for group_id, items in zip(filter_names, reachable_leaves) } LOGGER.debug( "to_practice_counts - getting items in groups took %s seconds", (timer('to_practice_counts'))) return render_json(request, response, template='models_json.html', help_text=to_practice_counts.__doc__)
def login(request): """ Log in GET parameters: html turn on the HTML version of the API POST parameters (JSON): username: user's name password: user's password """ if request.method == 'GET': return render(request, 'user_login.html', {}, help_text=login.__doc__) elif request.method == 'POST': credentials = json_body(request.body.decode("utf-8")) user = auth.authenticate( username=credentials.get('username', ''), password=credentials.get('password', ''), ) if user is None: return render_json( request, { 'error': _('Password or username does not match.'), 'error_type': 'password_username_not_match' }, template='user_json.html', status=401) if not user.is_active: return render_json( request, { 'error': _('The account has not been activated.'), 'error_type': 'account_not_activated' }, template='user_json.html', status=401) auth.login(request, user) request.method = "GET" return profile(request) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def plans(request): lang = get_language(request) discount_code = get_discount_code(request) if discount_code is not None: discount_code.is_valid(request.user, throw_exception=True) return render_json(request, [ p.to_json(lang=lang, discount_code=discount_code) for p in SubscriptionPlan.objects.prepare_related().filter(active=True) ], template='subscription_json.html')
def stop_sending_emails(request, user_id, token): profile = get_object_or_404(UserProfile, user_id=user_id) if UserProfile.objects.get_user_hash(profile.user) != token: return render_json(request, { 'error': _('The given token does not match.'), 'error_type': 'unauthorized' }, status=401, template='user_json.html') profile.send_emails = False profile.save() return HttpResponse('ok', status=202)
def plans(request): lang = get_language(request) discount_code = get_discount_code(request) if discount_code is not None: discount_code.is_valid(request.user, throw_exception=True) return render_json( request, [p.to_json(lang=lang, discount_code=discount_code) for p in SubscriptionPlan.objects.prepare_related().filter(active=True)], template='subscription_json.html' )
def languages(request): """ Returns languages that are available in the system. Returns Dict: language_code -> domain """ return render_json(request, settings.LANGUAGE_DOMAINS if hasattr(settings, 'LANGUAGE_DOMAINS') else {"error": "Languages are not set. (Set LANGUAGE_DOMAINS in settings.py)"}, template='common_json.html', help_text=languages.__doc__)
def login_student(request): """ Log in student POST parameters (JSON): student: profile id of the student """ if not get_config('proso_user', 'allow_login_students', default=False): return render_json(request, { 'error': _('Log in as student is not allowed.'), 'error_type': 'login_student_not_allowed' }, template='class_create_student.html', help_text=login_student.__doc__, status=403) if request.method == 'GET': return render(request, 'class_login_student.html', {}, help_text=login_student.__doc__) elif request.method == 'POST': if not request.user.is_authenticated() or not hasattr(request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in.'), 'error_type': 'user_unauthorized' }, template='class_create_student.html', status=401) data = json_body(request.body.decode("utf-8")) try: student = User.objects.get(userprofile=data.get('student'), userprofile__classes__owner=request.user.userprofile) except User.DoesNotExist: return render_json(request, { 'error': _('Student not found'), 'error_type': 'student_not_found' }, template='class_login_student.html', status=401) if not student.is_active: return render_json(request, { 'error': _('The account has not been activated.'), 'error_type': 'account_not_activated' }, template='class_login_student.html', status=401) student.backend = 'django.contrib.auth.backends.ModelBackend' login(request, student) request.method = "GET" return profile(request) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def _csv_table(request, filename): if filename not in [x[1] for xs in get_tables_allowed_to_export().values() for x in xs] and \ filename not in [x for xs in get_custom_exports().values() for x in xs.keys()]: response = {"error": "the requested file '%s' is not valid" % filename} return render_json(request, response, status=400, template='common_json.html') download_file = settings.DATA_DIR + '/' + filename + ".csv" if not os.path.exists(download_file): response = {"error": "there is no data for the given table"} return render_json(request, response, status=204, template='common_json.html') response = HttpResponse(FileWrapper(open(download_file)), content_type='application/csv') response['Content-Length'] = os.path.getsize(download_file) response[ 'Content-Disposition'] = 'attachment; filename=' + filename + '.csv' return response
def status(request): user_id = get_user_id(request) time = get_time(request) environment = get_environment() if is_time_overridden(request): environment.shift_time(time) return render_json(request, { 'object_type': 'status', 'number_of_answers': environment.number_of_answers(user=user_id), 'number_of_correct_answers': environment.number_of_correct_answers(user=user_id), 'environment_info': get_active_environment_info(), }, template='models_json.html')
def classes(request): """Get all classes of current user""" if not request.user.is_authenticated() or not hasattr( request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in'), 'error_type': 'user_unauthorized' }, template='user_json.html', status=401) clss = [ c.to_json() for c in Class.objects.filter(owner=request.user.userprofile) ] return render_json(request, clss, status=200, template='user_json.html', help_text=classes.__doc__)
def signup(request): """ Create a new user with the given credentials. GET parameters: html turn on the HTML version of the API POST parameters (JSON): username: user's name email: user's e-mail password: user's password password_check: user's password again to check it first_name (optional): user's first name last_name (optional): user's last name """ if request.method == 'GET': return render(request, 'user_signup.html', {}, help_text=signup.__doc__) elif request.method == 'POST': if request.user.is_authenticated() and hasattr(request.user, "userprofile"): return render_json(request, { 'error': _('User already logged in'), 'error_type': 'username_logged' }, template='user_json.html', status=400) credentials = json_body(request.body.decode("utf-8")) error = _save_user(request, credentials, new=True) if error is not None: return render_json(request, error, template='user_json.html', status=400) else: auth.login(request, request.user) request.method = "GET" return profile(request, status=201) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def answers(request): limit = min(int(request.GET.get('limit', 10)), 1000) user_id = get_user_id(request) item_ids = Item.objects.filter_all_reachable_leaves( get_filter(request), get_language(request)) found_answers = Answer.objects.answers( Answer.objects.filter(item_asked_id__in=item_ids, user_id=user_id).order_by('-id').values_list( 'id', flat=True)[:limit]) return render_json(request, found_answers, template='models_json.html', help_text=answers.__doc__)
def subscribe(request, description_id): return_url = request.GET.get('return_url', request.META['HTTP_HOST']) description = get_object_or_404(SubscriptionPlanDescription, id=description_id) discount_code = get_discount_code(request) subscription = Subscription.objects.subscribe(request.user, description, discount_code, get_referral_user(request), return_url) return render_json(request, subscription.to_json(), template='subscription_json.html', status=202)
def create_class(request): """Create new class POST parameters (JSON): name: Human readable name of class code (optional): unique code of class used for joining to class """ if request.method == 'GET': return render(request, 'classes_create.html', {}, help_text=create_class.__doc__) if request.method == 'POST': if not request.user.is_authenticated() or not hasattr(request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in.'), 'error_type': 'user_unauthorized' }, template='classes_create.html', status=401) data = json_body(request.body.decode("utf-8")) if 'code' in data and Class.objects.filter(code=data['code']).exists(): return render_json(request, { 'error': _('A class with this code already exists.'), 'error_type': 'class_with_code_exists' }, template='classes_create.html', status=400) if 'name' not in data or not data['name']: return render_json(request, {'error': _('Class name is missing.'), 'error_type': 'missing_class_name'}, template='classes_create.html', status=400) cls = Class(name=data['name'], owner=request.user.userprofile) if 'code' in data: cls.code = data['code'] cls.save() return render_json(request, cls.to_json(), template='classes_create.html', status=201) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def user_stats_bulk(request): """ Get statistics for selected users and concepts since: time as timestamp - get stats changed since users: list of identifiers of users concepts (Optional): list of identifiers of concepts language: language of concepts """ language = get_language(request) users = load_query_json(request.GET, "users") if request.user.is_staff: if not hasattr(request.user, 'userprofile') or User.objects.filter(pk__in=users, userprofile__classes__owner=request.user.userprofile).count() < len(users): return render_json(request, { 'error': _('Some requested users are not in owned classes'), 'error_type': 'permission_denied' }, template='concepts_json.html', status=401) since = None if 'since' in request.GET: since = datetime.datetime.fromtimestamp(int(request.GET['since'])) concepts = None if "concepts" in request.GET: concepts = Concept.objects.filter(lang=language, active=True, identifier__in=load_query_json(request.GET, "concepts")) stats = UserStat.objects.get_user_stats(users, language, concepts=concepts, since=since) data = {"users": []} for user, s in stats.items(): data["users"].append({ "user_id": user, "concepts": s, }) return render_json(request, data, template='concepts_json.html', help_text=user_stats_bulk.__doc__)
def csv(request, filename=None): if not request.user.is_staff: response = { "error": "Permission denied: you need to be staff member. If you think you should be able to access logs, contact admins." } return render_json(request, response, status=401, template='common_json.html') if filename: return _csv_table(request, filename) else: return _csv_list(request)
def tag_values(request): """ Get tags types and values with localized names language: language of tags """ data = defaultdict(lambda: {"values": {}}) for tag in Tag.objects.filter(lang=get_language(request)): data[tag.type]["name"] = tag.type_name data[tag.type]["values"][tag.value] = tag.value_name return render_json(request, data, template='concepts_json.html', help_text=tag_values.__doc__)
def login(request): """ Log in GET parameters: html turn on the HTML version of the API POST parameters (JSON): username: user's name password: user's password """ if request.method == 'GET': return render(request, 'user_login.html', {}, help_text=login.__doc__) elif request.method == 'POST': credentials = json_body(request.body.decode("utf-8")) user = auth.authenticate( username=credentials.get('username', ''), password=credentials.get('password', ''), ) if user is None: return render_json(request, { 'error': _('Password or username does not match.'), 'error_type': 'password_username_not_match' }, template='user_json.html', status=401) if not user.is_active: return render_json(request, { 'error': _('The account has not been activated.'), 'error_type': 'account_not_activated' }, template='user_json.html', status=401) auth.login(request, user) request.method = "GET" return profile(request) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def to_practice_counts(request): """ Get number of items available to practice. filters: -- use this or body json as in BODY language: language of the items BODY json in following format: { "#identifier": [] -- custom identifier (str) and filter ... } """ data = None if request.method == "POST": data = json.loads(request.body.decode("utf-8"))["filters"] if "filters" in request.GET: data = load_query_json(request.GET, "filters") if data is None: return render_json(request, {}, template='models_json.html', help_text=to_practice_counts.__doc__) language = get_language(request) timer('to_practice_counts') filter_names, filter_filters = list(zip(*sorted(data.items()))) reachable_leaves = Item.objects.filter_all_reachable_leaves_many(filter_filters, language) response = { group_id: { 'filter': data[group_id], 'number_of_items': len(items), } for group_id, items in zip(filter_names, reachable_leaves) } LOGGER.debug("flashcard_counts - getting flashcards in groups took %s seconds", (timer('to_practice_counts'))) return render_json(request, response, template='models_json.html', help_text=to_practice_counts.__doc__)
def join_class(request): """Join a class POST parameters (JSON): code: code of the class """ if request.method == 'GET': return render(request, 'classes_join.html', {}, help_text=join_class.__doc__) if request.method == 'POST': if not request.user.is_authenticated() or not hasattr(request.user, "userprofile"): return render_json(request, { 'error': _('User is not logged in.'), 'error_type': 'user_unauthorized' }, template='classes_join.html', status=401) data = json_body(request.body.decode("utf-8")) if 'code' not in data or not data['code']: return render_json(request, {'error': _('Class code is missing.'), 'error_type': 'missing_class_code'}, template='classes_join.html', status=400) try: cls = Class.objects.get(code=data['code']) except Class.DoesNotExist: return render_json(request, { 'error': _('Class with given code not found.'), 'error_type': 'class_not_found', }, template='classes_join.html', status=404) cls.members.add(request.user.userprofile) return render_json(request, cls.to_json(), template='classes_join.html', status=200) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def show_one(request, post_process_fun, object_class, id, template='common_json.html'): """ Return object of the given type with the specified identifier. GET parameters: user: identifier of the current user stats: turn on the enrichment of the objects by some statistics html turn on the HTML version of the API """ obj = get_object_or_404(object_class, pk=id) json = post_process_fun(request, obj) return render_json(request, json, template=template, help_text=show_one.__doc__)
def languages(request): """ Returns languages that are available in the system. Returns Dict: language_code -> domain """ return render_json( request, settings.LANGUAGE_DOMAINS if hasattr(settings, 'LANGUAGE_DOMAINS') else { "error": "Languages are not set. (Set LANGUAGE_DOMAINS in settings.py)" }, template='common_json.html', help_text=languages.__doc__)
def recommend_users(request): ''' Recommend users for further analysis. GET parameters: register_min: minimal date of user's registration ('%Y-%m-%d') register_max: maximal date of user's registration ('%Y-%m-%d') number_of_answers_min: minimal number of user's answers number_of_answers_max: maximal number of user's answers success_min: minimal user's success rate success_max: maximal user's success rate variable_name: name of the filtered parameter variable_min: minimal value of the parameter of the model variable_max: maximal value of parameter of the model limit: number of returned questions (default 10, maximum 100) ''' limit = int(request.GET.get('limit', 1)) def _get_interval(key): return request.GET.get('{}_min'.format(key)), request.GET.get( '{}_max'.format(key)) def _convert_time_interval(interval): mapped = [ None if x is None else datetime.datetime.strptime(x, '%Y-%m-%d') for x in list(interval) ] return mapped[0], mapped[1] recommended = models_recommend_users( _convert_time_interval(_get_interval('register')), _get_interval('number_of_answers'), _get_interval('success'), request.GET.get('variable_name'), _get_interval('variable'), limit) return render_json(request, recommended, template='models_json.html', help_text=recommend_users.__doc__)
def _csv_list(request): apps = defaultdict(dict) for app, app_data in get_tables_allowed_to_export().items(): apps[app]['tables'] = list( map( lambda d: { 'name': d[1], 'url': reverse('csv_table', kwargs={'filename': d[1]}) }, app_data)) for app, app_data in get_custom_exports().items(): apps[app]['custom_exports'] = list( map( lambda name: { 'name': name, 'url': reverse('csv_table', kwargs={'filename': name}) }, app_data)) return render_json(request, apps, template='common_json.html')
def recommend_users(request): ''' Recommend users for further analysis. GET parameters: register_min: minimal date of user's registration ('%Y-%m-%d') register_max: maximal date of user's registration ('%Y-%m-%d') number_of_answers_min: minimal number of user's answers number_of_answers_max: maximal number of user's answers success_min: minimal user's success rate success_max: maximal user's success rate variable_name: name of the filtered parameter variable_min: minimal value of the parameter of the model variable_max: maximal value of parameter of the model limit: number of returned questions (default 10, maximum 100) ''' limit = int(request.GET.get('limit', 1)) def _get_interval(key): return request.GET.get('{}_min'.format(key)), request.GET.get('{}_max'.format(key)) def _convert_time_interval(interval): mapped = [None if x is None else datetime.datetime.strptime(x, '%Y-%m-%d') for x in list(interval)] return mapped[0], mapped[1] recommended = models_recommend_users( _convert_time_interval(_get_interval('register')), _get_interval('number_of_answers'), _get_interval('success'), request.GET.get('variable_name'), _get_interval('variable'), limit) return render_json(request, recommended, template='models_json.html', help_text=recommend_users.__doc__)
def user_stats(request): """ JSON of user stats of the user GET parameters: html (bool): turn on the HTML version of the API, defaults to false user (int): identifier of the user, defaults to logged user concepts (list): list of identifiers of concepts, defaults to all concepts lang (str): language of requested concepts, defaults to language from django """ user = get_user_id(request) language = get_language(request) concepts = None # meaning all concept if "concepts" in request.GET: concepts = Concept.objects.filter(lang=language, active=True, identifier__in=load_query_json(request.GET, "concepts")) data = UserStat.objects.get_user_stats(user, language, concepts) return render_json(request, data, template='concepts_json.html', help_text=user_stats.__doc__)