예제 #1
0
    def get(self):
        user = users.get_current_user()
        if not user:
            self.redirect(
                users.create_login_url('/modules/admin'), normalize=False)
            return
        if not self.can_view():
            login_url = users.create_login_url('/modules/admin')

            node_list = safe_dom.NodeList().append(
                safe_dom.Element('p').add_text(
                   'The current user has insufficient rights ' +
                    'to access this page.'))

            paragraph = safe_dom.Element('p').add_text('Go to the ')
            paragraph.append(safe_dom.A(href=login_url).add_text('Login page'))
            paragraph.add_text(
                ' to log in as an administrator, or go back to the ')
            paragraph.append(safe_dom.A(href='/').add_text('Home page'))
            paragraph.add_text('.')
            node_list.append(paragraph)

            self.response.write(node_list.sanitized)
            return
        super(WelcomeHandler, self).get()
예제 #2
0
def get_certificate_table_entry(handler, student, course):
    # I18N: Title of section on page showing certificates for course completion.
    title = handler.gettext('Certificate')

    if student_is_qualified(student, course):
        nl = safe_dom.NodeList()
        nl.append(
            safe_dom.A(
                CERTIFICATE_HANDLER_PATH
            ).add_text(
                # I18N: Label on control to navigate to page showing certificate
                handler.gettext('Click for certificate'))
        ).append(
            safe_dom.Text(' | ')
        ).append(
            safe_dom.A(
                CERTIFICATE_PDF_HANDLER_PATH
            ).add_text(
                # I18N: Link for a PDF.
                handler.gettext('Download PDF'))
        )
        return (title, nl)
    else:
        return (
            title,
            # I18N: Text indicating student has not yet completed a course.
            handler.gettext(
                'You have not yet met the course requirements for a '
                'certificate of completion.'))
예제 #3
0
def get_student_profile_sub_unsub_link(handler, student, unused_course):
    email = student.email
    is_unsubscribed = unsubscribe.has_unsubscribed(email)

    # I18N: Control allowing user to subscribe/unsubscribe from email invitation
    sub_unsub_title = handler.gettext('Subscribe/Unsubscribe')
    sub_unsub_message = safe_dom.NodeList()

    if is_unsubscribed:
        resubscribe_url = unsubscribe.get_resubscribe_url(handler, email)
        sub_unsub_message.append(
            safe_dom.Text(
                # I18N: Message - user has unsubscribed from email invitations.
                handler.gettext(
                    'You are currently unsubscribed from course-related emails.'
                )))
        sub_unsub_message.append(
            safe_dom.A(resubscribe_url).add_text(
                # I18N: Control allowing user to re-subscribe to email invitations.
                handler.gettext('Click here to re-subscribe.')))
    else:
        unsubscribe_url = unsubscribe.get_unsubscribe_url(handler, email)
        sub_unsub_message.append(
            safe_dom.Text(
                # I18N: Text indicating user has opted in to email invitations.
                handler.gettext(
                    'You are currently receiving course-related emails. ')))
        sub_unsub_message.append(
            safe_dom.A(unsubscribe_url).add_text(
                # I18N: Control allowing user to unsubscribe from email invitations.
                handler.gettext('Click here to unsubscribe.')))

    return (sub_unsub_title, sub_unsub_message)
예제 #4
0
    def get(self):
        action = self.request.get('action')

        if action:
            destination = '%s?action=%s' % (self.URL, action)
        else:
            destination = self.URL

        user = users.get_current_user()
        login_url = users.create_login_url(destination)
        if not user:
            self.redirect(login_url, normalize=False)
            return
        if not can_view_admin_action(action):
            node_list = safe_dom.NodeList().append(
                safe_dom.Element('p').add_text(
                   'The current user has insufficient rights ' +
                    'to access this page.'))

            paragraph = safe_dom.Element('p').add_text('Go to the ')
            paragraph.append(safe_dom.A(href=login_url).add_text('Login page'))
            paragraph.add_text(
                ' to log in as an administrator, or go back to the ')
            paragraph.append(safe_dom.A(href='/').add_text('Home page'))
            paragraph.add_text('.')
            node_list.append(paragraph)

            self.response.write(node_list.sanitized)
            self.response.set_status(403)

            return

        if action not in self._custom_get_actions:
            config.Registry.get_overrides(force_update=True)
            super(GlobalAdminHandler, self).get()
            return

        result = self._custom_get_actions[action].handler(self)
        if result is None:
            return

        # The following code handles pages for actions that do not write out
        # their responses.

        template_values = {
            'page_title': self.format_title(self.get_nav_title(action)),
        }
        if isinstance(result, dict):
            template_values.update(result)
        else:
            template_values['main_content'] = result

        self.render_page(template_values)
        return
