예제 #1
0
from google.appengine.ext import db

# Module registration
custom_module = None
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')
예제 #2
0
 def test_append_node_list(self):
     """NodeList should support appending both Nodes and NodeLists."""
     node_list = safe_dom.NodeList().append(safe_dom.NodeList().append(
         MockNode('a')).append(MockNode('b'))).append(MockNode('c'))
     self.assertEqual('abc', node_list.__str__())
예제 #3
0
 def test_insert_node_list(self):
     """NodeList should support inserting Nodes."""
     node_list = safe_dom.NodeList()
     node_list.append(MockNode('a')).append(MockNode('c'))
     node_list.insert(1, MockNode('b'))
     self.assertEqual('abc', node_list.__str__())
예제 #4
0
 def test_list(self):
     """NodeList should escape all its members."""
     node_list = safe_dom.NodeList()
     node_list.append(MockNode('a')).append(MockNode('b'))
     self.assertEqual('ab', node_list.sanitized)
예제 #5
0
 def test_len(self):
     """NodeList should support len."""
     node_list = safe_dom.NodeList().append(MockNode('a')).append(
         MockNode('b'))
     self.assertEqual(2, len(node_list))
예제 #6
0
    def get_courses(self):
        """Shows a list of all courses available on this site."""
        template_values = {}
        template_values['page_title'] = self.format_title('Courses')
        template_values['page_description'] = messages.COURSES_DESCRIPTION

        content = safe_dom.NodeList()
        content.append(
            safe_dom.Element(
                'a',
                id='add_course',
                className='btn btn-primary pull-right',
                role='button',
                href='admin?action=add_course').add_text('Add Course')).append(
                    safe_dom.Element(
                        'div', style='clear: both; padding-top: 2px;')).append(
                            safe_dom.Element('h3').add_text('All Courses'))
        table = safe_dom.Element('table')
        content.append(table)
        table.add_child(
            safe_dom.Element('tr').add_child(
                safe_dom.Element('th').add_text('Course Title')).add_child(
                    safe_dom.Element('th').add_text('Context Path')).add_child(
                        safe_dom.Element('th').add_text('Content Location')).
            add_child(
                safe_dom.Element('th').add_text('Student Data Location')))
        courses = sites.get_all_courses()
        count = 0
        for course in courses:
            count += 1
            error = safe_dom.Text('')
            slug = course.get_slug()
            try:
                name = course.get_title()
            except Exception as e:  # pylint: disable-msg=broad-except
                name = 'UNKNOWN COURSE'
                error = safe_dom.Element('p').add_text('Error in ').add_child(
                    safe_dom.Element('strong').add_text(
                        'course.yaml')).add_text(' file. ').add_child(
                            safe_dom.Element('br')).add_child(
                                safe_dom.Element('pre').add_text(
                                    '\n%s\n%s\n' %
                                    (e.__class__.__name__, str(e))))

            if course.fs.is_read_write():
                location = 'namespace: %s' % course.get_namespace_name()
            else:
                location = 'disk: %s' % sites.abspath(course.get_home_folder(),
                                                      '/')

            if slug == '/':
                link = '/dashboard'
            else:
                link = '%s/dashboard' % slug
            link = safe_dom.Element('a', href=link).add_text(name)

            table.add_child(
                safe_dom.Element('tr').add_child(
                    safe_dom.Element('td').add_child(link).add_child(error)).
                add_child(safe_dom.Element('td').add_text(slug)).add_child(
                    safe_dom.Element('td').add_text(location)).add_child(
                        safe_dom.Element('td').add_text(
                            'namespace: %s' % course.get_namespace_name())))

        table.add_child(
            safe_dom.Element('tr').add_child(
                safe_dom.Element('td', colspan='4', align='right').add_text(
                    'Total: %s item(s)' % count)))
        template_values['main_content'] = content

        self.render_page(template_values)
