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')
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__())
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__())
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)
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))
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)
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
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
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(' ')) 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
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
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)
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)
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)
def format_title(self, text): """Formats standard title.""" return safe_dom.NodeList().append(safe_dom.Text('U-MOOC ')).append( safe_dom.Entity('>')).append(safe_dom.Text(' Admin ')).append( safe_dom.Entity('>')).append(safe_dom.Text(' %s' % text))
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
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(' ')). add_text('[ the value override set via this page ]').add_child( safe_dom.Entity(' '))).add_text(', ').add_child( safe_dom.Element('span', className='gcb-db-draft'). add_child(safe_dom.Entity(' ')).add_text( '[ the default value with pending value override ]' ).add_child(safe_dom.Entity(' '))).add_text(', '). add_child( safe_dom.Element('span', className='gcb-env-diff').add_child( safe_dom.Entity(' ')). add_text('[ the environment value in app.yaml ]').add_child( safe_dom.Entity(' '))).add_text(', ').add_text(""" and the [ default value ] in the U-MOOC codebase. """)) template_values['main_content'] = content self.render_page(template_values)
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__())
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)
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)