예제 #5
0
def create_edit_button(edit_url):
    return safe_dom.A(
        href=edit_url,
        className='icon md-mode-edit row-hover',
        title='Edit',
        alt='Edit',
    )
예제 #6
0
    def add_delete_data_footer(cls, app_context):
        user = users.get_current_user()
        if not user:
            return []

        # No need for link if user has no PII in the course.  Here, we are
        # using the presence of a Student record as a marker for that, and
        # that's reasonable.  If there is no Student record, then either
        # there is no PII, or deletion is already in progress, and
        # re-requesting deletion would be pointless.
        student = models.Student.get_by_user(user)
        if not student or student.is_transient:
            return []
        if student.is_enrolled:
            link = 'student/unenroll'
        else:
            link = DataRemovalConfirmationHandler.URL.lstrip('/')

        # I18N: Gives a link on the footer of the page to permit the user
        # to delete their personal data.  This link only appears for users
        # who are currently enrolled in the course or who were enrolled
        # but still have personal data present in the course.
        text = app_context.gettext('Delete My Data')
        return [
            safe_dom.Element('li').add_child(safe_dom.A(link).add_text(text))]
예제 #7
0
def get_pipeline_link(xsrf, app_context, generator_class, job):
    ret = safe_dom.NodeList()
    if (not issubclass(generator_class, jobs.MapReduceJob) or
            # Don't give access to the pipeline details UI unless someone
            # has actively intended to provide access.  The UI allows you to
            # kill jobs, and we don't want naive users stumbling around in
            # there without adult supervision.
            not mapreduce_module.GCB_ENABLE_MAPREDUCE_DETAIL_ACCESS.value or

            # Status URL may not be available immediately after job is launched;
            # pipeline setup is done w/ 'yield', and happens a bit later.
            not job or not jobs.MapReduceJob.has_status_url(job)):
        return ret

    if job.has_finished:
        link_text = 'View completed job run details'
    else:
        link_text = 'Check status of job'

    status_url = jobs.MapReduceJob.get_status_url(
        job, app_context.get_namespace_name(),
        xsrf.create_xsrf_token(mapreduce_module.XSRF_ACTION_NAME))
    ret.append(safe_dom.Text('    '))
    ret.append(safe_dom.A(status_url, target='_blank').add_text(link_text))
    return ret
예제 #8
0
def create_launch_button(url, active=True):
    if active:
        return safe_dom.A(
            href=url,
            className='icon row-hover material-icons',
        ).add_text('open_in_new')
    else:
        return safe_dom.Element('div', className='icon inactive')
예제 #9
0
def _create_clone_button(question_id):
    return safe_dom.A(
        href='#',
        className='icon md md-content-copy',
        title='Clone',
        alt='Clone',
        data_key=str(question_id)
    )
예제 #10
0
def create_edit_button(edit_url, editable=True):
    if editable:
        return safe_dom.A(
            href=edit_url,
            className='icon md-mode-edit md row-hover',
            title='Edit',
            alt='Edit',
        )
    else:
        return safe_dom.Element('div', className='icon inactive')
예제 #11
0
def _make_welcome_form_content():
    """Add content to welcome page to get user's consent for stat collection."""
    if messaging.is_disabled():
        return None

    checkbox = safe_dom.Element(
        'input'
    ).set_attribute(
        'type', 'checkbox'
    ).set_attribute(
        'name', USAGE_REPORTING_CONSENT_CHECKBOX_NAME
    ).set_attribute(
        'value', USAGE_REPORTING_CONSENT_CHECKBOX_VALUE
    )
    if config.REPORT_ALLOWED.value or not config.is_consent_set():
        checkbox.set_attribute('checked', 'checked')

    return safe_dom.Element(
        'div'
        ).set_attribute(
            'style', 'width: 60%; margin: 0 auto; '
        ).append(
            safe_dom.Element(
                'div'
                ).set_attribute(
                    'style', 'float: left; width: 10%; '
                ).add_child(checkbox)
        ).append(
            safe_dom.Element(
                'div'
                ).set_attribute(
                    'style', 'float: left; width: 90%; text-align: left'
                ).add_text(
                    'I agree that Google may collect information about this '
                    'deployment of Course Builder to help improve Google\'s '
                    'products and services and for research purposes.  '
                    'Google will maintain this data in acccordance with '
                ).add_child(
                    safe_dom.A(
                        'http://www.google.com/policies/privacy/'
                        ).add_text(
                            'Google\'s privacy policy'
                        )
                ).add_text(
                    ' and will not associate the data it collects with '
                    'this course or a user.  Your response to this question '
                    'will be sent to Google.'
                )
        ).append(
            safe_dom.Element(
                'div'
                ).set_attribute(
                    'style', 'clear: both; '
                )
        )