예제 #7
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
예제 #8
0
def _list_questions(handler, all_questions, all_question_groups,
                    location_maps):
    """Prepare a list of the question bank contents."""
    if not handler.app_context.is_editable_fs():
        return safe_dom.NodeList()

    output = safe_dom.NodeList().append(
        safe_dom.Element('h3').add_text('Questions (%s)' % len(all_questions))
    ).append(
        safe_dom.Element('div', className='gcb-button-toolbar').append(
            safe_dom.Element('a',
                             className='gcb-button',
                             href='dashboard?action=add_mc_question').
            add_text('Add Multiple Choice')).append(safe_dom.Text(' ')).append(
                safe_dom.Element('a',
                                 className='gcb-button',
                                 href='dashboard?action=add_sa_question').
                add_text('Add Short Answer')).append(
                    safe_dom.Text(' ')).append(
                        safe_dom.Element(
                            'a',
                            className='gcb-button',
                            href='dashboard?action=import_gift_questions').
                        add_text('Add GIFT Questions')).append(
                            safe_dom.Element(
                                'div',
                                className='filter-container gcb-pull-right',
                                id='question-filter').append(
                                    safe_dom.Element(
                                        'button',
                                        className='gcb-button filter-button').
                                    add_text('Filter'))))

    # Create questions table
    table = _add_assets_table(output, 'question-table',
                              [('Description', 25), ('Question Groups', 25),
                               ('Course Locations', 25), ('Last Modified', 16),
                               ('Type', 9)])
    _attach_filter_data(handler, table)
    token = crypto.XsrfTokenManager.create_xsrf_token('clone_question')
    table.add_attribute(data_clone_question_token=token)
    token = crypto.XsrfTokenManager.create_xsrf_token('add_to_question_group')
    table.add_attribute(data_qg_xsrf_token=token)
    tbody = safe_dom.Element('tbody')
    table.add_child(tbody)

    table.add_child(
        _create_empty_footer('No questions available', 5, all_questions))

    question_to_group = {}
    for group in all_question_groups:
        for quid in group.question_ids:
            question_to_group.setdefault(long(quid), []).append(group)

    for question in all_questions:
        tr = safe_dom.Element('tr', data_quid=str(question.id))
        # Add description including action icons
        td = safe_dom.Element('td', className='description')
        tr.add_child(td)
        td.add_child(
            dashboard_utils.create_edit_button(
                'dashboard?action=edit_question&key=%s' % question.id))
        td.add_child(_create_preview_button())
        td.add_child(_create_clone_button(question.id))
        td.add_text(question.description)

        # Add containing question groups
        used_by_groups = question_to_group.get(question.id, [])
        cell = safe_dom.Element('td', className='groups')
        if all_question_groups:
            cell.add_child(_create_add_to_group_button())
        cell.add_child(
            _create_list([
                safe_dom.Text(group.description)
                for group in sorted(used_by_groups,
                                    key=lambda g: g.description)
            ]))
        tr.add_child(cell)

        # Add locations
        locations = _get_question_locations(question.id, location_maps,
                                            used_by_groups)
        tr.add_child(_create_locations_cell(locations))

        # Add last modified timestamp
        tr.add_child(
            safe_dom.Element('td',
                             data_timestamp=str(question.last_modified),
                             className='timestamp'))

        # Add question type
        tr.add_child(
            safe_dom.Element('td').add_text(
                'MC' if question.type == models.QuestionDTO.MULTIPLE_CHOICE
                else ('SA' if question.type == models.QuestionDTO.
                      SHORT_ANSWER else ('Unknown Type'))).add_attribute(
                          style='text-align: center'))

        # Add filter information
        filter_info = {}
        filter_info['description'] = question.description
        filter_info['type'] = question.type
        filter_info['lessons'] = []
        unit_ids = set()
        for (lesson, unit) in locations.get('lessons', ()):
            unit_ids.add(unit.unit_id)
            filter_info['lessons'].append(lesson.lesson_id)
        filter_info['units'] = list(unit_ids) + [
            a.unit_id for a in locations.get('assessments', ())
        ]
        filter_info['groups'] = [qg.id for qg in used_by_groups]
        filter_info['unused'] = int(not (
            locations and any(locations.values())))
        tr.add_attribute(data_filter=transforms.dumps(filter_info))
        tbody.add_child(tr)

    return output
