def send_account_recovery_email_for_user(user, request, email=None): """ Send out a account recovery email for the given user. Arguments: user (User): Django User object request (HttpRequest): Django request object email (str): Send email to this address. """ site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'request': request, # Used by google_analytics_tracking_pixel 'email': email, 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'reset_link': '{protocol}://{site}{link}?is_account_recovery=true'.format( protocol='https' if request.is_secure() else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('password_reset_confirm', kwargs={ 'uidb36': int_to_base36(user.id), 'token': default_token_generator.make_token(user), }), ) }) msg = AccountRecoveryMessage().personalize( recipient=Recipient(user.username, email), language=get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) ace.send(msg)
def send_password_reset_email_for_user(user, request, preferred_email=None): """ Send out a password reset email for the given user. Arguments: user (User): Django User object request (HttpRequest): Django request object preferred_email (str): Send email to this address if present, otherwise fallback to user's email address. """ site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'request': request, # Used by google_analytics_tracking_pixel # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'reset_link': '{protocol}://{site}{link}'.format( protocol='https' if request.is_secure() else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('password_reset_confirm', kwargs={ 'uidb36': int_to_base36(user.id), 'token': default_token_generator.make_token(user), }), ) }) msg = PasswordReset().personalize( recipient=Recipient(user.username, preferred_email or user.email), language=get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) ace.send(msg)
def save(self, # pylint: disable=arguments-differ use_https=False, token_generator=default_token_generator, request=None, **_kwargs): """ Generates a one-use only link for resetting password and sends to the user. """ for user in self.users_cache: site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'request': request, # Used by google_analytics_tracking_pixel # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'reset_link': '{protocol}://{site}{link}'.format( protocol='https' if use_https else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('password_reset_confirm', kwargs={ 'uidb36': int_to_base36(user.id), 'token': token_generator.make_token(user), }), ) }) msg = PasswordReset().personalize( recipient=Recipient(user.username, user.email), language=get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) ace.send(msg)
def send_discussion_email_notification(sender, user, post, **kwargs): if not waffle().is_enabled(FORUM_RESPONSE_NOTIFICATIONS): log.debug('Discussion: Response notifications waffle switch not enabled') return if not SEND_NOTIFICATIONS_FOR_COURSE.is_enabled(CourseKey.from_string(post.thread.course_id)): log.debug('Discussion: Response notifications not enabled for course: %s.', post.thread.course_id) return current_site = get_current_site() if current_site is None: log.info('Discussion: No current site, not sending notification about post: %s.', post.id) return try: if not current_site.configuration.get_value(ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY, False): log_message = 'Discussion: notifications not enabled for site: %s. Not sending message about post: %s.' log.info(log_message, current_site, post.id) return except SiteConfiguration.DoesNotExist: log_message = 'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.' log.info(log_message, current_site, post.id) return send_message(post, current_site)
def _create_schedule(enrollment, enrollment_created): """ Checks configuration and creates Schedule with ScheduleExperience for this enrollment. """ if not enrollment_created: # only create schedules when enrollment records are created return current_site = get_current_site() if current_site is None: log.debug('Schedules: No current site') return schedule_config = ScheduleConfig.current(current_site) if ( not schedule_config.create_schedules and not CREATE_SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id) ): log.debug('Schedules: Creation not enabled for this course or for this site') return if not enrollment.course_overview.self_paced: log.debug('Schedules: Creation only enabled for self-paced courses') return # This represents the first date at which the learner can access the content. This will be the latter of # either the enrollment date or the course's start date. content_availability_date = max(enrollment.created, enrollment.course_overview.start) upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date) experience_type = _get_experience_type(enrollment) if _should_randomly_suppress_schedule_creation( schedule_config, enrollment, upgrade_deadline, experience_type, content_availability_date, ): return schedule = Schedule.objects.create( enrollment=enrollment, start=content_availability_date, upgrade_deadline=upgrade_deadline ) ScheduleExperience(schedule=schedule, experience_type=experience_type).save() return { 'content_availability_date': content_availability_date, 'upgrade_deadline': upgrade_deadline, 'experience_type': experience_type, }
def get_programs(uuid=None): """Read programs from the cache. The cache is populated by a management command, cache_programs. Keyword Arguments: uuid (string): UUID identifying a specific program to read from the cache. Returns: list of dict, representing programs. dict, if a specific program is requested. """ missing_details_msg_tpl = 'Failed to get details for program {uuid} from the cache.' if uuid: program = cache.get(PROGRAM_CACHE_KEY_TPL.format(uuid=uuid)) if not program: logger.warning(missing_details_msg_tpl.format(uuid=uuid)) return program if waffle.switch_is_active('get-multitenant-programs'): uuids = cache.get(SITE_PROGRAM_UUIDS_CACHE_KEY_TPL.format(domain=get_current_site().domain), []) else: uuids = cache.get(PROGRAM_UUIDS_CACHE_KEY, []) if not uuids: logger.warning('Failed to get program UUIDs from the cache.') programs = cache.get_many([PROGRAM_CACHE_KEY_TPL.format(uuid=uuid) for uuid in uuids]) programs = list(programs.values()) # The get_many above sometimes fails to bring back details cached on one or # more Memcached nodes. It doesn't look like these keys are being evicted. # 99% of the time all keys come back, but 1% of the time all the keys stored # on one or more nodes are missing from the result of the get_many. One # get_many may fail to bring these keys back, but a get_many occurring # immediately afterwards will succeed in bringing back all the keys. This # behavior can be mitigated by trying again for the missing keys, which is # what we do here. Splitting the get_many into smaller chunks may also help. missing_uuids = set(uuids) - set(program['uuid'] for program in programs) if missing_uuids: logger.info( 'Failed to get details for {count} programs. Retrying.'.format(count=len(missing_uuids)) ) retried_programs = cache.get_many([PROGRAM_CACHE_KEY_TPL.format(uuid=uuid) for uuid in missing_uuids]) programs += list(retried_programs.values()) still_missing_uuids = set(uuids) - set(program['uuid'] for program in programs) for uuid in still_missing_uuids: logger.warning(missing_details_msg_tpl.format(uuid=uuid)) return programs
def create_schedule(sender, **kwargs): if not kwargs['created']: # only create schedules when enrollment records are created return current_site = get_current_site() if current_site is None: log.debug('Schedules: No current site') return enrollment = kwargs['instance'] schedule_config = ScheduleConfig.current(current_site) if not schedule_config.create_schedules: log.debug('Schedules: Creation not enabled for this course or for this site') return if not enrollment.course_overview.self_paced: log.debug('Schedules: Creation only enabled for self-paced courses') return # This represents the first date at which the learner can access the content. This will be the latter of # either the enrollment date or the course's start date. content_availability_date = max(enrollment.created, enrollment.course_overview.start) upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date) if course_has_highlights(enrollment.course_id): experience_type = ScheduleExperience.EXPERIENCES.course_updates else: experience_type = ScheduleExperience.EXPERIENCES.default if _should_randomly_suppress_schedule_creation( schedule_config, enrollment, upgrade_deadline, experience_type, content_availability_date, ): return schedule = Schedule.objects.create( enrollment=enrollment, start=content_availability_date, upgrade_deadline=upgrade_deadline ) ScheduleExperience(schedule=schedule, experience_type=experience_type).save() log.debug('Schedules: created a new schedule starting at %s with an upgrade deadline of %s and experience type: %s', content_availability_date, upgrade_deadline, ScheduleExperience.EXPERIENCES[experience_type])
def get_current_site_configuration(): """ Return configuration for the current site. Returns: (openedx.core.djangoapps.site_configuration.models.SiteConfiguration): SiteConfiguration instance associated with the current site. """ # Import is placed here to avoid circular import from openedx.core.djangoapps.theming.helpers import get_current_site site = get_current_site() try: return getattr(site, "configuration", None) except SiteConfiguration.DoesNotExist: return None
def send_discussion_email_notification(sender, user, post, **kwargs): current_site = get_current_site() if current_site is None: log.info(u'Discussion: No current site, not sending notification about post: %s.', post.id) return try: if not current_site.configuration.get_value(ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY, False): log_message = u'Discussion: notifications not enabled for site: %s. Not sending message about post: %s.' log.info(log_message, current_site, post.id) return except SiteConfiguration.DoesNotExist: log_message = u'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.' log.info(log_message, current_site, post.id) return send_message(post, current_site)
def create_schedule(sender, **kwargs): if not kwargs['created']: # only create schedules when enrollment records are created return current_site = get_current_site() if current_site is None: log.debug('Schedules: No current site') return enrollment = kwargs['instance'] schedule_config = ScheduleConfig.current(current_site) if ( not schedule_config.create_schedules and not CREATE_SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id) ): log.debug('Schedules: Creation not enabled for this course or for this site') return if not enrollment.course_overview.self_paced: log.debug('Schedules: Creation only enabled for self-paced courses') return # This represents the first date at which the learner can access the content. This will be the latter of # either the enrollment date or the course's start date. content_availability_date = max(enrollment.created, enrollment.course_overview.start) upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date) schedule = Schedule.objects.create( enrollment=enrollment, start=content_availability_date, upgrade_deadline=upgrade_deadline ) try: get_week_highlights(enrollment.course_id, 1) experience_type = ScheduleExperience.EXPERIENCES.course_updates except CourseUpdateDoesNotExist: experience_type = ScheduleExperience.EXPERIENCES.default ScheduleExperience(schedule=schedule, experience_type=experience_type).save() log.debug('Schedules: created a new schedule starting at %s with an upgrade deadline of %s and experience type: %s', content_availability_date, upgrade_deadline, ScheduleExperience.EXPERIENCES[experience_type])
def create_schedule(sender, **kwargs): if not kwargs['created']: # only create schedules when enrollment records are created return current_site = get_current_site() if current_site is None: log.debug('Schedules: No current site') return enrollment = kwargs['instance'] schedule_config = ScheduleConfig.current(current_site) if ( not schedule_config.create_schedules and not SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id) ): log.debug('Schedules: Creation not enabled for this course or for this site') return if not enrollment.course_overview.self_paced: log.debug('Schedules: Creation only enabled for self-paced courses') return # This represents the first date at which the learner can access the content. This will be the latter of # either the enrollment date or the course's start date. content_availability_date = max(enrollment.created, enrollment.course_overview.start) upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date) Schedule.objects.create( enrollment=enrollment, start=content_availability_date, upgrade_deadline=upgrade_deadline ) log.debug('Schedules: created a new schedule starting at %s with an upgrade deadline of %s', content_availability_date, upgrade_deadline)
def send_password_reset_email_for_user(user, request, preferred_email=None): """ Send out a password reset email for the given user. Arguments: user (User): Django User object request (HttpRequest): Django request object preferred_email (str): Send email to this address if present, otherwise fallback to user's email address. """ site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'request': request, # Used by google_analytics_tracking_pixel # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'reset_link': '{protocol}://{site}{link}?track=pwreset'.format( protocol='https' if request.is_secure() else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('password_reset_confirm', kwargs={ 'uidb36': int_to_base36(user.id), 'token': default_token_generator.make_token(user), }), ) }) msg = PasswordReset().personalize( recipient=Recipient(user.username, preferred_email or user.email), language=get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) ace.send(msg)
def send_account_recovery_email_for_user(user, request, email=None): """ Send out a account recovery email for the given user. Arguments: user (User): Django User object request (HttpRequest): Django request object email (str): Send email to this address. """ site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'request': request, # Used by google_analytics_tracking_pixel 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'reset_link': '{protocol}://{site}{link}'.format( protocol='https' if request.is_secure() else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('account_recovery_confirm', kwargs={ 'uidb36': int_to_base36(user.id), 'token': default_token_generator.make_token(user), }), ) }) msg = AccountRecoveryMessage().personalize( recipient=Recipient(user.username, email), language=get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) ace.send(msg)
def retrieve_last_sitewide_block_completed(username): """ Completion utility From a string 'username' or object User retrieve the last course block marked as 'completed' and construct a URL :param username: str(username) or obj(User) :return: block_lms_url """ if not completion_waffle.waffle().is_enabled( completion_waffle.ENABLE_COMPLETION_TRACKING): return if not isinstance(username, User): userobj = User.objects.get(username=username) else: userobj = username latest_completions_by_course = BlockCompletion.latest_blocks_completed_all_courses( userobj) known_site_configs = [ other_site_config.get_value('course_org_filter') for other_site_config in SiteConfiguration.objects.all() if other_site_config.get_value('course_org_filter') ] current_site_configuration = get_config_value_from_site_or_settings( name='course_org_filter', site=get_current_site()) # courses.edx.org has no 'course_org_filter' # however the courses within DO, but those entries are not found in # known_site_configs, which are White Label sites # This is necessary because the WL sites and courses.edx.org # have the same AWS RDS mySQL instance candidate_course = None candidate_block_key = None latest_date = None # Go through dict, find latest for course, [modified_date, block_key] in latest_completions_by_course.items(): if not current_site_configuration: # This is a edx.org if course.org in known_site_configs: continue if not latest_date or modified_date > latest_date: candidate_course = course candidate_block_key = block_key latest_date = modified_date else: # This is a White Label site, and we should find candidates from the same site if course.org not in current_site_configuration: # Not the same White Label, or a edx.org course continue if not latest_date or modified_date > latest_date: candidate_course = course candidate_block_key = block_key latest_date = modified_date if not candidate_course: return lms_root = SiteConfiguration.get_value_for_org(candidate_course.org, "LMS_ROOT_URL", settings.LMS_ROOT_URL) try: item = modulestore().get_item(candidate_block_key, depth=1) except ItemNotFoundError: item = None if not (lms_root and item): return return u"{lms_root}/courses/{course_key}/jump_to/{location}".format( lms_root=lms_root, course_key=text_type(item.location.course_key), location=text_type(item.location), )
def create_schedule(sender, **kwargs): if not kwargs['created']: # only create schedules when enrollment records are created return current_site = get_current_site() if current_site is None: log.debug('Schedules: No current site') return enrollment = kwargs['instance'] schedule_config = ScheduleConfig.current(current_site) if (not schedule_config.create_schedules and not SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id)): log.debug( 'Schedules: Creation not enabled for this course or for this site') return delta = None if enrollment.course_overview.self_paced: global_config = DynamicUpgradeDeadlineConfiguration.current() if global_config.enabled: # Use the default from this model whether or not the feature is enabled delta = global_config.deadline_days # Check if the course has a deadline override course_config = CourseDynamicUpgradeDeadlineConfiguration.current( enrollment.course_id) if course_config.enabled: delta = course_config.deadline_days upgrade_deadline = None # This represents the first date at which the learner can access the content. This will be the latter of # either the enrollment date or the course's start date. content_availability_date = max(enrollment.created, enrollment.course_overview.start) if delta is not None: upgrade_deadline = content_availability_date + datetime.timedelta( days=delta) course_upgrade_deadline = None try: verified_mode = CourseMode.verified_mode_for_course( enrollment.course_id) except CourseMode.DoesNotExist: pass else: if verified_mode: course_upgrade_deadline = verified_mode.expiration_datetime if course_upgrade_deadline is not None and upgrade_deadline is not None: # The content availability-based deadline should never occur after the verified mode's # expiration date, if one is set. upgrade_deadline = min(upgrade_deadline, course_upgrade_deadline) Schedule.objects.create(enrollment=enrollment, start=content_availability_date, upgrade_deadline=upgrade_deadline) log.debug( 'Schedules: created a new schedule starting at %s with an upgrade deadline of %s', content_availability_date, upgrade_deadline)
def password_change_request_handler(request): """Handle password change requests originating from the account page. Uses the Account API to email the user a link to the password reset page. Note: The next step in the password reset process (confirmation) is currently handled by student.views.password_reset_confirm_wrapper, a custom wrapper around Django's password reset confirmation view. Args: request (HttpRequest) Returns: HttpResponse: 200 if the email was sent successfully HttpResponse: 400 if there is no 'email' POST parameter HttpResponse: 403 if the client has been rate limited HttpResponse: 405 if using an unsupported HTTP method Example usage: POST /account/password """ limiter = BadRequestRateLimiter() if limiter.is_rate_limit_exceeded(request): AUDIT_LOG.warning("Password reset rate limit exceeded") return HttpResponseForbidden() user = request.user # Prefer logged-in user's email email = user.email if user.is_authenticated else request.POST.get('email') if email: try: from openedx.core.djangoapps.user_api.accounts.api import request_password_change request_password_change(email, request.is_secure()) user = user if user.is_authenticated else User.objects.get( email=email) destroy_oauth_tokens(user) except UserNotFound: AUDIT_LOG.info("Invalid password reset attempt") # Increment the rate limit counter limiter.tick_bad_request_counter(request) # If enabled, send an email saying that a password reset was attempted, but that there is # no user associated with the email if configuration_helpers.get_value( 'ENABLE_PASSWORD_RESET_FAILURE_EMAIL', settings.FEATURES['ENABLE_PASSWORD_RESET_FAILURE_EMAIL']): site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'failed': True, 'request': request, # Used by google_analytics_tracking_pixel 'email_address': email, }) msg = PasswordReset().personalize( recipient=Recipient(username='', email_address=email), language=settings.LANGUAGE_CODE, user_context=message_context, ) ace.send(msg) except UserAPIInternalError as err: log.exception( 'Error occured during password change for user {email}: {error}' .format(email=email, error=err)) return HttpResponse(_( "Some error occured during password change. Please try again"), status=500) return HttpResponse(status=200) else: return HttpResponseBadRequest(_("No email address provided."))
def password_change_request_handler(request): """Handle password change requests originating from the account page. Uses the Account API to email the user a link to the password reset page. Note: The next step in the password reset process (confirmation) is currently handled by student.views.password_reset_confirm_wrapper, a custom wrapper around Django's password reset confirmation view. Args: request (HttpRequest) Returns: HttpResponse: 200 if the email was sent successfully HttpResponse: 400 if there is no 'email' POST parameter HttpResponse: 403 if the client has been rate limited HttpResponse: 405 if using an unsupported HTTP method Example usage: POST /account/password """ limiter = BadRequestRateLimiter() if limiter.is_rate_limit_exceeded(request): AUDIT_LOG.warning("Password reset rate limit exceeded") return HttpResponseForbidden() user = request.user # Prefer logged-in user's email email = user.email if user.is_authenticated else request.POST.get('email') if email: try: request_password_change(email, request.is_secure()) user = user if user.is_authenticated else User.objects.get(email=email) destroy_oauth_tokens(user) except UserNotFound: AUDIT_LOG.info("Invalid password reset attempt") # Increment the rate limit counter limiter.tick_bad_request_counter(request) # If enabled, send an email saying that a password reset was attempted, but that there is # no user associated with the email if configuration_helpers.get_value('ENABLE_PASSWORD_RESET_FAILURE_EMAIL', settings.FEATURES['ENABLE_PASSWORD_RESET_FAILURE_EMAIL']): site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'failed': True, 'request': request, # Used by google_analytics_tracking_pixel 'email_address': email, }) msg = PasswordReset().personalize( recipient=Recipient(username='', email_address=email), language=settings.LANGUAGE_CODE, user_context=message_context, ) ace.send(msg) except UserAPIInternalError as err: log.exception('Error occured during password change for user {email}: {error}' .format(email=email, error=err)) return HttpResponse(_("Some error occured during password change. Please try again"), status=500) return HttpResponse(status=200) else: return HttpResponseBadRequest(_("No email address provided."))
def retrieve_last_sitewide_block_completed(user): """ Completion utility From a string 'username' or object User retrieve the last course block marked as 'completed' and construct a URL :param user: obj(User) :return: block_lms_url """ if not completion_waffle.waffle().is_enabled(completion_waffle.ENABLE_COMPLETION_TRACKING): return latest_completions_by_course = BlockCompletion.latest_blocks_completed_all_courses(user) known_site_configs = [ other_site_config.get_value('course_org_filter') for other_site_config in SiteConfiguration.objects.all() if other_site_config.get_value('course_org_filter') ] current_site_configuration = get_config_value_from_site_or_settings( name='course_org_filter', site=get_current_site() ) # courses.edx.org has no 'course_org_filter' # however the courses within DO, but those entries are not found in # known_site_configs, which are White Label sites # This is necessary because the WL sites and courses.edx.org # have the same AWS RDS mySQL instance candidate_course = None candidate_block_key = None latest_date = None # Go through dict, find latest for course, [modified_date, block_key] in latest_completions_by_course.items(): if not current_site_configuration: # This is a edx.org if course.org in known_site_configs: continue if not latest_date or modified_date > latest_date: candidate_course = course candidate_block_key = block_key latest_date = modified_date else: # This is a White Label site, and we should find candidates from the same site if course.org not in current_site_configuration: # Not the same White Label, or a edx.org course continue if not latest_date or modified_date > latest_date: candidate_course = course candidate_block_key = block_key latest_date = modified_date if not candidate_course: return lms_root = SiteConfiguration.get_value_for_org(candidate_course.org, "LMS_ROOT_URL", settings.LMS_ROOT_URL) try: item = modulestore().get_item(candidate_block_key, depth=1) except ItemNotFoundError: item = None if not (lms_root and item): return return u"{lms_root}/courses/{course_key}/jump_to/{location}".format( lms_root=lms_root, course_key=text_type(item.location.course_key), location=text_type(item.location), )
def wharf_url(self, force=False): """Determine which site we're on, then get the Wharf URL that said site has configured.""" # The complexities of Tahoe require that we check several places # for the site configuration, which itself contains the URL # of the AVL cluster associated with this site. # # If we are in Tahoe studio, the Site object associated with this request # will not be the one used within Tahoe. To get the proper domain # we rely on the "organization", which always equals `Site.name`. # If the organization value does not return a site object, we are probably on # the LMS side. In this case, we use `get_current_site()`, which _does_ # return the incorrect site object. If all this fails, we fallback # to the DEFAULT_WHARF_URL. try: # The name of the Site object will always match self.course_id.org. # See: https://git.io/vpilS site = Site.objects.get(name=self.course_id.org) except (Site.DoesNotExist, AttributeError): # Probably on the lms side. if get_current_site: site = get_current_site() # From the request. else: site = Site.objects.all().order_by('domain').first() url = cache.get(make_cache_key(site.domain)) if url: return url # Nothing in the cache. Go find the URL. site_wharf_url = None if hasattr(site, 'configuration'): site_wharf_url = site.configuration.get_value(WHARF_URL_KEY) elif siteconfig_helpers: # Rely on edX's helper, which will fall back to the microsites app. site_wharf_url = siteconfig_helpers.get_value(WHARF_URL_KEY) urls = ( # A SiteConfig object: this is the preferred implementation. ( 'SiteConfiguration', site_wharf_url ), # A string: the currently supported implementation. ( "ENV_TOKENS[{}]".format(WHARF_URL_KEY), settings.ENV_TOKENS.get(WHARF_URL_KEY) ), # A dict: the deprecated version. ( "ENV_TOKENS['LAUNCHCONTAINER_API_CONF']", settings.ENV_TOKENS.get('LAUNCHCONTAINER_API_CONF', {}).get('default') ), ) try: url = next((x[1] for x in urls if is_valid(x[1]))) except StopIteration: raise ImproperlyConfigured("No Virtual Labs URL was found, " "please contact your site administrator.") if not url: raise AssertionError("You must set a valid url for the launchcontainer XBlock. " "URLs attempted: {}".format(urls) ) cache.set(make_cache_key(site), url, CACHE_KEY_TIMEOUT) logger.debug("XBlock-launchcontainer urls attempted: {}".format(urls)) return url
def post(self, request, **kwargs): #from student.forms import send_password_reset_email_for_user from openedx.core.djangoapps.ace_common.template_context import get_base_template_context from openedx.core.djangoapps.theming.helpers import get_current_site from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from student.message_types import PasswordReset from django.contrib.auth.tokens import default_token_generator from django.utils.http import int_to_base36 from edx_ace.recipient import Recipient from openedx.core.djangoapps.user_api.preferences.api import get_user_preference from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY from edx_ace import ace self.data = request.POST.dict() if not ('uservalue' and 'sendotptype' in self.data): return JsonResponse({ "status": 400, "message": "Please enter Valid Mobile Number or Email Address or password", }) if self.data.get('sendotptype') == "mobile": mobile = self.data.get('uservalue') user = User.objects.get(extrafields__phone=mobile) email = user.email else: email = self.data.get('uservalue') if not email: return JsonResponse({ "status": 400, "message": "Email id can not be blank", }) user = User.objects.get(email=email) try: site = get_current_site() message_context = get_base_template_context(site) message_context.update({ 'request': request, # Used by google_analytics_tracking_pixel # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'reset_link': '{protocol}://{site}{link}'.format( protocol='https', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('password_reset_confirm', kwargs={ 'uidb36': int_to_base36(user.id), 'token': default_token_generator.make_token(user), }), ) }) msg = PasswordReset().personalize( recipient=Recipient(user.username, user.email), language=get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) ace.send(msg) return JsonResponse({ "status": 200, "message": "We sent mail in you email", }) except Exception as e: return JsonResponse({ "status": 400, "message": "Something error in sending mail", "error": "err2", })