Files
edx-platform/lms/djangoapps/courseware/access_utils.py
Kyle McCormick 151bd13666 Use full names for common.djangoapps imports; warn when using old style (#25477)
* Generate common/djangoapps import shims for LMS
* Generate common/djangoapps import shims for Studio
* Stop appending project root to sys.path
* Stop appending common/djangoapps to sys.path
* Import from common.djangoapps.course_action_state instead of course_action_state
* Import from common.djangoapps.course_modes instead of course_modes
* Import from common.djangoapps.database_fixups instead of database_fixups
* Import from common.djangoapps.edxmako instead of edxmako
* Import from common.djangoapps.entitlements instead of entitlements
* Import from common.djangoapps.pipline_mako instead of pipeline_mako
* Import from common.djangoapps.static_replace instead of static_replace
* Import from common.djangoapps.student instead of student
* Import from common.djangoapps.terrain instead of terrain
* Import from common.djangoapps.third_party_auth instead of third_party_auth
* Import from common.djangoapps.track instead of track
* Import from common.djangoapps.util instead of util
* Import from common.djangoapps.xblock_django instead of xblock_django
* Add empty common/djangoapps/__init__.py to fix pytest collection
* Fix pylint formatting violations
* Exclude import_shims/ directory tree from linting
2020-11-10 07:02:01 -05:00

170 lines
5.3 KiB
Python

"""
Simple utility functions for computing access.
It allows us to share code between access.py and block transformers.
"""
from datetime import datetime, timedelta
from logging import getLogger
from django.conf import settings
from django.utils.translation import ugettext as _
from pytz import UTC
from lms.djangoapps.courseware.access_response import (
AccessResponse,
StartDateError,
EnrollmentRequiredAccessError,
AuthenticationRequiredAccessError,
)
from lms.djangoapps.courseware.masquerade import get_course_masquerade, is_masquerading_as_student
from openedx.core.djangoapps.util.user_messages import PageLevelMessages
from openedx.core.djangolib.markup import HTML
from openedx.features.course_experience import (
COURSE_PRE_START_ACCESS_FLAG,
COURSE_ENABLE_UNENROLLED_ACCESS_FLAG,
)
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.roles import CourseBetaTesterRole
from xmodule.util.xmodule_django import get_current_request_hostname
from xmodule.course_module import COURSE_VISIBILITY_PUBLIC
DEBUG_ACCESS = False
log = getLogger(__name__)
ACCESS_GRANTED = AccessResponse(True)
ACCESS_DENIED = AccessResponse(False)
def debug(*args, **kwargs):
"""
Helper function for local debugging.
"""
# to avoid overly verbose output, this is off by default
if DEBUG_ACCESS:
log.debug(*args, **kwargs)
def adjust_start_date(user, days_early_for_beta, start, course_key):
"""
If user is in a beta test group, adjust the start date by the appropriate number of
days.
Returns:
A datetime. Either the same as start, or earlier for beta testers.
"""
if days_early_for_beta is None:
# bail early if no beta testing is set up
return start
if CourseBetaTesterRole(course_key).has_user(user):
debug(u"Adjust start time: user in beta role for %s", course_key)
delta = timedelta(days_early_for_beta)
effective = start - delta
return effective
return start
def check_start_date(user, days_early_for_beta, start, course_key, display_error_to_user=True, now=None):
"""
Verifies whether the given user is allowed access given the
start date and the Beta offset for the given course.
Arguments:
display_error_to_user: If True, display this error to users in the UI.
Returns:
AccessResponse: Either ACCESS_GRANTED or StartDateError.
"""
start_dates_disabled = settings.FEATURES['DISABLE_START_DATES']
masquerading_as_student = is_masquerading_as_student(user, course_key)
if start_dates_disabled and not masquerading_as_student:
return ACCESS_GRANTED
else:
if start is None or in_preview_mode() or get_course_masquerade(user, course_key):
return ACCESS_GRANTED
if now is None:
now = datetime.now(UTC)
effective_start = adjust_start_date(user, days_early_for_beta, start, course_key)
if now > effective_start:
return ACCESS_GRANTED
return StartDateError(start, display_error_to_user=display_error_to_user)
def in_preview_mode():
"""
Returns whether the user is in preview mode or not.
"""
hostname = get_current_request_hostname()
preview_lms_base = settings.FEATURES.get('PREVIEW_LMS_BASE', None)
return bool(preview_lms_base and hostname and hostname.split(':')[0] == preview_lms_base.split(':')[0])
def check_course_open_for_learner(user, course):
"""
Check if the course is open for learners based on the start date.
Returns:
AccessResponse: Either ACCESS_GRANTED or StartDateError.
"""
if COURSE_PRE_START_ACCESS_FLAG.is_enabled():
return ACCESS_GRANTED
return check_start_date(user, course.days_early_for_beta, course.start, course.id)
def check_enrollment(user, course):
"""
Check if the course requires a learner to be enrolled for access.
Returns:
AccessResponse: Either ACCESS_GRANTED or EnrollmentRequiredAccessError.
"""
if check_public_access(course, [COURSE_VISIBILITY_PUBLIC]):
return ACCESS_GRANTED
if CourseEnrollment.is_enrolled(user, course.id):
return ACCESS_GRANTED
return EnrollmentRequiredAccessError()
def check_authentication(user, course):
"""
Grants access if the user is authenticated, or if the course allows public access.
Returns:
AccessResponse: Either ACCESS_GRANTED or AuthenticationRequiredAccessError
"""
if user.is_authenticated:
return ACCESS_GRANTED
if check_public_access(course, [COURSE_VISIBILITY_PUBLIC]):
return ACCESS_GRANTED
return AuthenticationRequiredAccessError()
def check_public_access(course, visibilities):
"""
This checks if the unenrolled access waffle flag for the course is set
and the course visibility matches any of the input visibilities.
The "visibilities" argument is one of these constants from xmodule.course_module:
- COURSE_VISIBILITY_PRIVATE
- COURSE_VISIBILITY_PUBLIC
- COURSE_VISIBILITY_PUBLIC_OUTLINE
Returns:
AccessResponse: Either ACCESS_GRANTED or ACCESS_DENIED.
"""
unenrolled_access_flag = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(course.id)
allow_access = unenrolled_access_flag and course.course_visibility in visibilities
if allow_access:
return ACCESS_GRANTED
return ACCESS_DENIED