예제 #9
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-icon-button',
                href='dashboard?%s' % urllib.urlencode({
                    'action': 'manage_asset',
                    'tab': tab_name,
                    'key': subfolder
                }),
                id='upload-button',
            ).append(safe_dom.Element(
                'span', className='icon md-file-upload')).append(
                    safe_dom.Element('span').add_text(" Upload")))
    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
예제 #10
0
    safe_dom.NodeList().append(
        safe_dom.Element('p').add_text("""
A newline separated list of course entries. Each course entry has
four parts, separated by colons (':'). The four parts are:""")).append(
            safe_dom.Element('ol').add_child(
                safe_dom.Element('li').add_text(
                    'The word \'course\', which is a required element.')).
            add_child(
                safe_dom.Element('li').add_text("""
A unique course URL prefix. Examples could be '/cs101' or '/art'.
Default: '/'""")).add_child(
                    safe_dom.Element('li').add_text("""
A file system location of course asset files. If location is left empty,
the course assets are stored in a datastore instead of the file system. A course
with assets in a datastore can be edited online. A course with assets on file
system must be re-deployed to Google App Engine manually.""")).add_child(
                        safe_dom.Element('li').add_text("""
A course datastore namespace where course data is stored in App Engine.
Note: this value cannot be changed after the course is created."""))).
    append(
        safe_dom.Text(
            'For example, consider the following two course entries:')).append(
                safe_dom.Element('br')).append(
                    safe_dom.Element('blockquote').
                    add_text('course:/cs101::/ns_cs101').add_child(
                        safe_dom.Element('br')).add_text('course:/:/')).append(
                            safe_dom.Element('p').add_text("""
Assuming you are hosting Course Builder on http:/www.example.com, the first
entry defines a course on a http://www.example.com/cs101 and both its assets
and student data are stored in the datastore namespace 'ns_cs101'. The second
entry defines a course hosted on http://www.example.com/, with its assets
stored in the '/' folder of the installation and its data stored in the default
empty datastore namespace.""")).append(
                                safe_dom.Element('p').add_text("""
A line that starts with '#' is ignored. Course entries are applied in the
order they are defined.""")),
__author__ = 'Rahul Singal ([email protected])'

from common import safe_dom
from controllers import utils
from models import custom_modules
from models.config import ConfigProperty
from models.models import StudentProfileDAO
from modules.course_explorer import student

from google.appengine.api import users

GCB_ENABLE_COURSE_EXPLORER_PAGE = ConfigProperty(
    'gcb_enable_course_explorer_page', bool,
    safe_dom.NodeList().append(
        safe_dom.Element('p').add_text("""
If this option is selected, "/" redirects to the course explorer page.
Otherwise, it redirects to the preview page for the default course.""")
    ), False, multiline=False, validator=None)


custom_module = None


class ExplorerPageInitializer(utils.PageInitializer):
    """Page initializer for explorer page.

    Allow links to the course explorer to be added
    to the navbars of all course pages.
    """

    @classmethod
