def get_generator_status_message(generator_class, job): message = safe_dom.NodeList() generator_description = generator_class.get_description() if job is None: message.append( safe_dom.Text('Statistics for %s have not been calculated yet' % generator_description)) elif job.status_code == jobs.STATUS_CODE_COMPLETED: message.append( safe_dom.Text( 'Statistics for %s were last updated at %s in about %s sec.' % (generator_description, job.updated_on.strftime(utils.HUMAN_READABLE_DATETIME_FORMAT), job.execution_time_sec))) elif job.status_code == jobs.STATUS_CODE_FAILED: message.append( safe_dom.Text('There was an error updating %s ' % generator_description + 'statistics. Error msg:')) message.append(safe_dom.Element('br')) if issubclass(generator_class, jobs.MapReduceJob): error_message = jobs.MapReduceJob.get_error_message(job) else: error_message = job.output message.append( safe_dom.Element('div', className='gcb-message').add_child( safe_dom.Element('pre').add_text(error_message))) else: message.append( safe_dom.Text( 'Job for %s statistics started at %s and is running now.' % (generator_description, job.updated_on.strftime( utils.HUMAN_READABLE_DATETIME_FORMAT)))) return message
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)
def get_certificate_table_entry(handler, student, course): # I18N: Title of section on page showing certificates for course completion. title = handler.gettext('Certificate') explanations = [] if student_is_qualified(student, course, explanations=explanations): 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: nl = safe_dom.NodeList() nl.append( safe_dom.Text( # 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.'))) if explanations: ul = safe_dom.Element('ul', className='certificate-explanations') for expl in explanations: ul.append(safe_dom.Element('li').add_text(expl)) nl.append(ul) return (title, nl)
def format_title(self, text): """Formats standard title.""" return safe_dom.NodeList().append( safe_dom.Text('Course Builder ')).append( safe_dom.Entity('>')).append( safe_dom.Text(' Admin ')).append( safe_dom.Entity('>')).append( safe_dom.Text(' %s' % text))
def format_title(self, text): """Formats standard title.""" title = self.app_context.get_environ()['course']['title'] return safe_dom.NodeList().append(safe_dom.Text('U-MOOC ')).append( safe_dom.Entity('>')).append(safe_dom.Text( ' %s ' % title)).append(safe_dom.Entity('>')).append( safe_dom.Text(' Dashboard ')).append( safe_dom.Entity('>')).append( safe_dom.Text(' %s' % text))
def _get_availability(self, resource): if not hasattr(resource, 'now_available'): return safe_dom.Text('') if resource.now_available: return safe_dom.Text('') else: return safe_dom.NodeList().append(safe_dom.Text(' ')).append( safe_dom.Element('span', className='draft-label').add_text( '(%s)' % unit_lesson_editor.DRAFT_TEXT))
def get_markup(self, job): """Returns Jinja markup for question stats analytics.""" errors = [] stats_calculated = False update_message = safe_dom.Text('') accumulated_question_answers = None accumulated_assessment_answers = None if not job: update_message = safe_dom.Text( 'Multiple-choice question statistics have not been calculated ' 'yet.') else: if job.status_code == jobs.STATUS_CODE_COMPLETED: accumulated_question_answers, accumulated_assessment_answers = ( transforms.loads(job.output)) stats_calculated = True update_message = safe_dom.Text( """ Multiple-choice question statistics were last updated at %s in about %s second(s).""" % (job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT), job.execution_time_sec)) elif job.status_code == jobs.STATUS_CODE_FAILED: update_message = safe_dom.NodeList().append( safe_dom.Text(""" There was an error updating multiple-choice question statistics. Here is the message:""")).append( safe_dom.Element('br')).append( safe_dom.Element('blockquote').add_child( safe_dom.Element('pre').add_text('\n%s' % job.output))) else: update_message = safe_dom.Text( """ Multiple-choice question statistics update started at %s and is running now. Please come back shortly.""" % (job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT))) return jinja2.utils.Markup( self.get_template( 'question_stats.html', [os.path.dirname(__file__)]).render( { 'errors': errors, 'accumulated_question_answers': transforms.dumps(accumulated_question_answers), 'accumulated_assessment_answers': transforms.dumps(accumulated_assessment_answers), 'stats_calculated': stats_calculated, 'update_message': update_message, }, autoescape=True))
def _get_user_nav(self): current_action = self.request.get('action') nav_mappings = [('welcome', 'Welcome'), ('courses', 'Courses'), ('settings', 'Settings'), ('perf', 'Metrics'), ('deployment', 'Deployment')] if DIRECT_CODE_EXECUTION_UI_ENABLED: nav_mappings.append(('console', 'Console')) nav = safe_dom.NodeList() for action, title in nav_mappings: if action == current_action: elt = safe_dom.Element('a', href='/admin?action=%s' % action, className='selected') else: elt = safe_dom.Element('a', href='/admin?action=%s' % action) elt.add_text(title) nav.append(elt).append(safe_dom.Text(' ')) if appengine_config.gcb_appstats_enabled(): nav.append( safe_dom.Element( 'a', target='_blank', href='/admin/stats/').add_text('Appstats')).append( safe_dom.Text(' ')) if appengine_config.PRODUCTION_MODE: app_id = app.get_application_id() nav.append( safe_dom.Element('a', target='_blank', href=('https://appengine.google.com/' 'dashboard?app_id=s~%s' % app_id)).add_text('Google App Engine')) else: nav.append( safe_dom.Element('a', target='_blank', href='http://localhost:8000/').add_text( 'Google App Engine')).append( safe_dom.Text(' ')) nav.append( safe_dom.Element( 'a', target='_blank', href='https://code.google.com/p/course-builder/wiki/AdminPage' ).add_text('Help')) nav.append( safe_dom.Element( 'a', href=('https://groups.google.com/forum/' '?fromgroups#!forum/course-builder-announce'), target='_blank').add_text('News')) return nav
def describe(cls, entity_class): for fn in models_data_removal.Registry.get_user_id_removers(): if fn.im_self == entity_class: return safe_dom.Text('By user_id') for fn in models_data_removal.Registry.get_email_removers(): if fn.im_self == entity_class: return safe_dom.Text('By email') if (entity_class.kind() in models_data_removal.Registry.get_unindexed_classes()): return safe_dom.Text('Map/Reduce job')
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.SafeDom): 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 format_title(self, text): """Formats standard title with or without course picker.""" ret = safe_dom.NodeList() cb_text = 'Course Builder ' ret.append(safe_dom.Text(cb_text)) ret.append(safe_dom.Entity('>')) ret.append(safe_dom.Text(' %s ' % self.app_context.get_title())) ret.append(safe_dom.Entity('>')) dashboard_text = ' Dashboard ' ret.append(safe_dom.Text(dashboard_text)) ret.append(safe_dom.Entity('>')) ret.append(safe_dom.Text(' %s' % text)) return ret
def render_page(self, template_values, in_action=None): page_title = template_values['page_title'] template_values['header_title'] = page_title template_values['page_headers'] = [ hook(self) for hook in self.PAGE_HEADER_HOOKS] template_values['breadcrumbs'] = page_title current_action = (in_action or self.request.get('action') or self.default_action_for_current_permissions()) current_menu_item = self.actions_to_menu_items.get(current_action) template_values['root_menu_group'] = self.root_menu_group template_values['current_menu_item'] = current_menu_item template_values['is_global_admin'] = True template_values['course_app_contexts'] = dashboard.get_visible_courses() template_values['gcb_course_base'] = '/' template_values['user_nav'] = safe_dom.NodeList().append( safe_dom.Text('%s | ' % users.get_current_user().email()) ).append( safe_dom.Element( 'a', href=users.create_logout_url(self.request.uri) ).add_text('Logout')) template_values[ 'page_footer'] = 'Page created on: %s' % datetime.datetime.now() template_values['coursebuilder_version'] = ( os.environ['GCB_PRODUCT_VERSION']) template_values['application_id'] = app.get_application_id() template_values['application_version'] = ( os.environ['CURRENT_VERSION_ID']) if not template_values.get('sections'): template_values['sections'] = [] self.response.write( self.get_template('view.html', []).render(template_values))
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
def _get_assets_contrib(handler, items, name, all_paths): if not contrib_asset_listers: items.append(safe_dom.Text( 'No assets extensions have been registered')) else: for asset_lister in contrib_asset_listers: items.append(asset_lister(handler))
def render_page(self, template_values, in_action=None, in_tab=None): """Renders a page using provided template values.""" template_values['header_title'] = template_values['page_title'] template_values['page_headers'] = [ hook(self) for hook in self.PAGE_HEADER_HOOKS ] template_values['course_picker'] = self.get_course_picker() template_values['course_title'] = self.app_context.get_title() template_values['top_nav'] = self._get_top_nav(in_action, in_tab) template_values['gcb_course_base'] = self.get_base_href(self) template_values['user_nav'] = safe_dom.NodeList().append( safe_dom.Text('%s | ' % users.get_current_user().email())).append( safe_dom.Element('a', href=users.create_logout_url( self.request.uri)).add_text('Logout')) template_values[ 'page_footer'] = 'Page created on: %s' % datetime.datetime.now() template_values['coursebuilder_version'] = ( os.environ['GCB_PRODUCT_VERSION']) template_values['application_id'] = app_identity.get_application_id() template_values['application_version'] = ( os.environ['CURRENT_VERSION_ID']) template_values[ 'can_highlight_code'] = oeditor.CAN_HIGHLIGHT_CODE.value template_values['extra_css_href_list'] = self.EXTRA_CSS_HREF_LIST template_values['extra_js_href_list'] = self.EXTRA_JS_HREF_LIST if not template_values.get('sections'): template_values['sections'] = [] self.response.write( self.get_template('view.html', []).render(template_values))
def render_page(self, template_values, in_action=None, in_tab=None): page_title = template_values['page_title'] template_values['header_title'] = page_title template_values['page_headers'] = [ hook(self) for hook in self.PAGE_HEADER_HOOKS ] template_values['breadcrumbs'] = page_title template_values['top_nav'] = self._get_top_nav(in_action, in_tab) template_values['gcb_course_base'] = '/' template_values['user_nav'] = safe_dom.NodeList().append( safe_dom.Text('%s | ' % users.get_current_user().email())).append( safe_dom.Element('a', href=users.create_logout_url( self.request.uri)).add_text('Logout')) template_values[ 'page_footer'] = 'Page created on: %s' % datetime.datetime.now() template_values['coursebuilder_version'] = ( os.environ['GCB_PRODUCT_VERSION']) template_values['application_id'] = app.get_application_id() template_values['application_version'] = ( os.environ['CURRENT_VERSION_ID']) template_values[ 'can_highlight_code'] = oeditor.CAN_HIGHLIGHT_CODE.value if not template_values.get('sections'): template_values['sections'] = [] self.response.write( self.get_template('view.html', []).render(template_values))
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
def assemble_sanitized_message(text, link): node_list = safe_dom.NodeList() if text: node_list.append(safe_dom.Text(text)) if link: node_list.append(safe_dom.Element( 'a', href=link, target='_blank').add_text('Learn more...')) return node_list
def get_schema_fields(): enabled_name = ( GUIDE_SETTINGS_SCHEMA_SECTION + ':' + GUIDE_ENABLED_FOR_THIS_COURSE) enabled = schema_fields.SchemaField( enabled_name, 'Enable Guides', 'boolean', optional=True, i18n=False, editable=True, description=str(safe_dom.NodeList( ).append(safe_dom.Text( 'If checked, this course will be included in the guides ' 'experience accessible at ') ).append(safe_dom.assemble_link( '/modules/guides', '/modules/guides', target="_blank") ).append(safe_dom.Text('. Course must not be Private. ') ).append(safe_dom.assemble_link( services.help_urls.get(enabled_name), 'Learn more...', target="_blank")))) color = schema_fields.SchemaField( GUIDE_SETTINGS_SCHEMA_SECTION + ':' + GUIDE_COLOR, 'Color', 'string', optional=True, i18n=False, editable=True, description='The color scheme for this course\'s guides must ' 'be expressed as a web color hex triplet, beginning with ' 'a "#". If blank, #00838F will be used.') duration = schema_fields.SchemaField( GUIDE_SETTINGS_SCHEMA_SECTION + ':' + GUIDE_DURATION, 'Duration', 'integer', optional=True, i18n=False, editable=True, default_value=0, description=( 'Specify the average length of each lesson in the course in ' 'minutes and it will be used to estimate the duration of each ' 'guide. If blank or set to 0, duration will not be shown.')) availabiliy_name = GUIDE_SETTINGS_SCHEMA_SECTION + ':' + GUIDE_AVAILABILITY availability = schema_fields.SchemaField( availabiliy_name, 'Availability', 'boolean', optional=True, i18n=False, select_data=AVAILABILITY_SELECT_DATA, default_value=courses.AVAILABILITY_COURSE, description=str(safe_dom.NodeList( ).append(safe_dom.Text( 'Guides default to the availability of the course, ' 'but may also be restricted to admins (Private). ') ).append(safe_dom.assemble_link( services.help_urls.get(availabiliy_name), 'Learn more...', target="_blank")))) return (lambda _: enabled, lambda _: color, lambda _: duration, lambda _: availability)
def get_markup(self, job): template_values = {} template_values['stats_calculated'] = False if not job: message = ('%s statistics have not been calculated yet.' % self.description.capitalize()) template_values['update_message'] = safe_dom.Text(message) else: if job.status_code == jobs.STATUS_CODE_COMPLETED: template_values['stats_calculated'] = True default_message = ( '%s statistics were last updated at %s in about %s sec.' % (self.description.capitalize(), job.updated_on.strftime(utils.HUMAN_READABLE_TIME_FORMAT), job.execution_time_sec)) # This message can be overridden by _fill_completed_values() # as necessary and approprate. template_values['update_message'] = safe_dom.Text( default_message) self._fill_completed_values(job, template_values) elif job.status_code == jobs.STATUS_CODE_FAILED: message = ( 'There was an error updating %s statistics. Error msg:' % self.description) update_message = safe_dom.NodeList() update_message.append(safe_dom.Text(message)) update_message.append(safe_dom.Element('br')) update_message.append( safe_dom.Element('blockquote').add_child( safe_dom.Element('pre').add_text( '\n%s' % self._get_error_message(job)))) template_values['update_message'] = update_message else: message = ( '%s statistics update started at %s and is running now.' % (self.description.capitalize(), job.updated_on.strftime( utils.HUMAN_READABLE_TIME_FORMAT))) template_values['update_message'] = safe_dom.Text(message) self._fill_pending_values(job, template_values) return jinja2.utils.Markup( self.get_template(self.html_template_name, [os.path.dirname(__file__)]).render( template_values, autoescape=True))
def render_page(self, template_values, in_action=None): """Renders a page using provided template values.""" template_values['header_title'] = template_values['page_title'] template_values['page_headers'] = [ hook(self) for hook in self.PAGE_HEADER_HOOKS ] template_values['course_title'] = self.app_context.get_title() current_action = in_action or self._get_current_menu_action() template_values['current_menu_item'] = self.actions_to_menu_items.get( current_action) template_values['courses_menu_item'] = self.actions_to_menu_items.get( 'courses') template_values['root_menu_group'] = self.root_menu_group template_values['course_app_contexts'] = get_visible_courses() template_values['app_context'] = self.app_context template_values['current_course'] = self.get_course() template_values['gcb_course_base'] = self.get_base_href(self) template_values['user_nav'] = safe_dom.NodeList().append( safe_dom.Text('%s | ' % users.get_current_user().email())).append( safe_dom.Element('a', href=users.create_logout_url( self.request.uri)).add_text('Logout')) template_values[ 'page_footer'] = 'Page created on: %s' % datetime.datetime.now() template_values['coursebuilder_version'] = ( os.environ['GCB_PRODUCT_VERSION']) template_values['application_id'] = app_identity.get_application_id() version = os.environ['CURRENT_VERSION_ID'] if '.' not in version or not appengine_config.PRODUCTION_MODE: template_values['application_version'] = version else: version, deployed_at = version.split('.', 1) template_values['application_version'] = version template_values[ 'deployed_at'] = datetime.datetime.utcfromtimestamp( int(deployed_at) >> 28) # Yes, really. template_values['extra_css_href_list'] = self.EXTRA_CSS_HREF_LIST template_values['extra_js_href_list'] = self.EXTRA_JS_HREF_LIST template_values['powered_by_url'] = services.help_urls.get( 'dashboard:powered_by') if not template_values.get('sections'): template_values['sections'] = [] if not appengine_config.PRODUCTION_MODE: template_values['page_uuid'] = str(uuid.uuid1()) self.response.write( self.get_template('view.html').render(template_values))
def render_page(self, template_values, in_action=None): """Render page contents and write them into the response. NOTE: The resulting contents are *not* sent to the client (user's browser) as a result of calling render_page(). webapp2 does not forward the response and its contents to the client until the handler itself completes. """ page_title = template_values['page_title'] template_values['header_title'] = page_title template_values['page_headers'] = [ hook(self) for hook in self.PAGE_HEADER_HOOKS] template_values['breadcrumbs'] = page_title # menu current_action = (in_action or self.request.get('action') or self.default_action_for_current_permissions()) template_values['current_menu_item'] = self.actions_to_menu_items\ .get(current_action) template_values['courses_menu_item'] = self.actions_to_menu_items.get( 'courses') template_values['root_menu_group'] = self.root_menu_group template_values['course_app_contexts'] = dashboard.get_visible_courses() template_values['gcb_course_base'] = self.BASE_URL template_values['user_nav'] = safe_dom.NodeList().append( safe_dom.Text('%s | ' % users.get_current_user().email()) ).append( safe_dom.Element( 'a', href=users.create_logout_url(self.request.uri) ).add_text('Logout')) template_values[ 'page_footer'] = 'Page created on: %s' % datetime.datetime.now() template_values['coursebuilder_version'] = ( os.environ['GCB_PRODUCT_VERSION']) template_values['application_id'] = app.get_application_id() version = os.environ['CURRENT_VERSION_ID'] if '.' not in version or not appengine_config.PRODUCTION_MODE: template_values['application_version'] = version else: version, deployed_at = version.split('.', 1) template_values['application_version'] = version template_values['deployed_at'] = datetime.datetime.utcfromtimestamp( int(deployed_at) >> 28) # Yes, really. if not template_values.get('sections'): template_values['sections'] = [] if not appengine_config.PRODUCTION_MODE: template_values['page_uuid'] = str(uuid.uuid1()) self.response.write( self.get_template('view.html').render(template_values))
def render_page(self, template_values): """Renders a page using provided template values.""" template_values['top_nav'] = self._get_user_nav() template_values['user_nav'] = safe_dom.NodeList().append( safe_dom.Text('%s | ' % users.get_current_user().email())).append( safe_dom.Element('a', href=users.create_logout_url( self.request.uri)).add_text('Logout')) template_values[ 'page_footer'] = 'Created on: %s' % datetime.datetime.now() self.response.write( self.get_template('view.html', []).render(template_values))
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
def _fill_completed_values(self, job, template_values): course = courses.Course(self) template_values['entity_codes'] = transforms.dumps( progress.UnitLessonCompletionTracker.EVENT_CODE_MAPPING.values()) value = transforms.loads(job.output) if value: value = transforms.dumps(value) else: value = None template_values['progress'] = value try: template_values['content'] = transforms.dumps( progress.ProgressStats(course).compute_entity_dict( 'course', [])) except IOError: template_values['update_message'] = safe_dom.Text( 'This feature is supported by CB 1.3 and up.')
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)
def render_page(self, template_values, in_action=None): """Renders a page using provided template values.""" template_values['header_title'] = template_values['page_title'] template_values['page_headers'] = [ hook(self) for hook in self.PAGE_HEADER_HOOKS ] template_values['course_title'] = self.app_context.get_title() current_action = (in_action or self.request.get('action') or self.default_action_for_current_permissions()) current_menu_item = self.actions_to_menu_items.get(current_action) template_values['root_menu_group'] = self.root_menu_group template_values['current_menu_item'] = current_menu_item template_values['app_context'] = self.app_context template_values['course_app_contexts'] = get_visible_courses() template_values['current_course'] = self.get_course() template_values['gcb_course_base'] = self.get_base_href(self) template_values['user_nav'] = safe_dom.NodeList().append( safe_dom.Text('%s | ' % users.get_current_user().email())).append( safe_dom.Element('a', href=users.create_logout_url( self.request.uri)).add_text('Logout')) template_values[ 'page_footer'] = 'Page created on: %s' % datetime.datetime.now() template_values['coursebuilder_version'] = ( os.environ['GCB_PRODUCT_VERSION']) template_values['application_id'] = app_identity.get_application_id() template_values['application_version'] = ( os.environ['CURRENT_VERSION_ID']) template_values['extra_css_href_list'] = self.EXTRA_CSS_HREF_LIST template_values['extra_js_href_list'] = self.EXTRA_JS_HREF_LIST if not template_values.get('sections'): template_values['sections'] = [] self.response.write( self.get_template('view.html', []).render(template_values))
def get_markup(self, job): """Returns Jinja markup for peer review analytics.""" errors = [] stats_calculated = False update_message = safe_dom.Text('') course = courses.Course(self) serialized_units = [] if not job: update_message = safe_dom.Text( 'Peer review statistics have not been calculated yet.') else: if job.status_code == jobs.STATUS_CODE_COMPLETED: stats = transforms.loads(job.output) stats_calculated = True for unit in course.get_peer_reviewed_units(): if unit.unit_id in stats['counts_by_completed_reviews']: unit_stats = ( stats['counts_by_completed_reviews'][unit.unit_id]) serialized_units.append({ 'stats': unit_stats, 'title': unit.title, 'unit_id': unit.unit_id, }) update_message = safe_dom.Text( """ Peer review statistics were last updated at %s in about %s second(s).""" % (job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT), job.execution_time_sec)) elif job.status_code == jobs.STATUS_CODE_FAILED: update_message = safe_dom.NodeList().append( safe_dom.Text(""" There was an error updating peer review statistics. Here is the message:""")).append( safe_dom.Element('br')).append( safe_dom.Element('blockquote').add_child( safe_dom.Element('pre').add_text('\n%s' % job.output))) else: update_message = safe_dom.Text( """ Peer review statistics update started at %s and is running now. Please come back shortly.""" % job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT)) return jinja2.utils.Markup( self.get_template( 'stats.html', [os.path.dirname(__file__)]).render( { 'errors': errors, 'serialized_units': serialized_units, 'serialized_units_json': transforms.dumps(serialized_units), 'stats_calculated': stats_calculated, 'update_message': update_message, }, autoescape=True))
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( 'div', className='gcb-message').add_text('course:/cs101::ns_cs101').add_child( safe_dom.Element('br')).add_text('course:/:/')).append( safe_dom.Element('div').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('br')).append( safe_dom.Element('div').add_text(""" A line that starts with '#' is ignored. Course entries are applied in the order they are defined."""))
from models import jobs from models import services from models import transforms from modules.dashboard import dashboard from google.appengine.api import namespace_manager from google.appengine.api import search from google.appengine.ext import db MODULE_NAME = 'Full Text Search' DEPRECATED = config.ConfigProperty( 'gcb_can_index_automatically', bool, safe_dom.Text( 'This property has been deprecated; it is retained so that we ' 'will not generate no-such-variable error messages for existing ' 'installations that have this property set.'), default_value=False, label='Automatically index search', deprecated=True) SEARCH_QUERIES_MADE = counters.PerfCounter( 'gcb-search-queries-made', 'The number of student queries made to the search module.') SEARCH_RESULTS_RETURNED = counters.PerfCounter( 'gcb-search-results-returned', 'The number of search results returned across all student queries.') SEARCH_FAILURES = counters.PerfCounter( 'gcb-search-failures', 'The number of search failure messages returned across all student ' 'queries.')