utils.py 7.74 KB
Newer Older
1
# pylint: disable=E1103, E1101
David Baumgold committed
2

3
import copy
cahrens committed
4
import logging
cahrens committed
5
import re
6 7

from django.conf import settings
David Baumgold committed
8
from django.utils.translation import ugettext as _
9
from django.core.urlresolvers import reverse
10 11 12

from xmodule.contentstore.content import StaticContent
from xmodule.contentstore.django import contentstore
13
from xmodule.modulestore.django import modulestore
14
from xmodule.modulestore.exceptions import ItemNotFoundError
15
from xmodule.modulestore.locations import SlashSeparatedCourseKey, Location
16
from xmodule.modulestore.store_utilities import delete_course
17 18
from xmodule.modulestore.draft import DIRECT_ONLY_CATEGORIES
from student.roles import CourseInstructorRole, CourseStaffRole
19

cahrens committed
20 21

log = logging.getLogger(__name__)
22

23
# In order to instantiate an open ended tab automatically, need to have this data
David Baumgold committed
24 25
OPEN_ENDED_PANEL = {"name": _("Open Ended Panel"), "type": "open_ended"}
NOTES_PANEL = {"name": _("My Notes"), "type": "notes"}
26
EXTRA_TAB_PANELS = dict([(p['type'], p) for p in [OPEN_ENDED_PANEL, NOTES_PANEL]])
Calen Pennington committed
27

28

29 30 31 32 33 34 35 36
def delete_course_and_groups(course_id, commit=False):
    """
    This deletes the courseware associated with a course_id as well as cleaning update_item
    the various user table stuff (groups, permissions, etc.)
    """
    module_store = modulestore('direct')
    content_store = contentstore()

37
    module_store.ignore_write_events_on_courses.add(course_id)
38

39
    if delete_course(module_store, content_store, course_id, commit):
40 41 42 43 44

        print 'removing User permissions from course....'
        # in the django layer, we need to remove all the user permissions groups associated with this course
        if commit:
            try:
45
                staff_role = CourseStaffRole(course_id)
46
                staff_role.remove_users(*staff_role.users_with_role())
47
                instructor_role = CourseInstructorRole(course_id)
48
                instructor_role.remove_users(*instructor_role.users_with_role())
49
            except Exception as err:
50
                log.error("Error in deleting course groups for {0}: {1}".format(course_id, err))
51

52

53
def get_modulestore(category_or_location):
Don Mitchell committed
54 55 56
    """
    Returns the correct modulestore to use for modifying the specified location
    """
57 58
    if isinstance(category_or_location, Location):
        category_or_location = category_or_location.category
Calen Pennington committed
59

60
    if category_or_location in DIRECT_ONLY_CATEGORIES:
Don Mitchell committed
61 62 63
        return modulestore('direct')
    else:
        return modulestore()
64

Calen Pennington committed
65

66
def get_lms_link_for_item(location, preview=False):
67 68 69 70 71 72
    """
    Returns an LMS link to the course with a jump_to to the provided location.

    :param location: the location to jump to
    :param preview: True if the preview version of LMS should be returned. Default value is false.
    """
73 74 75 76 77 78 79
    assert(isinstance(location, Location))

    if settings.LMS_BASE is None:
        return None

    if preview:
        lms_base = settings.FEATURES.get('PREVIEW_LMS_BASE')
80
    else:
81
        lms_base = settings.LMS_BASE
82

83 84 85 86 87
    return u"//{lms_base}/courses/{course_id}/jump_to/{location}".format(
        lms_base=lms_base,
        course_id=location.course_key.to_deprecated_string(),
        location=location.to_deprecated_string(),
    )
88

Calen Pennington committed
89

90
def get_lms_link_for_about_page(course_id):
cahrens committed
91 92 93
    """
    Returns the url to the course about page from the location tuple.
    """
94 95 96

    assert(isinstance(course_id, SlashSeparatedCourseKey))

97
    if settings.FEATURES.get('ENABLE_MKTG_SITE', False):
cahrens committed
98 99
        if not hasattr(settings, 'MKTG_URLS'):
            log.exception("ENABLE_MKTG_SITE is True, but MKTG_URLS is not defined.")
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
            return None

        marketing_urls = settings.MKTG_URLS

        # Root will be "https://www.edx.org". The complete URL will still not be exactly correct,
        # but redirects exist from www.edx.org to get to the Drupal course about page URL.
        about_base = marketing_urls.get('ROOT', None)

        if about_base is None:
            log.exception('There is no ROOT defined in MKTG_URLS')
            return None

        # Strip off https:// (or http://) to be consistent with the formatting of LMS_BASE.
        about_base = re.sub(r"^https?://", "", about_base)