예제 #12
0
    def get_courses(self):
        """Shows a list of all courses available on this site."""
        template_values = {}
        template_values['page_title'] = self.format_title('Courses')
        template_values['page_description'] = messages.COURSES_DESCRIPTION

        content = safe_dom.NodeList()
        content.append(
            safe_dom.Element(
                'a',
                id='add_course',
                className='gcb-button gcb-pull-right',
                role='button',
                href='%s?action=add_course' %
                self.LINK_URL).add_text('Add Course')).append(
                    safe_dom.Element(
                        'div', style='clear: both; padding-top: 2px;')).append(
                            safe_dom.Element('h3').add_text('All Courses'))
        table = safe_dom.Element('table')
        content.append(table)
        table.add_child(
            safe_dom.Element('tr').add_child(
                safe_dom.Element('th').add_text('Course Title')).add_child(
                    safe_dom.Element('th').add_text('Context Path')).add_child(
                        safe_dom.Element('th').add_text('Content Location')).
            add_child(
                safe_dom.Element('th').add_text('Student Data Location')))
        count = 0
        for course in sorted(sites.get_all_courses(),
                             key=lambda course: course.get_title().lower()):
            count += 1
            error = safe_dom.Text('')
            slug = course.get_slug()
            name = course.get_title()

            if course.fs.is_read_write():
                location = 'namespace: %s' % course.get_namespace_name()
            else:
                location = 'disk: %s' % sites.abspath(course.get_home_folder(),
                                                      '/')

            if slug == '/':
                link = '/dashboard'
            else:
                link = '%s/dashboard' % slug
            link = safe_dom.Element('a', href=link).add_text(name)

            table.add_child(
                safe_dom.Element('tr').add_child(
                    safe_dom.Element('td').add_child(link).add_child(error)).
                add_child(safe_dom.Element('td').add_text(slug)).add_child(
                    safe_dom.Element('td').add_text(location)).add_child(
                        safe_dom.Element('td').add_text(
                            'namespace: %s' % course.get_namespace_name())))

        table.add_child(
            safe_dom.Element('tr').add_child(
                safe_dom.Element('td', colspan='4', align='right').add_text(
                    'Total: %s item(s)' % count)))
        template_values['main_content'] = content

        self.render_page(template_values)
예제 #13
0
    def get_deployment(self):
        """Shows server environment and deployment information page."""
        template_values = {}
        template_values['page_title'] = self.format_title('Deployment')
        template_values['page_description'] = messages.DEPLOYMENT_DESCRIPTION

        # modules
        module_content = safe_dom.NodeList()
        module_content.append(safe_dom.Element('h3').add_text('Modules'))
        ol = safe_dom.Element('ol')
        module_content.append(ol)
        for name in sorted(custom_modules.Registry.registered_modules.keys()):
            enabled_text = ''
            if name not in custom_modules.Registry.enabled_module_names:
                enabled_text = ' (disabled)'

            li = safe_dom.Element('li').add_text('%s%s' % (name, enabled_text))
            ol.add_child(li)

            amodule = custom_modules.Registry.registered_modules.get(name)
            self._make_routes_dom(li, amodule.global_routes, 'Global Routes')
            self._make_routes_dom(li, amodule.namespaced_routes,
                                  'Namespaced Routes')

        # Custom tags.
        tag_content = safe_dom.NodeList()
        tag_content.append(safe_dom.Element('h3').add_text('Custom Tags'))
        ol = safe_dom.Element('ol')
        tag_content.append(ol)
        tag_bindings = tags.get_tag_bindings()
        for name in sorted(tag_bindings.keys()):
            clazz = tag_bindings.get(name)
            tag = clazz()
            vendor = tag.vendor()
            ol.add_child(
                safe_dom.Element('li').add_text(
                    '%s: %s: %s' % (name, tag.__class__.__name__, vendor)))

        # Yaml file content.
        yaml_content = safe_dom.NodeList()
        yaml_content.append(
            safe_dom.Element('h3').add_text('Contents of ').add_child(
                safe_dom.Element('code').add_text('app.yaml')))
        ol = safe_dom.Element('ol')
        yaml_content.append(ol)
        yaml_lines = open(
            os.path.join(os.path.dirname(__file__), '../../app.yaml'),
            'r').readlines()
        for line in yaml_lines:
            ol.add_child(safe_dom.Element('li').add_text(line))

        # Application identity.
        app_id = app.get_application_id()
        app_dict = {}
        app_dict['application_id'] = escape(app_id)
        app_dict['default_ver_hostname'] = escape(
            app.get_default_version_hostname())

        template_values['main_content'] = safe_dom.NodeList().append(
            self.render_dict(
                app_dict,
                'About the Application')).append(module_content).append(
                    tag_content).append(yaml_content).append(
                        self.render_dict(os.environ,
                                         'Server Environment Variables'))

        self.render_page(template_values)
