startup.py 6.55 KB
Newer Older
1 2 3
"""
Module for code that should run during LMS startup
"""
Calen Pennington committed
4

5 6
# pylint: disable=unused-argument

7 8 9
from django.conf import settings

# Force settings to run so that the python path is modified
10
settings.INSTALLED_APPS  # pylint: disable=pointless-statement
11

12
from openedx.core.lib.django_startup import autostartup
13
import edxmako
14
import logging
15
from monkey_patch import django_utils_translation
16
import analytics
17 18
from util import keyword_substitution

19 20

log = logging.getLogger(__name__)
21

22

23 24 25 26
def run():
    """
    Executed during django startup
    """
27 28
    django_utils_translation.patch()

29
    autostartup()
30

31 32
    add_mimetypes()

33 34 35
    if settings.FEATURES.get('USE_CUSTOM_THEME', False):
        enable_theme()

36 37 38
    if settings.FEATURES.get('USE_MICROSITES', False):
        enable_microsites()

39 40 41
    if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH', False):
        enable_third_party_auth()

42
    # Initialize Segment.io analytics module. Flushes first time a message is received and
43
    # every 50 messages thereafter, or if 10 seconds have passed since last flush
44
    if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
45 46
        analytics.init(settings.SEGMENT_IO_LMS_KEY, flush_at=50)

47 48 49 50 51 52
    # Monkey patch the keyword function map
    if keyword_substitution.keyword_function_map_is_empty():
        keyword_substitution.add_keyword_function_map(get_keyword_function_map())
        # Once keyword function map is set, make update function do nothing
        keyword_substitution.add_keyword_function_map = lambda x: None

53

54 55 56
def add_mimetypes():
    """
    Add extra mimetypes. Used in xblock_resource.
57 58

    If you add a mimetype here, be sure to also add it in cms/startup.py.
59 60 61 62 63 64 65 66 67
    """
    import mimetypes

    mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
    mimetypes.add_type('application/x-font-opentype', '.otf')
    mimetypes.add_type('application/x-font-ttf', '.ttf')
    mimetypes.add_type('application/font-woff', '.woff')


68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
def enable_theme():
    """
    Enable the settings for a custom theme, whose files should be stored
    in ENV_ROOT/themes/THEME_NAME (e.g., edx_all/themes/stanford).
    """
    # Workaround for setting THEME_NAME to an empty
    # string which is the default due to this ansible
    # bug: https://github.com/ansible/ansible/issues/4812
    if settings.THEME_NAME == "":
        settings.THEME_NAME = None
        return

    assert settings.FEATURES['USE_CUSTOM_THEME']
    settings.FAVICON_PATH = 'themes/{name}/images/favicon.ico'.format(
        name=settings.THEME_NAME
    )

    # Calculate the location of the theme's files
    theme_root = settings.ENV_ROOT / "themes" / settings.THEME_NAME

    # Include the theme's templates in the template search paths
89
    settings.TEMPLATE_DIRS.insert(0, theme_root / 'templates')
90
    edxmako.paths.add_lookup('main', theme_root / 'templates', prepend=True)
91 92 93 94 95 96

    # Namespace the theme's static files to 'themes/<theme_name>' to
    # avoid collisions with default edX static files
    settings.STATICFILES_DIRS.append(
        (u'themes/{}'.format(settings.THEME_NAME), theme_root / 'static')
    )
97

98 99 100
    # Include theme locale path for django translations lookup
    settings.LOCALE_PATHS = (theme_root / 'conf/locale',) + settings.LOCALE_PATHS

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137

def enable_microsites():
    """
    Enable the use of microsites, which are websites that allow
    for subdomains for the edX platform, e.g. foo.edx.org
    """

    microsites_root = settings.MICROSITE_ROOT_DIR
    microsite_config_dict = settings.MICROSITE_CONFIGURATION

    for ms_name, ms_config in microsite_config_dict.items():
        # Calculate the location of the microsite's files
        ms_root = microsites_root / ms_name
        ms_config = microsite_config_dict[ms_name]

        # pull in configuration information from each
        # microsite root

        if ms_root.isdir():
            # store the path on disk for later use
            ms_config['microsite_root'] = ms_root

            template_dir = ms_root / 'templates'
            ms_config['template_dir'] = template_dir

            ms_config['microsite_name'] = ms_name
            log.info('Loading microsite {0}'.format(ms_root))
        else:
            # not sure if we have application logging at this stage of
            # startup
            log.error('Error loading microsite {0}. Directory does not exist'.format(ms_root))
            # remove from our configuration as it is not valid
            del microsite_config_dict[ms_name]

    # if we have any valid microsites defined, let's wire in the Mako and STATIC_FILES search paths
    if microsite_config_dict:
        settings.TEMPLATE_DIRS.append(microsites_root)
138
        edxmako.paths.add_lookup('main', microsites_root)
139 140

        settings.STATICFILES_DIRS.insert(0, microsites_root)
141 142 143 144 145 146 147 148 149 150 151


def enable_third_party_auth():
    """
    Enable the use of third_party_auth, which allows users to sign in to edX
    using other identity providers. For configuration details, see
    common/djangoapps/third_party_auth/settings.py.
    """

    from third_party_auth import settings as auth_settings
    auth_settings.apply_settings(settings.THIRD_PARTY_AUTH, settings)
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199


def get_keyword_function_map():
    """
    Define the mapping of keywords and filtering functions

    The functions are used to filter html, text and email strings
    before rendering them.

    The generated map will be monkey-patched onto the keyword_substitution
    module so that it persists along with the running server.

    Each function must take: user & course as parameters
    """

    from student.models import anonymous_id_for_user
    from util.date_utils import get_default_time_display

    def user_id_sub(user, course):
        """
        Gives the anonymous id for the given user

        For compatibility with the existing anon_ids, return anon_id without course_id
        """
        return anonymous_id_for_user(user, None)

    def user_fullname_sub(user, course=None):
        """ Returns the given user's name """
        return user.profile.name

    def course_display_name_sub(user, course):
        """ Returns the course's display name """
        return course.display_name

    def course_end_date_sub(user, course):
        """ Returns the course end date in the default display """
        return get_default_time_display(course.end)

    # Define keyword -> function map
    # Take care that none of these functions return %% encoded keywords
    kf_map = {
        '%%USER_ID%%': user_id_sub,
        '%%USER_FULLNAME%%': user_fullname_sub,
        '%%COURSE_DISPLAY_NAME%%': course_display_name_sub,
        '%%COURSE_END_DATE%%': course_end_date_sub
    }

    return kf_map