예제 #12
0
def _list_labels(handler):
    """Prepare a list of labels for use on the Assets page."""
    output = safe_dom.NodeList()
    if not handler.app_context.is_editable_fs():
        return output

    output.append(
        safe_dom.A('dashboard?action=add_label',
                   className='gcb-button gcb-pull-right'
                  ).add_text('Add Label')
        ).append(
            safe_dom.Element(
                'div', style='clear: both; padding-top: 2px;'
            )
        )
    output.append(
            safe_dom.Element('h3').add_text('Labels')
    )
    labels = models.LabelDAO.get_all()
    if labels:
        all_labels_ul = safe_dom.Element('ul')
        output.append(all_labels_ul)
        for label_type in sorted(
            models.LabelDTO.LABEL_TYPES,
            lambda a, b: cmp(a.menu_order, b.menu_order)):

            type_li = safe_dom.Element('li').add_text(label_type.title)
            all_labels_ul.add_child(type_li)
            labels_of_type_ul = safe_dom.Element('ul')
            type_li.add_child(labels_of_type_ul)
            for label in sorted(
                labels, lambda a, b: cmp(a.title, b.title)):
                if label.type == label_type.type:
                    li = safe_dom.Element('li')
                    labels_of_type_ul.add_child(li)
                    li.add_text(
                        label.title
                    ).add_attribute(
                        title='id: %s, type: %s' % (label.id, label_type))
                    if label_type not in (
                        models.LabelDTO.SYSTEM_EDITABLE_LABEL_TYPES):

                        li.add_child(
                            dashboard_utils.create_edit_button(
                                'dashboard?action=edit_label&key=%s' %
                                label.id,
                                ).add_attribute(
                                    id='label_%s' % label.title))
    else:
        output.append(safe_dom.Element('blockquote').add_text('< none >'))
    return output
예제 #13
0
 def _add_pipeline_link(self, job, template_values, message):
     status_url = jobs.MapReduceJob.get_status_url(
         # app_context is forcibly injected into instances from
         # modules.dashboard.get_analytics()
         # pylint: disable=undefined-variable
         job,
         self.app_context.get_namespace_name(),
         utils.XsrfTokenManager.create_xsrf_token(
             mapreduce_module.XSRF_ACTION_NAME))
     update_message = safe_dom.NodeList()
     update_message.append(template_values['update_message'])
     update_message.append(safe_dom.Text('    '))
     update_message.append(
         safe_dom.A(status_url, target='_blank').add_text(message))
     template_values['update_message'] = update_message
예제 #14
0
def get_certificate_table_entry(unused_handler, student, course):
    # I18N: Title of section on page showing certificates for course completion.
    title = gettext.gettext('Certificate')

    if student_is_qualified(student, course):
        link = safe_dom.A(CERTIFICATE_HANDLER_PATH).add_text(
            # I18N: Label on control to navigate to page showing certificate.
            gettext.gettext('Click for certificate'))
        return (title, link)
    else:
        return (
            title,
            # I18N: Text indicating student has not yet completed a course.
            gettext.gettext(
                'You have not yet met the course requirements for a '
                'certificate of completion.'))
예제 #15
0
    def get_course_picker(self, destination=None):
        destination = destination or '/dashboard'
        action = self.request.get('action') or self._default_get_action

        # disable picker if we are on the well known page; we dont want picked
        # on pages where edits or creation of new object can get triggered
        safe_action = action and action in [
            a for a, _ in self.get_nav_mappings()
        ] + ['admin']

        tab = self.request.get('tab')
        if action in self.get_actions:
            tab_group = tabs.Registry.get_tab_group(action)
            if tab_group and tab in tab_group:
                tab = '&tab=%s' % tab
            else:
                tab = ''
            destination = '%s?action=%s%s' % (destination, action, tab)

        current_course = sites.get_course_for_current_request()
        options = []
        for course in sorted(sites.get_all_courses()):
            with Namespace(course.namespace):
                if self.current_user_has_access(course):
                    url = (course.canonicalize_url(destination)
                           if safe_action else 'javascript:void(0)')
                    title = '%s (%s)' % (course.get_title(), course.get_slug())
                    option = safe_dom.Element('li')
                    link = safe_dom.A(url).add_text(title)
                    if current_course == course:
                        link.set_attribute('class', 'selected')
                    option.add_child(link)
                    options.append((course.get_title(), option))

        picker_class_name = 'hidden'
        if not safe_action:
            picker_class_name += ' disabled'

        picker = safe_dom.Element('ol',
                                  id='gcb-course-picker-menu',
                                  className=picker_class_name)

        for title, option in sorted(options, key=lambda item: item[0].lower()):
            picker.append(option)
        return picker