예제 #14
0
def _list_questions(handler, all_questions, all_question_groups, location_maps):
    """Prepare a list of the question bank contents."""
    if not handler.app_context.is_editable_fs():
        return safe_dom.NodeList()

    table_attributes = _get_filter_data(handler)
    table_attributes.update({
        'data-clone-question-token':
            crypto.XsrfTokenManager.create_xsrf_token('clone_question'),
        'data-qg-xsrf-token':
            crypto.XsrfTokenManager.create_xsrf_token('add_to_question_group'),
    })

    question_to_group = {}
    for group in all_question_groups:
        for quid in group.question_ids:
            question_to_group.setdefault(long(quid), []).append(group)

    question_infos = []

    for question in all_questions:
        # containing question groups
        used_by_groups = question_to_group.get(question.id, [])
        in_group_descriptions = sorted([
            group.description for group in used_by_groups])

        # locations
        locations = _get_question_locations(
            question.id, location_maps, used_by_groups)

        # type
        question_type = (
            'MC' if question.type == models.QuestionDTO.MULTIPLE_CHOICE else (
            'SA' if question.type == models.QuestionDTO.SHORT_ANSWER else (
            'Unknown Type')))

        # filter information
        filter_info = {}
        filter_info['description'] = question.description
        filter_info['type'] = question.type
        filter_info['lessons'] = []
        unit_ids = set()
        for (lesson, unit) in locations.get('lessons', ()):
            unit_ids.add(unit.unit_id)
            filter_info['lessons'].append(lesson.lesson_id)
        filter_info['units'] = list(unit_ids) + [
            a.unit_id for a in  locations.get('assessments', ())]
        filter_info['groups'] = [qg.id for qg in used_by_groups]
        filter_info['unused'] = int(not (locations and any(locations.values())))

        question_infos.append(dict(
            description=question.description,
            filter_info=transforms.dumps(filter_info),
            id=question.id,
            group_descriptions=in_group_descriptions,
            last_modified=question.last_modified,
            type=question_type,
            locations=locations,
            url='dashboard?action=edit_question&key=%s' % question.id,
        ))

    return safe_dom.Template(
        jinja_utils.get_template('question_list.html', [TEMPLATE_DIR]),
        table_attributes=table_attributes,
        groups_exist=bool(all_question_groups), questions=question_infos)
예제 #15
0
 def format_title(self, text):
     """Formats standard title."""
     return safe_dom.NodeList().append(safe_dom.Text('U-MOOC ')).append(
         safe_dom.Entity('&gt;')).append(safe_dom.Text(' Admin ')).append(
             safe_dom.Entity('&gt;')).append(safe_dom.Text(' %s' % text))
예제 #16
0
def _list_question_groups(handler, all_questions, all_question_groups,
                          locations_map):
    """Prepare a list of question groups."""
    if not handler.app_context.is_editable_fs():
        return safe_dom.NodeList()

    output = safe_dom.NodeList()
    output.append(
        safe_dom.Element('h3').add_text('Question Groups (%s)' %
                                        len(all_question_groups)))
    output.append(
        safe_dom.Element('div', className='gcb-button-toolbar').append(
            safe_dom.Element('a',
                             className='gcb-button',
                             href='dashboard?action=add_question_group').
            add_text('Add Question Group'))).append(
                safe_dom.Element('div',
                                 style='clear: both; padding-top: 2px;'))

    # Create question groups table
    table = _add_assets_table(output, 'question-group-table',
                              [('Description', 25), ('Questions', 25),
                               ('Course Locations', 25),
                               ('Last Modified', 25)])
    tbody = safe_dom.Element('tbody')
    table.add_child(tbody)

    if not all_question_groups:
        table.add_child(_create_empty_footer('No question groups available',
                                             4))

    quid_to_question = {long(qu.id): qu for qu in all_questions}
    for question_group in all_question_groups:
        tr = safe_dom.Element('tr', data_qgid=str(question_group.id))
        # Add description including action icons
        td = safe_dom.Element('td', className='description')
        tr.add_child(td)
        td.add_child(
            dashboard_utils.create_edit_button(
                'dashboard?action=edit_question_group&key=%s' %
                (question_group.id)))
        td.add_text(question_group.description)

        # Add questions
        tr.add_child(
            _create_list_cell([
                safe_dom.Text(descr) for descr in sorted([
                    quid_to_question[long(quid)].description
                    for quid in question_group.question_ids
                ])
            ]).add_attribute(className='questions'))

        # Add locations
        tr.add_child(
            _create_locations_cell(locations_map.get(question_group.id, {})))

        # Add last modified timestamp
        tr.add_child(
            safe_dom.Element('td',
                             data_timestamp=str(question_group.last_modified),
                             className='timestamp'))

        tbody.add_child(tr)

    return output
