def handle(self, *args, **options): """ Execute the command. """ old_lang_code = options['old_lang_code'] new_lang_code = options['new_lang_code'] chunk_size = options['chunk_size'] sleep_time_secs = options['sleep_time_secs'] start = options['start_id'] end = start + chunk_size # Make sure we're changing to a code that actually exists. Presumably it's safe to move away from a code that # doesn't. dark_lang_config = DarkLangConfig.current() langs = [lang_code[0] for lang_code in settings.LANGUAGES] langs += dark_lang_config.released_languages_list langs += dark_lang_config.beta_languages_list if dark_lang_config.enable_beta_languages else [] if new_lang_code not in langs: raise CommandError(u'{} is not a configured language code in settings.LANGUAGES ' 'or the current DarkLangConfig.'.format(new_lang_code)) max_id = UserPreference.objects.all().aggregate(Max('id'))['id__max'] print(u'Updating user language preferences from {} to {}. ' u'Start id is {}, current max id is {}. ' u'Chunk size is of {}'.format(old_lang_code, new_lang_code, start, max_id, chunk_size)) updated_count = 0 while True: # On the last time through catch any new rows added since this run began if end >= max_id: print('Last round, includes all new rows added since this run started.') id_query = Q(id__gte=start) else: id_query = Q(id__gte=start) & Q(id__lt=end) curr = UserPreference.objects.filter( id_query, key='pref-lang', value=old_lang_code ).update(value=new_lang_code) updated_count += curr print(u'Updated rows {} to {}, {} rows affected'.format(start, end - 1, curr)) if end >= max_id: break start = end end += chunk_size sleep(sleep_time_secs) print(u'Finished! Updated {} total preferences from {} to {}'.format( updated_count, old_lang_code, new_lang_code ))
def released_languages(): """Retrieve the list of released languages. Constructs a list of Language tuples by intersecting the list of valid language tuples with the list of released language codes. Returns: list of Language: Languages in which full translations are available. Example: >>> print released_languages() [Language(code='en', name=u'English'), Language(code='fr', name=u'Français')] """ released_language_codes = DarkLangConfig.current().released_languages_list default_language_code = settings.LANGUAGE_CODE if default_language_code not in released_language_codes: released_language_codes.append(default_language_code) released_language_codes.sort() # Intersect the list of valid language tuples with the list # of released language codes return [ Language(language_info[0], language_info[1]) for language_info in settings.LANGUAGES if language_info[0] in released_language_codes ]
def _user_can_preview_languages(self, user): """ Returns true if the specified user can preview languages. """ if not DarkLangConfig.current().enabled: return False return user and not user.is_anonymous
def process_darklang_request(self, request): """ Proccess the request to Set or clear the DarkLang depending on the incoming request. Arguments: request (Request): The Django Request Object Returns: HttpResponse: View containing the form for setting the preview lang with the status included in the context """ context = {'disable_courseware_js': True, 'uses_pattern_library': True} response = None if not DarkLangConfig.current().enabled: message = _('Preview Language is currently disabled') context.update({'form_submit_message': message}) context.update({'success': False}) response = render_to_response(self.template_name, context, request=request) elif 'set_language' in request.POST: # Set the Preview Language response = self._set_preview_language(request, context) elif 'reset' in request.POST: # Reset and clear the language preference response = self._clear_preview_language(request, context) return response
def process_request(self, request): """ If a user's UserPreference contains a language preference, use the user's preference. Save the current language preference cookie as the user's preferred language. """ cookie_lang = lang_pref_helpers.get_language_cookie(request) if cookie_lang: if request.user.is_authenticated: # DarkLangMiddleware will take care of this so don't change anything if DarkLangConfig.current().enabled and get_user_preference(request.user, DARK_LANGUAGE_KEY): return set_user_preference(request.user, LANGUAGE_KEY, cookie_lang) else: request._anonymous_user_cookie_lang = cookie_lang # lint-amnesty, pylint: disable=protected-access accept_header = request.META.get(LANGUAGE_HEADER, None) if accept_header: current_langs = parse_accept_lang_header(accept_header) # Promote the cookie_lang over any language currently in the accept header current_langs = [(lang, qvalue) for (lang, qvalue) in current_langs if lang != cookie_lang] current_langs.insert(0, (cookie_lang, 1)) accept_header = ",".join(f"{lang};q={qvalue}" for (lang, qvalue) in current_langs) else: accept_header = cookie_lang request.META[LANGUAGE_HEADER] = accept_header # Allow the new cookie setting to update the language in the user's session if LANGUAGE_SESSION_KEY in request.session and request.session[LANGUAGE_SESSION_KEY] != cookie_lang: del request.session[LANGUAGE_SESSION_KEY]
def process_darklang_request(self, request): """ Proccess the request to Set or clear the DarkLang depending on the incoming request. Arguments: request (Request): The Django Request Object Returns: HttpResponse: View containing the form for setting the preview lang with the status included in the context """ context = { 'disable_courseware_js': True, 'uses_pattern_library': True } response = None if not DarkLangConfig.current().enabled: message = _('Preview Language is currently disabled') context.update({'form_submit_message': message}) context.update({'success': False}) response = render_to_response(self.template_name, context, request=request) elif 'set_language' in request.POST: # Set the Preview Language response = self._set_preview_language(request, context) elif 'reset' in request.POST: # Reset and clear the language preference response = self._clear_preview_language(request, context) return response
def process_response(self, request, response): # lint-amnesty, pylint: disable=missing-function-docstring # If the user is logged in, check for their language preference. Also check for real user # if current user is a masquerading user, user_pref = None current_user = None if hasattr(request, 'user'): current_user = getattr(request.user, 'real_user', request.user) if current_user and current_user.is_authenticated: # DarkLangMiddleware has already set this cookie if DarkLangConfig.current().enabled and get_user_preference(current_user, DARK_LANGUAGE_KEY): return response anonymous_cookie_lang = getattr(request, '_anonymous_user_cookie_lang', None) if anonymous_cookie_lang: user_pref = anonymous_cookie_lang set_user_preference(current_user, LANGUAGE_KEY, anonymous_cookie_lang) else: # Get the user's language preference try: user_pref = get_user_preference(current_user, LANGUAGE_KEY) except (UserAPIRequestError, UserAPIInternalError): # If we can't find the user preferences, then don't modify the cookie pass # If set, set the user_pref in the LANGUAGE_COOKIE_NAME if user_pref and not is_request_from_mobile_app(request): lang_pref_helpers.set_language_cookie(request, response, user_pref) else: lang_pref_helpers.unset_language_cookie(response) return response
def beta_langs(self): """ Current list of released languages """ language_options = DarkLangConfig.current().beta_languages_list if settings.LANGUAGE_CODE not in language_options: language_options.append(settings.LANGUAGE_CODE) return language_options
def process_request(self, request): """ Prevent user from requesting un-released languages except by using the preview-lang query string. """ if not DarkLangConfig.current().enabled: return self._clean_accept_headers(request)
def released_langs(self): """ Current list of released languages """ language_options = DarkLangConfig.current().released_languages_list language_code = configuration_helpers.get_value('LANGUAGE_CODE') if language_code not in language_options: language_options.append(language_code) return language_options
def process_request(self, request): """ Prevent user from requesting un-released languages except by using the preview-lang query string. """ if not DarkLangConfig.current().enabled: return self._clean_accept_headers(request) self._activate_preview_language(request)
def process_response(self, request, response): """ Apply user's dark lang preference as a cookie for future requests. """ if DarkLangConfig.current().enabled: self._set_site_or_microsite_language(request, response) self._activate_preview_language(request, response) return response
def _fuzzy_match(self, lang_code): """Returns a fuzzy match for lang_code""" match = None dark_lang_config = DarkLangConfig.current() if dark_lang_config.enable_beta_languages: langs = self.released_langs + self.beta_langs else: langs = self.released_langs if lang_code in langs: match = lang_code else: lang_prefix = lang_code.partition('-')[0] for released_lang in langs: released_prefix = released_lang.partition('-')[0] if lang_prefix == released_prefix: match = released_lang return match
def released_languages(): """Retrieve the list of released languages. Constructs a list of Language tuples by intersecting the list of valid language tuples with the list of released language codes. If request comes from a Microsite, it will look for the LANGUAGE_LIST in the microsite configuration Returns: list of Language: Languages in which full translations are available. Example: >>> print released_languages() [Language(code='en', name=u'English'), Language(code='fr', name=u'Français')] """ released_language_codes = DarkLangConfig.current().released_languages_list default_language_code = configuration_helpers.get_value('LANGUAGE_CODE') site_languages = configuration_helpers.get_value('LANGUAGE_LIST', None) if site_languages is not None: released_language_codes = site_languages if default_language_code not in released_language_codes: released_language_codes.append(default_language_code) released_language_codes.sort() # Intersect the list of valid language tuples with the list # of released language codes return [ Language(language_info[0], language_info[1]) for language_info in settings.LANGUAGES if language_info[0] in released_language_codes ]
def account_settings_context(request): """ Context for the account settings page. Args: request: The request object. Returns: dict """ user = request.user year_of_birth_options = [(six.text_type(year), six.text_type(year)) for year in UserProfile.VALID_YEARS] try: user_orders = get_user_orders(user) except: # pylint: disable=bare-except log.exception('Error fetching order history from Otto.') # Return empty order list as account settings page expect a list and # it will be broken if exception raised user_orders = [] beta_language = {} dark_lang_config = DarkLangConfig.current() if dark_lang_config.enable_beta_languages: user_preferences = get_user_preferences(user) pref_language = user_preferences.get('pref-lang') if pref_language in dark_lang_config.beta_languages_list: beta_language['code'] = pref_language beta_language['name'] = settings.LANGUAGE_DICT.get(pref_language) context = { 'auth': {}, 'duplicate_provider': None, 'nav_hidden': True, 'fields': { 'country': { 'options': list(countries), }, 'gender': { 'options': [(choice[0], _(choice[1])) for choice in UserProfile.GENDER_CHOICES], }, 'language': { 'options': released_languages(), }, 'level_of_education': { 'options': [(choice[0], _(choice[1])) for choice in UserProfile.LEVEL_OF_EDUCATION_CHOICES], }, 'password': { 'url': reverse('password_reset'), }, 'year_of_birth': { 'options': year_of_birth_options, }, 'preferred_language': { 'options': all_languages(), }, 'time_zone': { 'options': TIME_ZONE_CHOICES, } }, 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'password_reset_support_link': configuration_helpers.get_value('PASSWORD_RESET_SUPPORT_LINK', settings.PASSWORD_RESET_SUPPORT_LINK) or settings.SUPPORT_SITE_LINK, 'user_accounts_api_url': reverse("accounts_api", kwargs={'username': user.username}), 'user_preferences_api_url': reverse('preferences_api', kwargs={'username': user.username}), 'disable_courseware_js': True, 'show_program_listing': ProgramsApiConfig.is_enabled(), 'show_dashboard_tabs': True, 'order_history': user_orders, 'disable_order_history_tab': should_redirect_to_order_history_microfrontend(), 'enable_account_deletion': configuration_helpers.get_value( 'ENABLE_ACCOUNT_DELETION', settings.FEATURES.get('ENABLE_ACCOUNT_DELETION', False)), 'extended_profile_fields': _get_extended_profile_fields(), 'beta_language': beta_language, } enterprise_customer = enterprise_customer_for_request(request) update_account_settings_context_for_enterprise(context, enterprise_customer, user) if third_party_auth.is_enabled(): # If the account on the third party provider is already connected with another edX account, # we display a message to the user. context['duplicate_provider'] = pipeline.get_duplicate_provider( messages.get_messages(request)) auth_states = pipeline.get_provider_user_states(user) context['auth']['providers'] = [ { 'id': state.provider.provider_id, 'name': state.provider.name, # The name of the provider e.g. Facebook 'connected': state. has_account, # Whether the user's edX account is connected with the provider. # If the user is not connected, they should be directed to this page to authenticate # with the particular provider, as long as the provider supports initiating a login. 'connect_url': pipeline.get_login_url( state.provider.provider_id, pipeline.AUTH_ENTRY_ACCOUNT_SETTINGS, # The url the user should be directed to after the auth process has completed. redirect_url=reverse('account_settings'), ), 'accepts_logins': state.provider.accepts_logins, # If the user is connected, sending a POST request to this url removes the connection # information for this provider from their edX account. 'disconnect_url': pipeline.get_disconnect_url(state.provider.provider_id, state.association_id), # We only want to include providers if they are either currently available to be logged # in with, or if the user is already authenticated with them. } for state in auth_states if state.provider.display_for_login or state.has_account ] return context
def account_settings_context(request): """ Context for the account settings page. Args: request: The request object. Returns: dict """ user = request.user year_of_birth_options = [(unicode(year), unicode(year)) for year in UserProfile.VALID_YEARS] try: user_orders = get_user_orders(user) except: # pylint: disable=bare-except log.exception('Error fetching order history from Otto.') # Return empty order list as account settings page expect a list and # it will be broken if exception raised user_orders = [] beta_language = {} dark_lang_config = DarkLangConfig.current() if dark_lang_config.enable_beta_languages: user_preferences = get_user_preferences(user) pref_language = user_preferences.get('pref-lang') if pref_language in dark_lang_config.beta_languages_list: beta_language['code'] = pref_language beta_language['name'] = settings.LANGUAGE_DICT.get(pref_language) context = { 'auth': {}, 'duplicate_provider': None, 'nav_hidden': True, 'fields': { 'country': { 'options': list(countries), }, 'gender': { 'options': [(choice[0], _(choice[1])) for choice in UserProfile.GENDER_CHOICES], }, 'language': { 'options': released_languages(), }, 'level_of_education': { 'options': [(choice[0], _(choice[1])) for choice in UserProfile.LEVEL_OF_EDUCATION_CHOICES], }, 'password': { 'url': reverse('password_reset'), }, 'year_of_birth': { 'options': year_of_birth_options, }, 'preferred_language': { 'options': all_languages(), }, 'time_zone': { 'options': TIME_ZONE_CHOICES, } }, 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'password_reset_support_link': configuration_helpers.get_value( 'PASSWORD_RESET_SUPPORT_LINK', settings.PASSWORD_RESET_SUPPORT_LINK ) or settings.SUPPORT_SITE_LINK, 'user_accounts_api_url': reverse("accounts_api", kwargs={'username': user.username}), 'user_preferences_api_url': reverse('preferences_api', kwargs={'username': user.username}), 'disable_courseware_js': True, 'show_program_listing': ProgramsApiConfig.is_enabled(), 'show_dashboard_tabs': True, 'order_history': user_orders, 'disable_order_history_tab': should_redirect_to_order_history_microfrontend(), 'enable_account_deletion': configuration_helpers.get_value( 'ENABLE_ACCOUNT_DELETION', settings.FEATURES.get('ENABLE_ACCOUNT_DELETION', False) ), 'extended_profile_fields': _get_extended_profile_fields(), 'beta_language': beta_language, } enterprise_customer = get_enterprise_customer_for_learner(user=request.user) update_account_settings_context_for_enterprise(context, enterprise_customer) if third_party_auth.is_enabled(): # If the account on the third party provider is already connected with another edX account, # we display a message to the user. context['duplicate_provider'] = pipeline.get_duplicate_provider(messages.get_messages(request)) auth_states = pipeline.get_provider_user_states(user) context['auth']['providers'] = [{ 'id': state.provider.provider_id, 'name': state.provider.name, # The name of the provider e.g. Facebook 'connected': state.has_account, # Whether the user's edX account is connected with the provider. # If the user is not connected, they should be directed to this page to authenticate # with the particular provider, as long as the provider supports initiating a login. 'connect_url': pipeline.get_login_url( state.provider.provider_id, pipeline.AUTH_ENTRY_ACCOUNT_SETTINGS, # The url the user should be directed to after the auth process has completed. redirect_url=reverse('account_settings'), ), 'accepts_logins': state.provider.accepts_logins, # If the user is connected, sending a POST request to this url removes the connection # information for this provider from their edX account. 'disconnect_url': pipeline.get_disconnect_url(state.provider.provider_id, state.association_id), # We only want to include providers if they are either currently available to be logged # in with, or if the user is already authenticated with them. } for state in auth_states if state.provider.display_for_login or state.has_account] return context