115 116 117
    elif settings.LMS_BASE is not None:
        about_base = settings.LMS_BASE
    else:
118
        return None
cahrens committed
119

120 121 122 123
    return u"//{about_base_url}/courses/{course_id}/about".format(
        about_base_url=about_base,
        course_id=course_id.to_deprecated_string()
    )
cahrens committed
124

Calen Pennington committed
125

126 127
def course_image_url(course):
    """Returns the image url for the course."""
128 129
    loc = StaticContent.compute_location(course.location.course_key, course.course_image)
    path = loc.to_deprecated_string()
130 131 132
    return path


133
class PublishState(object):
134 135 136 137 138
    """
    The publish state for a given xblock-- either 'draft', 'private', or 'public'.

    Currently in CMS, an xblock can only be in 'draft' or 'private' if it is at or below the Unit level.
    """
139 140 141 142 143
    draft = 'draft'
    private = 'private'
    public = 'public'


144
def compute_publish_state(xblock):
145
    """
146
    Returns whether this xblock is 'draft', 'public', or 'private'.
147 148 149 150

    'draft' content is in the process of being edited, but still has a previous
        version visible in the LMS
    'public' content is locked and visible in the LMS
151
    'private' content is editable and not visible in the LMS
152 153
    """

154
    if getattr(xblock, 'is_draft', False):
155
        try:
156 157
            modulestore('direct').get_item(xblock.location)
            return PublishState.draft
158
        except ItemNotFoundError:
159
            return PublishState.private
160
    else:
161
        return PublishState.public
Lyla Fischer committed
162 163


164
def add_extra_panel_tab(tab_type, course):
Vik Paruchuri committed
165
    """
166 167
    Used to add the panel tab to a course if it does not exist.
    @param tab_type: A string representing the tab type.
Vik Paruchuri committed
168 169 170
    @param course: A course object from the modulestore.
    @return: Boolean indicating whether or not a tab was added and a list of tabs for the course.
    """
Don Mitchell committed
171
    # Copy course tabs
172 173
    course_tabs = copy.copy(course.tabs)
    changed = False
Don Mitchell committed
174
    # Check to see if open ended panel is defined in the course
175

176 177
    tab_panel = EXTRA_TAB_PANELS.get(tab_type)
    if tab_panel not in course_tabs:
Don Mitchell committed
178
        # Add panel to the tabs if it is not defined
179
        course_tabs.append(tab_panel)
180 181
        changed = True
    return changed, course_tabs
182

Chris Dodge committed
183

184
def remove_extra_panel_tab(tab_type, course):
185
    """
186 187
    Used to remove the panel tab from a course if it exists.
    @param tab_type: A string representing the tab type.
188 189 190
    @param course: A course object from the modulestore.
    @return: Boolean indicating whether or not a tab was added and a list of tabs for the course.
    """
Don Mitchell committed
191
    # Copy course tabs
192 193
    course_tabs = copy.copy(course.tabs)
    changed = False
Don Mitchell committed
194
    # Check to see if open ended panel is defined in the course
195 196 197

    tab_panel = EXTRA_TAB_PANELS.get(tab_type)
    if tab_panel in course_tabs:
Don Mitchell committed
198
        # Add panel to the tabs if it is not defined
199
        course_tabs = [ct for ct in course_tabs if ct != tab_panel]
200 201
        changed = True
    return changed, course_tabs
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226


def reverse_url(handler_name, key_name=None, key_value=None, kwargs=None):
    """
    Creates the URL for the given handler.
    The optional key_name and key_value are passed in as kwargs to the handler.
    """
    kwargs_for_reverse = {key_name: unicode(key_value)} if key_name else None
    if kwargs:
        kwargs_for_reverse.update(kwargs)
    return reverse('contentstore.views.' + handler_name, kwargs=kwargs_for_reverse)


def reverse_course_url(handler_name, course_key, kwargs=None):
    """
    Creates the URL for handlers that use course_keys as URL parameters.
    """
    return reverse_url(handler_name, 'course_key_string', course_key, kwargs)


def reverse_usage_url(handler_name, usage_key, kwargs=None):
    """
    Creates the URL for handlers that use usage_keys as URL parameters.
    """
    return reverse_url(handler_name, 'usage_key_string', usage_key, kwargs)