예제 #16
0
    def _get_top_nav(self, in_action, in_tab):
        nav_bars = []

        nav = safe_dom.NodeList()

        nav.append(
            safe_dom.Element('a', href=self.URL,
                             className='selected').add_text('Site Admin'))

        nav.append(
            safe_dom.Element(
                'a',
                href='https://code.google.com/p/course-builder/wiki/Dashboard',
                target='_blank').add_text('Help'))

        nav.append(
            safe_dom.Element(
                'a',
                href=(
                    'https://groups.google.com/forum/?fromgroups#!categories/'
                    'course-builder-forum/general-troubleshooting'),
                target='_blank').add_text('Support'))
        nav_bars.append(nav)

        tab_name = in_tab or self.request.get('tab') or self.DEFAULT_TAB
        sub_nav = safe_dom.NodeList()
        tab_group = tabs.Registry.get_tab_group(self.default_action)
        for tab in tab_group:
            if tab.contents:
                href = '%s?tab=%s' % (self.LINK_URL, tab.name)
            else:
                href = tab.href
            target = tab.target or '_self'
            sub_nav.append(
                safe_dom.A(
                    href,
                    className=('selected' if tab.name == tab_name else ''),
                    target=target).add_text(tab.title))
        nav_bars.append(sub_nav)

        return nav_bars
예제 #17
0
def get_student_profile_invitation_link(handler, unused_student,
                                        unused_course):
    env = handler.app_context.get_environ()
    email_env = env['course'].get(INVITATION_EMAIL_KEY, {})
    if not email_env.get('enabled'):
        return (None, None)

    # I18N: Title encouraging user to invite friends to join a course
    invitation_title = handler.gettext('Invite Friends')
    if InvitationEmail.is_available(handler):
        invitation_link = safe_dom.A(
            InvitationHandler.URL
            # I18N: Label on control asking user to invite friends to join.
        ).add_text(
            handler.gettext('Click to send invitations to family and friends'))
    else:
        # I18N: Inviting friends to join a course is not currently enabled.
        invitation_link = safe_dom.Text(
            handler.gettext('Invitations not currently available'))

    return (invitation_title, invitation_link)
예제 #18
0
MODULE_NAME = 'Map/Reduce'
XSRF_ACTION_NAME = 'view-mapreduce-ui'
MAX_MAPREDUCE_METADATA_RETENTION_DAYS = 3

GCB_ENABLE_MAPREDUCE_DETAIL_ACCESS = ConfigProperty(
    'gcb_enable_mapreduce_detail_access',
    bool,
    safe_dom.NodeList().append(
        safe_dom.Element('p').add_text("""
Enables access to status pages showing details of progress for individual
map/reduce jobs as they run.  These pages can be used to cancel jobs or
sub-jobs.  This is a benefit if you have launched a huge job that is
consuming too many resources, but a hazard for naive users.""")).append(
            safe_dom.Element('p').add_child(
                safe_dom.A('/mapreduce/ui/pipeline/list',
                           target='_blank').add_text("""
See an example page (with this control enabled)"""))),
    False,
    multiline=False,
    validator=None)


def authorization_wrapper(self, *args, **kwargs):
    # developers.google.com/appengine/docs/python/taskqueue/overview-push
    # promises that this header cannot be set by external callers.  If this
    # is present, we can be certain that the request is internal and from
    # the task queue worker.  (This is belt-and-suspenders with the admin
    # restriction on /mapreduce/worker*)
    if 'X-AppEngine-TaskName' not in self.request.headers:
        self.response.out.write('Forbidden')
        self.response.set_status(403)