예제 #17
0
    def get_settings(self):
        """Shows configuration properties information page."""
        template_values = {}
        template_values['page_title'] = self.format_title('Settings')
        template_values['page_description'] = messages.SETTINGS_DESCRIPTION

        content = safe_dom.NodeList()
        table = safe_dom.Element('table', className='gcb-config').add_child(
            safe_dom.Element('tr').
            add_child(safe_dom.Element('th').add_text('Name')).add_child(
                safe_dom.Element('th').add_text('Current Value')).add_child(
                    safe_dom.Element('th').add_text('Actions')).add_child(
                        safe_dom.Element('th').add_text('Description')))
        content.append(
            safe_dom.Element('h3').add_text('All Settings')).append(table)

        def get_style_for(value, value_type):
            """Formats CSS style for given value."""
            style = ''
            if not value or value_type in [int, long, bool]:
                style = 'text-align: center;'
            return style

        def get_action_html(caption, args, onclick=None):
            """Formats actions <a> link."""
            a = safe_dom.Element('a',
                                 href='/admin?%s' % urllib.urlencode(args),
                                 className='btn btn-primary').add_text(caption)
            if onclick:
                a.add_attribute(onclick=onclick)
            return a

        def get_actions(name, override):
            """Creates actions appropriate to an item."""
            if override:
                return get_action_html('Edit', {
                    'action': 'config_edit',
                    'name': name
                })
            else:
                return safe_dom.Element(
                    'form',
                    action='/admin?%s' % urllib.urlencode({
                        'action': 'config_override',
                        'name': name
                    }),
                    method='POST').add_child(
                        safe_dom.Element(
                            'input',
                            type='hidden',
                            name='xsrf_token',
                            value=self.create_xsrf_token(
                                'config_override'))).add_child(
                                    safe_dom.Element(
                                        'button',
                                        className='btn btn-primary',
                                        type='submit').add_text('Override'))

        def get_doc_string(item, default_value):
            """Formats an item documentation string for display."""
            doc_string = item.doc_string
            if not doc_string:
                doc_string = 'No documentation available.'
            if isinstance(doc_string, safe_dom.NodeList) or isinstance(
                    doc_string, safe_dom.Node):
                return safe_dom.NodeList().append(doc_string).append(
                    safe_dom.Text(' Default: \'%s\'.' % default_value))
            doc_string = ' %s Default: \'%s\'.' % (doc_string, default_value)
            return safe_dom.Text(doc_string)

        def get_lines(value):
            """Convert \\n line breaks into <br> and escape the lines."""
            escaped_value = safe_dom.NodeList()
            for line in str(value).split('\n'):
                escaped_value.append(safe_dom.Text(line)).append(
                    safe_dom.Element('br'))
            return escaped_value

        # get fresh properties and their overrides
        unused_overrides = config.Registry.get_overrides(force_update=True)
        registered = config.Registry.registered.copy()
        db_overrides = config.Registry.db_overrides.copy()
        names_with_draft = config.Registry.names_with_draft.copy()

        count = 0
        for name in sorted(registered.keys()):
            count += 1
            item = registered[name]
            has_environ_value, unused_environ_value = item.get_environ_value()

            # figure out what kind of override this is
            class_current = ''
            if has_environ_value:
                class_current = 'gcb-env-diff'
            if item.name in db_overrides:
                class_current = 'gcb-db-diff'
            if item.name in names_with_draft:
                class_current = 'gcb-db-draft'

            # figure out default and current value
            default_value = item.default_value
            value = item.value
            if default_value:
                default_value = str(default_value)
            if value:
                value = str(value)

            style_current = get_style_for(value, item.value_type)

            tr = safe_dom.Element('tr')
            table.add_child(tr)

            tr.add_child(
                safe_dom.Element('td', style='white-space: nowrap;').add_text(
                    item.name))

            td_value = safe_dom.Element('td').add_child(get_lines(value))
            if style_current:
                td_value.add_attribute(style=style_current)
            if class_current:
                td_value.add_attribute(className=class_current)
            tr.add_child(td_value)

            tr.add_child(
                safe_dom.Element('td',
                                 style='white-space: nowrap;',
                                 align='center').add_child(
                                     get_actions(
                                         name, name in db_overrides
                                         or name in names_with_draft)))

            tr.add_child(
                safe_dom.Element('td').add_child(
                    get_doc_string(item, default_value)))

        table.add_child(
            safe_dom.Element('tr').add_child(
                safe_dom.Element('td', colspan='4', align='right').add_text(
                    'Total: %s item(s)' % count)))

        content.append(
            safe_dom.Element('p').add_child(
                safe_dom.Element('strong').add_text('Legend')).add_text(':').
            add_text("""
                For each property, the value shown corresponds to, in
                descending order of priority:
            """).add_child(
                safe_dom.Element('span', className='gcb-db-diff').add_child(
                    safe_dom.Entity('&nbsp;')).
                add_text('[ the value override set via this page ]').add_child(
                    safe_dom.Entity('&nbsp;'))).add_text(', ').add_child(
                        safe_dom.Element('span', className='gcb-db-draft').
                        add_child(safe_dom.Entity('&nbsp;')).add_text(
                            '[ the default value with pending value override ]'
                        ).add_child(safe_dom.Entity('&nbsp;'))).add_text(', ').
            add_child(
                safe_dom.Element('span',
                                 className='gcb-env-diff').add_child(
                                     safe_dom.Entity('&nbsp;')).
                add_text('[ the environment value in app.yaml ]').add_child(
                    safe_dom.Entity('&nbsp;'))).add_text(', ').add_text("""
                and the [ default value ] in the U-MOOC codebase.
            """))

        template_values['main_content'] = content
        self.render_page(template_values)
