def feedback(request): """ Send feedback to the authors of the system. GET parameters: html turn on the HTML version of the API POST parameters (JSON): text: the main feedback content email (optional): user's e-mail username (optional): user's name """ if request.method == 'GET': return render(request, 'feedback_feedback.html', {}, help_text=feedback.__doc__) if request.method == 'POST': feedback_data = json_body(request.body.decode("utf-8")) feedback_data['user_agent'] = Session.objects.get_current_session().http_user_agent.content if not feedback_data.get('username'): feedback_data['username'] = request.user.username if not feedback_data.get('email'): feedback_data['email'] = request.user.email comment = Comment.objects.create( username=feedback_data['username'], email=feedback_data['email'], text=feedback_data['text']) if get_config('proso_feedback', 'send_emails', default=True): feedback_domain = get_config('proso_feedback', 'domain', required=True) feedback_to = get_config('proso_feedback', 'to', required=True) if is_likely_worthless(feedback_data): mail_from = 'spam@' + feedback_domain else: mail_from = 'feedback@' + feedback_domain text_content = render_to_string("emails/feedback.plain.txt", { "feedback": feedback_data, "user": request.user, }) html_content = render_to_string("emails/feedback.html", { "feedback": feedback_data, "user": request.user, }) subject = feedback_domain + ' feedback ' + str(comment.id) mail = EmailMultiAlternatives( subject, text_content, mail_from, feedback_to, ) mail.attach_alternative(html_content, "text/html") mail.send() LOGGER.debug("email sent %s\n", text_content) return HttpResponse('ok', status=201) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def __init__(self): name = 'locmemcache@%i' % hash(currentThread()) params = { 'max_entries': get_config('proso_common', 'request_cache.max_entries', 100000) } super(RequestCache, self).__init__(name, params)
def load_environment_info(self, initial, config_name): set_default_config_name(config_name) config = Config.objects.from_content(get_config('proso_models', 'predictive_model', default={})) if initial: if EnvironmentInfo.objects.filter(status=EnvironmentInfo.STATUS_LOADING).count() > 0: raise CommandError("There is already one currently loading environment.") last_revisions = EnvironmentInfo.objects.filter(config=config).order_by('-revision')[:1] if last_revisions: new_revision = last_revisions[0].id + 1 else: new_revision = 0 return EnvironmentInfo.objects.create(config=config, revision=new_revision) else: return EnvironmentInfo.objects.get(config=config, status=EnvironmentInfo.STATUS_LOADING)
def get_item_selector(): cached = get_from_request_permenent_cache(ITEM_SELECTOR_CACHE_KEY) if cached is None: item_selector = instantiate_from_config( 'proso_models', 'item_selector', default_class='proso.models.item_selection.ScoreItemSelection', pass_parameters=[get_predictive_model()] ) nth = get_config('proso_models', 'random_test.nth') if nth is not None and nth > 0: item_selector = TestWrapperItemSelection(item_selector, nth) cached = item_selector set_to_request_permanent_cache(ITEM_SELECTOR_CACHE_KEY, cached) return cached
def home(request, hack=None): JS_FILES = ( "dist/js/bower-libs.min.js", "dist/js/proso-apps-all.js", "dist/js/geography.min.js", "dist/js/geography.html.js", ) CSS_FILES = ( "dist/css/bower-libs.css", "dist/css/app.css", "dist/css/map.css" ) if not hasattr(request.user, "userprofile") or request.user.userprofile is None: environment = get_environment() user = json.dumps({ 'user': {}, 'number_of_answers': environment.number_of_answers(user=request.user.id) if request.user.id is not None else 0, 'number_of_correct_answers': environment.number_of_correct_answers(user=request.user.id) if request.user.id is not None else 0, }) email = '' else: if get_config('proso_user', 'google.openid.migration', default=True) and not is_user_id_overridden(request): migrated_user = migrate_google_openid_user(request.user) if migrated_user is not None: auth.logout(request) migrated_user.backend = 'social_auth.backends.google.GoogleOAuth2Backend' auth.login(request, migrated_user) user = json.dumps(request.user.userprofile.to_json(stats=True)) email = request.user.email c = { 'title': _(u'Slepé mapy') + ' - ' + _(u'inteligentní aplikace na procvičování zeměpisu'), 'map': get_map_from_url(hack), 'is_production': settings.ON_PRODUCTION, 'css_files': CSS_FILES, 'js_files': JS_FILES, 'continents': Category.objects.filter( lang=get_language(), type='continent').order_by('name'), 'states': Category.objects.filter( lang=get_language(), type='state').order_by('name'), 'user_json': user, 'email': email, 'LANGUAGE_CODE': get_language(), 'LANGUAGES': settings.LANGUAGES, 'is_homepage': hack is None, 'config_json': json.dumps(get_global_config()), } return render_to_response('home.html', c)
def home(request, hack=None): if not hasattr(request.user, "userprofile") or request.user.userprofile is None: environment = get_environment() user = json.dumps({ 'user': {}, 'number_of_answers': environment.number_of_answers(user=request.user.id) if request.user.id is not None else 0, 'number_of_correct_answers': environment.number_of_correct_answers(user=request.user.id) if request.user.id is not None else 0, }) email = '' else: if hack is None: return redirect('/overview/') if get_config('proso_user', 'google.openid.migration', default=True) and not is_user_id_overridden(request): migrated_user = migrate_google_openid_user(request.user) if migrated_user is not None: auth.logout(request) migrated_user.backend = 'social_auth.backends.google.GoogleOAuth2Backend' auth.login(request, migrated_user) user = json.dumps(request.user.userprofile.to_json(stats=True)) email = request.user.email c = { 'title': _(u'Slepé mapy') + ' - ' + _(u'inteligentní aplikace na procvičování zeměpisu'), 'map': get_map_from_url(hack), 'is_production': settings.ON_PRODUCTION, 'css_files': CSS_FILES, 'map_files': get_map_files(), 'js_files': JS_FILES, 'continents': Category.objects.filter( lang=get_language(), type='continent').order_by('name'), 'states': Category.objects.filter( lang=get_language(), type='state').order_by('name'), 'regions': Category.objects.filter( lang=get_language(), type='region').order_by('name'), 'user_json': user, 'email': email, 'LANGUAGE_CODE': get_language(), 'LANGUAGES': settings.LANGUAGES, 'LANGUAGE_DOMAINS': settings.LANGUAGE_DOMAINS if hasattr( settings, 'LANGUAGE_DOMAINS') else {}, 'is_homepage': hack is None, 'hack': hack or '', 'config_json': json.dumps(get_global_config()), 'DOMAIN': request.build_absolute_uri('/')[:-1], 'screenshot_files': get_screenshot_files(request, hack), } return render_to_response('home.html', c)
def confusing_factor_more_items(self, item, items, user=None): cached_all = {} confusing_factor_cache = cache.get('database_environment__confusing_factor', {}) for item_secondary in items: _items = self._sorted([item, item_secondary]) cache_key = '{}_{}_{}'.format(_items[0], _items[1], user) cached_item = confusing_factor_cache.get(cache_key) if cached_item: cached_all[item_secondary] = int(cached_item) to_find = [i for i in items if i not in list(cached_all.keys())] if len(cached_all) != 0: LOGGER.debug('cache hit for confusing factor, item {}, {} other items and user {}'.format(item, len(cached_all), user)) if len(to_find) != 0: LOGGER.debug('cache miss for confusing factor, item {}, {} other items and user {}'.format(item, len(to_find), user)) where, where_params = self._where({ 'item_answered_id': to_find, 'item_asked_id': to_find, }, force_null=False, for_answers=True, conjuction=False) user_where, user_params = self._column_comparison('user_id', user, force_null=False) with closing(connection.cursor()) as cursor: cursor.execute( ''' SELECT item_asked_id, item_answered_id, COUNT(id) AS confusing_factor FROM proso_models_answer WHERE guess = 0 AND (item_asked_id = %s OR item_asked_id = %s) AND ''' + user_where + ' AND (' + where + ') GROUP BY item_asked_id, item_answered_id', [item, item] + user_params + where_params) found = {} for item_asked, item_answered, count in cursor: if item_asked == item: found[item_answered] = found.get(item_answered, 0) + count else: found[item_asked] = found.get(item_asked, 0) + count for i in to_find: found[i] = found.get(i, 0) cache_expiration = get_config('proso_models', 'confusing_factor.cache_expiration', default=24 * 60 * 60) for item_secondary, count in found.items(): _items = self._sorted([item, item_secondary]) cache_key = '{}_{}_{}'.format(_items[0], _items[1], user) confusing_factor_cache[cache_key] = count cached_all[item_secondary] = count cache.set('database_environment__confusing_factor', confusing_factor_cache, cache_expiration) return [cached_all[i] for i in items]
def get_active_environment_info(): if is_cache_prepared(): cached = get_request_cache().get(ENVIRONMENT_INFO_CACHE_KEY) if cached is not None: return cached cached = cache.get(ENVIRONMENT_INFO_CACHE_KEY) if cached is None: try: active_envinfo = EnvironmentInfo.objects.select_related('config').get(status=EnvironmentInfo.STATUS_ACTIVE) except EnvironmentInfo.DoesNotExist: config = Config.objects.from_content(get_config('proso_models', 'predictive_model', default={})) active_envinfo, _ = EnvironmentInfo.objects.get_or_create(config=config, status=EnvironmentInfo.STATUS_ACTIVE, revision=0) cached = active_envinfo.to_json() if is_cache_prepared(): get_request_cache().set(ENVIRONMENT_INFO_CACHE_KEY, cached) if EnvironmentInfo.objects.filter(status=EnvironmentInfo.STATUS_LOADING).count() == 0: cache.set(ENVIRONMENT_INFO_CACHE_KEY, cached, ENVIRONMENT_INFO_CACHE_EXPIRATION) return cached
def load_environment_info(self, initial, config_name): set_default_config_name(config_name) config = Config.objects.from_content( get_config('proso_models', 'predictive_model', default={})) if initial: if EnvironmentInfo.objects.filter( status=EnvironmentInfo.STATUS_LOADING).count() > 0: raise CommandError( "There is already one currently loading environment.") last_revisions = EnvironmentInfo.objects.filter( config=config).order_by('-revision')[:1] if last_revisions: new_revision = last_revisions[0].id + 1 else: new_revision = 0 return EnvironmentInfo.objects.create(config=config, revision=new_revision) else: return EnvironmentInfo.objects.get( config=config, status=EnvironmentInfo.STATUS_LOADING)
def profile(request, status=200): """ Get the user's profile. If the user has no assigned profile, the HTTP 404 is returned. Make a POST request to modify the user's profile. GET parameters: html turn on the HTML version of the API username: username of user (only for users with public profile) stats: attache addition user statistics POST parameters (JSON): send_emails: switcher turning on sending e-mails to user public: swicher making the user's profile publicly available user: 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': if request.GET.get("username", False): try: user_profile = User.objects.get(username=request.GET.get("username"), userprofile__public=True).userprofile except ObjectDoesNotExist: raise Http404("user not found or have not public profile") else: user_id = get_user_id(request) if get_config('proso_user', 'google.openid.migration', default=True) and not is_user_id_overridden(request): migrated_user = migrate_google_openid_user(request.user) if migrated_user is not None: auth.logout(request) migrated_user.backend = 'social.backends.google.GoogleOAuth2' auth.login(request, migrated_user) user_profile = get_object_or_404(UserProfile, user_id=user_id) return render_json( request, user_profile, status=status, template='user_profile.html', help_text=profile.__doc__) elif request.method == 'POST': with transaction.atomic(): to_save = json_body(request.body.decode("utf-8")) user_id = get_user_id(request) user_profile = get_object_or_404(UserProfile, user_id=user_id) user = to_save.get('user', None) if 'send_emails' in to_save: user_profile.send_emails = bool(to_save['send_emails']) if 'public' in to_save: user_profile.public = bool(to_save['public']) if user: error = _save_user(request, user, new=False) if error: return render_json(request, error, template='user_json.html', status=400) if 'properties' in to_save: user_profile.save_properties(to_save['properties']) user_profile.save() request.method = "GET" return profile(request, status=202) else: return HttpResponseBadRequest("method %s is not allowed".format(request.method))
def get_mastery_trashold(): return get_config("proso_models", "mastery_threshold", default=0.9)
def __init__(self): name = 'locmemcache@%i' % hash(currentThread()) params = {'max_entries': get_config('proso_common', 'request_cache.max_entries', 100000)} super(RequestCache, self).__init__(name, params)
def test_get_config(self): self.assertEqual(get_config('proso_tests', 'a.b.c'), 'blah') self.assertEqual(get_config('proso_tests', 'unknown', default='is here'), 'is here') with self.assertRaises(Exception): get_config('proso_tests', 'unknown', require=True)
def test_config_default_name(self): set_default_config_name('super') self.assertEqual(get_default_config_name(), 'super') self.assertIsNone(get_config('proso_tests', 'a.b.c'))
def profile(request, status=200): """ Get the user's profile. If the user has no assigned profile, the HTTP 404 is returned. Make a POST request to modify the user's profile. GET parameters: html turn on the HTML version of the API username: username of user (only for users with public profile) stats: attache addition user statistics POST parameters (JSON): send_emails: switcher turning on sending e-mails to user public: swicher making the user's profile publicly available user: 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': if request.GET.get("username", False): try: user_profile = User.objects.get( username=request.GET.get("username"), userprofile__public=True).userprofile except ObjectDoesNotExist: raise Http404("user not found or have not public profile") else: user_id = get_user_id(request) if get_config('proso_user', 'google.openid.migration', default=True) and not is_user_id_overridden(request): migrated_user = migrate_google_openid_user(request.user) if migrated_user is not None: auth.logout(request) migrated_user.backend = 'social.backends.google.GoogleOAuth2' auth.login(request, migrated_user) user_profile = get_object_or_404(UserProfile, user_id=user_id) return render_json(request, user_profile, status=status, template='user_profile.html', help_text=profile.__doc__) elif request.method == 'POST': with transaction.atomic(): to_save = json_body(request.body.decode("utf-8")) user_id = get_user_id(request) user_profile = get_object_or_404(UserProfile, user_id=user_id) user = to_save.get('user', None) if 'send_emails' in to_save: user_profile.send_emails = bool(to_save['send_emails']) if 'public' in to_save: user_profile.public = bool(to_save['public']) if user: error = _save_user(request, user, new=False) if error: return render_json(request, error, template='user_json.html', status=400) if 'properties' in to_save: user_profile.save_properties(to_save['properties']) user_profile.save() request.method = "GET" return profile(request, status=202) else: return HttpResponseBadRequest("method %s is not allowed".format( request.method))
def test_get_config(self): self.assertEqual(get_config('proso_tests', 'a.b.c'), 'blah') self.assertEqual( get_config('proso_tests', 'unknown', default='is here'), 'is here') with self.assertRaises(Exception): get_config('proso_tests', 'unknown', require=True)