예제 #19
0
    def _get_top_nav(self, in_action, in_tab):
        current_action = in_action or self.request.get(
            'action') or self.default_action
        nav_bars = []
        nav = safe_dom.NodeList()
        for action, title in self.get_nav_mappings():
            if not self.can_view(action):
                continue
            class_name = 'selected' if action == current_action else ''
            action_href = 'dashboard?action=%s' % action
            nav.append(
                safe_dom.Element('a', href=action_href,
                                 className=class_name).add_text(title))

        if roles.Roles.is_super_admin():
            nav.append(
                safe_dom.Element(
                    'a',
                    href='admin?action=admin',
                    className=('selected' if current_action == 'admin' else
                               '')).add_text('Site Admin'))

        nav.append(
            safe_dom.Element(
                'a',
                href='https://code.google.com/p/course-builder/wiki/Dashboard',
                target='_blank').add_text('Help'))

        nav.append(
            safe_dom.Element(
                'a',
                href=(
                    'https://groups.google.com/forum/?fromgroups#!categories/'
                    'course-builder-forum/general-troubleshooting'),
                target='_blank').add_text('Support'))
        nav_bars.append(nav)

        tab_group = tabs.Registry.get_tab_group(current_action)
        if tab_group:
            if current_action == 'assets':
                exclude_tabs = []
                course = self.get_course()
                if courses.has_only_new_style_assessments(course):
                    exclude_tabs.append('Assessments')
                if courses.has_only_new_style_activities(course):
                    exclude_tabs.append('Activities')
                    tab_group = [
                        t for t in tab_group if t.title not in exclude_tabs
                    ]
            tab_name = (in_tab or self.request.get('tab')
                        or self.default_subtab_action[current_action]
                        or tab_group[0].name)
            sub_nav = safe_dom.NodeList()
            for tab in tab_group:
                href = tab.href or 'dashboard?action=%s&tab=%s' % (
                    current_action, tab.name)
                target = tab.target or '_self'
                sub_nav.append(
                    safe_dom.A(
                        href,
                        className=('selected' if tab.name == tab_name else ''),
                        target=target).add_text(tab.title))
            nav_bars.append(sub_nav)
        return nav_bars
예제 #20
0
def _list_and_format_file_list(
    handler, title, subfolder, tab_name,
    links=False, upload=False, prefix=None, caption_if_empty='< none >',
    edit_url_template=None, merge_local_files=False, sub_title=None,
    all_paths=None):
    """Walks files in folders and renders their names in a section."""

    # keep a list of files without merging
    unmerged_files = {}
    if merge_local_files:
        unmerged_files = dashboard_utils.list_files(
            handler, subfolder, merge_local_files=False, all_paths=all_paths)

    items = safe_dom.NodeList()
    count = 0
    for filename in dashboard_utils.list_files(
            handler, subfolder, merge_local_files=merge_local_files,
            all_paths=all_paths):
        if prefix and not filename.startswith(prefix):
            continue

        # make a <li> item
        li = safe_dom.Element('li')
        if links:
            url = urllib.quote(filename)
            li.add_child(safe_dom.Element(
                'a', href=url).add_text(filename))
        else:
            li.add_text(filename)

        # add actions if available
        if (edit_url_template and
            handler.app_context.fs.impl.is_read_write()):

            li.add_child(safe_dom.Entity('&nbsp;'))
            edit_url = edit_url_template % (
                tab_name, urllib.quote(filename))
            # show [overridden] + edit button if override exists
            if (filename in unmerged_files) or (not merge_local_files):
                li.add_text('[Overridden]').add_child(
                    dashboard_utils.create_edit_button(edit_url))
            # show an [override] link otherwise
            else:
                li.add_child(safe_dom.A(edit_url).add_text('[Override]'))

        count += 1
        items.append(li)

    output = safe_dom.NodeList()

    if handler.app_context.is_editable_fs() and upload:
        output.append(
            safe_dom.Element(
                'a', className='gcb-button gcb-pull-right',
                href='dashboard?%s' % urllib.urlencode(
                    {'action': 'manage_asset',
                     'tab': tab_name,
                     'key': subfolder})
            ).add_text(
                'Upload to ' + subfolder.lstrip('/').rstrip('/'))
        ).append(
            safe_dom.Element(
                'div', style='clear: both; padding-top: 2px;'
            )
        )
    if title:
        h3 = safe_dom.Element('h3')
        if count:
            h3.add_text('%s (%s)' % (title, count))
        else:
            h3.add_text(title)
        output.append(h3)
    if sub_title:
        output.append(safe_dom.Element('blockquote').add_text(sub_title))
    if items:
        output.append(safe_dom.Element('ol').add_children(items))
    else:
        if caption_if_empty:
            output.append(
                safe_dom.Element('blockquote').add_text(caption_if_empty))
    return output