예제 #18
0
 def test_include_node_list(self):
     """Element should include a list of children."""
     element = safe_dom.Element('a').add_children(
         safe_dom.NodeList().append(MockNode('b')).append(MockNode('c')))
     self.assertEqual('<a>bc</a>', element.__str__())
예제 #19
0
    def add_mentors(cls, handler):
        template_values = {}
        template_values['page_title'] = handler.format_title('Added Mentors')
        mentor_email_lc_list = cls.parse_mentor_csv(
            handler.request.get('mentor_email_list'))

        added_mentors = []
        not_found_mentors = []

        for m in mentor_email_lc_list:
            if len(m) < 1:
                continue

            email = m[0].strip()
            if len(m) >= 2:
                college_id = m[1].strip()
            else:
                college_id = ''

            if not email:
                continue
            p = Student.get_by_email(email)
            if (p is None
                    or (college_id and local_chapter_model.LocalChapterDAO.
                        get_local_chapter_by_key(college_id) is None)):
                not_found_mentors.append(email)
            else:
                mentor = Mentor.get_or_create(user_id=p.user_id)
                if college_id:
                    mentor.local_chapter = True
                    mentor.college_id = college_id
                else:
                    mentor.local_chapter = False
                mentor.put()
                added_mentors.append(email)

        content = safe_dom.NodeList()
        if len(added_mentors) > 0:
            content.append(
                safe_dom.Element('h3').add_text('Successfully added Mentors'))
            l = safe_dom.Element('ol')
            for m in added_mentors:
                l.add_child(safe_dom.Element('li').add_text(m))
            content.append(l)

        if len(not_found_mentors) > 0:
            content.append(
                safe_dom.Element('h3').add_text('Mentor Addition Failed'))
            l = safe_dom.Element('ol')
            for m in not_found_mentors:
                l.add_child(safe_dom.Element('li').add_text(m))
            content.append(l)

        if len(not_found_mentors) == 0 and len(added_mentors) == 0:
            content.append(
                safe_dom.Element('h3').add_text(
                    'No Emails specified for adding to mentor list'))

        handler.render_page(
            {
                'page_title': handler.format_title(cls.NAME),
                'main_content': content
            },
            in_action=cls.DASHBOARD_NAV,
            in_tab=cls.DASHBOARD_SHOW_LIST_TAB)
예제 #20
0
파일: settings.py 프로젝트: thejeshgn/seek
    def get_google_service_account(cls, handler):
        """Displays list of service account settings."""

        if roles.Roles.is_super_admin():
            # ?tab= for v1.9, ?action= for v1.8
            exit_url = '%s?tab=google_service_account' % handler.LINK_URL
        else:
            exit_url = cls.request.referer
        rest_url = GoogleServiceAccountRESTHandler.URI

        template_values = {}
        template_values['page_title'] = handler.format_title(
            'Google Service Accounts')

        content = safe_dom.NodeList()
        edit_google_service_account_action = (
            base.GoogleServiceAccountBase.DASHBOARD_EDIT_SERVICE_ACCOUNT_ACTION
        )

        for name, key in (service_account_models.GoogleServiceAccountTypes.
                          to_dict().iteritems()):
            content.append(
                safe_dom.Element(
                    'a',
                    id=edit_google_service_account_action,
                    className='gcb-button gcb-pull-right',
                    role='button',
                    style='margin: 5px',
                    href='%s?action=%s&key=%s&credential_type=%s' %
                    (handler.LINK_URL, edit_google_service_account_action, key,
                     key)).add_text('Add/Edit %s object' % name))

        # Title - Default Settings
        content.append(safe_dom.Element('h3').add_text('Default Settings'))

        # Table - Default Settings
        table_div = safe_dom.Element(
            'div', style='width: 100%; overflow: scroll; margin-top: 10px;')
        table = safe_dom.Element('table')
        table_div.add_child(table)
        content.append(table_div)

        table_heading = safe_dom.Element('tr')
        for attr in cls.TABLE_HEADING_LIST:
            table_heading.add_child(safe_dom.Element('th').add_text(attr))

        # table_heading.add_child(
        #     safe_dom.Element('th').add_text('Edit Link'))

        table.add_child(table_heading)

        all_settings = (google_service_account.GoogleServiceManager.
                        get_all_default_settings())

        # TODO(rthakker) Add support for namespaces from course list etc
        # later on
        for entity in all_settings:
            tr = safe_dom.Element('tr')
            table.add_child(tr)
            args = {
                'action': edit_google_service_account_action,
                'key': entity.id,
            }

            for attr in cls.TABLE_HEADING_LIST:
                tr.add_child(
                    safe_dom.Element('td').add_text(getattr(entity, attr)))

            # href = '%s?%s' % (handler.LINK_URL, urllib.urlencode(args))
            # link = safe_dom.Element(
            #     'a', href=href, type='button', className='gcb-button'
            # ).add_text('Edit')
            # edit_td = safe_dom.Element('td')
            # edit_td.add_child(link)
            # tr.add_child(edit_td)

        content.append(
            safe_dom.Element('p').add_text('Total: %d' % len(all_settings)))
        template_values['main_content'] = content
        handler.render_page(template_values)