Exemplo n.º 1
0
def linked_user_comments(user, maxlength=0, avatar=20):

    if not isinstance(user, model.User):
        user_name = unicode(user)
        user = model.User.get(user_name)
        if not user:
            return user_name
    if user:
        name = user.name if model.User.VALID_NAME.match(user.name) else user.id
        displayname = user.display_name
        user_name = user.name if model.User.VALID_NAME.match(user.name) else user.id

        if maxlength and len(user.display_name) > maxlength:
            displayname = displayname[:maxlength] + '...'

        if maxlength and len(user.name) > maxlength:
            user_name = user_name[:maxlength] + '...'

        return tags.literal(u'{icon} {link}'.format(
            icon=gravatar(
                email_hash=user.email_hash,
                size=avatar
            ),
            link=tags.link_to(
                user_name,
                url_for(controller='user', action='read', id=name)
            )
        ))
Exemplo n.º 2
0
	def errorlist(self, name=None, **attrs):
		"""
		Renders errors in a <ul> element if there are multiple, otherwise will
		use a div. Unless specified in attrs, class will be "Alert".

		If no errors present returns an empty string.

		`name` : errors for name. If **None** all errors will be rendered.
		"""

		if name is None:
			errors = self.all_errors()
		else:
			errors = self.errors_for(name)

		if not errors:
			return ''

		if 'class_' not in attrs:
			attrs['class_'] = "Alert"

		if len(errors) > 1:
			content = "\n".join(HTML.tag("li", error) for error in errors)

			return HTML.tag("ul", tags.literal(content), **attrs)

		return HTML.tag("div", errors[0], **attrs)
Exemplo n.º 3
0
    def errorlist(self, name=None, **attrs):
        _ = self.form.request.translate
        """
        Renders errors in a <ul> element if there are multiple, otherwise will
        use a div. Unless specified in attrs, class will be "Alert".

        If no errors present returns an empty string.

        `name` : errors for name. If **None** all errors will be rendered.
        """

        if name is None:
            errors = self.all_errors()
        else:
            errors = self.errors_for(name)

        if not errors:
            return ''

        if 'class_' not in attrs:
            attrs['class_'] = "Alert"

        if len(errors) > 1:
            content = Markup("\n").join(
                HTML.tag("li", error) for error in errors)

            return HTML.tag("ul", tags.literal(content), **attrs)

        return Markup('''
            <div class="ui-widget clearfix" style="margin: 0.25em;">
                <div class="ui-state-error error-field-wrapper">
                <span class="ui-icon ui-icon-alert error-notice-icon">%s</span>%s
                </div>
            </div>
            ''') % (_('Error'), errors[0])
Exemplo n.º 4
0
    def _fetch_drupal_content(self, identifier, language=None, fallback=True):
        """ This helper fetches content from Drupal database using url alias identifier.
            Return content as dictionary containing language, title, body, node_id and edit link. None if not found.
            Tries to fallback to different language if fallback is True.

            Not cached.
        """
        if not language:
            language = helpers.lang()

        query = """SELECT url_alias.language, node.title, field_revision_body.body_value, node.nid from url_alias
                       INNER JOIN node ON node.nid = split_part(url_alias.source, '/', 2)::integer
                       INNER JOIN field_revision_body ON field_revision_body.entity_id = split_part(url_alias.source, '/', 2)::integer
                   WHERE url_alias.alias = %(identifier)s"""  # noqa: E501

        results = {}
        for content_language, title, body, node_id in self.engine.execute(query, {'identifier': identifier}):
            results[content_language] = {'language': content_language, 'title': title, 'body': body, 'node_id': node_id}

        result = results.get(language, None)

        if not result and fallback and results:
            for fallback_language in self._language_fallback_order:
                result = results.get(fallback_language)
                if result:
                    break
            if not result:
                result = results.itervalues().next()

        if result:
            result['edit'] = urllib.quote("/%s/node/%s/edit" % (language, str(result['node_id'])))
            result['body'] = literal(result['body'])

        return result
Exemplo n.º 5
0
    def errorlist(self, name=None, **attrs):
        _ = self.form.request.translate
        """
        Renders errors in a <ul> element if there are multiple, otherwise will
        use a div. Unless specified in attrs, class will be "Alert".

        If no errors present returns an empty string.

        `name` : errors for name. If **None** all errors will be rendered.
        """

        if name is None:
            errors = self.all_errors()
        else:
            errors = self.errors_for(name)

        if not errors:
            return ''

        if 'class_' not in attrs:
            attrs['class_'] = "Alert"

        if len(errors) > 1:
            content = Markup("\n").join(HTML.tag("li", error) for error in errors)

            return HTML.tag("ul", tags.literal(content), **attrs)

        return Markup('''
            <div class="ui-widget clearfix" style="margin: 0.25em;">
                <div class="ui-state-error error-field-wrapper">
                <span class="ui-icon ui-icon-alert error-notice-icon">%s</span>%s
                </div>
            </div>
            ''') % (_('Error'),errors[0])
Exemplo n.º 6
0
 def column(self, name, content, cols, inner_cols=None, errors=True):
     "Wraps content in a Foundation column"
     error_content = ''
     if errors:
         error_content = self.error_small(name, cols=inner_cols)
     return HTML.tag(
         'div', tags.literal(content), error_content,
         class_='small-%d columns %s' % (
             cols, 'error' if error_content else ''))
Exemplo n.º 7
0
 def column(self, name, content, cols, inner_cols=None, errors=True):
     "Wraps content in a Foundation column"
     error_content = ''
     if errors:
         error_content = self.error_small(name, cols=inner_cols)
     return HTML.tag('div',
                     tags.literal(content),
                     error_content,
                     class_='small-%d columns %s' %
                     (cols, 'error' if error_content else ''))
Exemplo n.º 8
0
    def hidden_tag(self, *names):
        """
        Convenience for printing all hidden fields in a form inside a 
        hidden DIV. Will also render the CSRF hidden field.

        :versionadded: 0.4
        """
        inputs = [self.hidden(name) for name in names]
        inputs.append(self.csrf())
        return HTML.tag("div", tags.literal("".join(inputs)), style="display:none;")
Exemplo n.º 9
0
    def hidden_tag(self, *names):
        """
        Convenience for printing all hidden fields in a form inside a 
        hidden DIV. Will also render the CSRF hidden field.

        :versionadded: 0.4
        """
        inputs = [self.hidden(name) for name in names]
        inputs.append(self.csrf())
        return HTML.tag("div",
                        tags.literal("".join(inputs)),
                        style="display:none;")
Exemplo n.º 10
0
def linked_organization(org):
    organization = helpers.get_organization(org)
    if organization:
        return tags.literal(u'{icon} {link}'.format(
            icon=helpers.icon_html(
                organization['image_display_url'], alt='', inline=False),
            link=tags.link_to(organization['title'],
                              url_for(
                                  controller='organization',
                                  action='read',
                                  id=organization['name']))))
    return 'Not Existed'
Exemplo n.º 11
0
    def hidden_tag(self, *names):
        """
        Convenience for printing all hidden fields in a form inside a hidden
        DIV. Will also render the CSRF and referal hidden fields if they
        haven't been output explicitly already.

        :versionadded: 0.4
        """
        inputs = [self.hidden(name) for name in names]
        if not self._csrf_done:
            inputs.append(self.csrf())
        if not self._came_from_done:
            inputs.append(self.came_from())
        return HTML.tag(
            'div', tags.literal(''.join(inputs)), style='display:none;')
Exemplo n.º 12
0
    def hidden_tag(self, *names):
        """
        Convenience for printing all hidden fields in a form inside a hidden
        DIV. Will also render the CSRF and referal hidden fields if they
        haven't been output explicitly already.

        :versionadded: 0.4
        """
        inputs = [self.hidden(name) for name in names]
        if not self._csrf_done:
            inputs.append(self.csrf())
        if not self._came_from_done:
            inputs.append(self.came_from())
        return HTML.tag('div',
                        tags.literal(''.join(inputs)),
                        style='display:none;')
Exemplo n.º 13
0
    def _fetch_drupal_content(self, identifier, language=None, fallback=True):
        """ This helper fetches content from Drupal database using url alias identifier.
            Return content as dictionary containing language, title, body, node_id and edit link. None if not found.
            Tries to fallback to different language if fallback is True.

            Not cached.
        """
        if not language:
            language = helpers.lang()

        query = """SELECT url_alias.language, node.title, field_revision_body.body_value, node.nid from url_alias
                       INNER JOIN node ON node.nid = split_part(url_alias.source, '/', 2)::integer
                       INNER JOIN field_revision_body ON field_revision_body.entity_id = split_part(url_alias.source, '/', 2)::integer
                   WHERE url_alias.alias = %(identifier)s"""

        results = {}
        for content_language, title, body, node_id in self.engine.execute(
                query, {'identifier': identifier}):
            results[content_language] = {
                'language': content_language,
                'title': title,
                'body': body,
                'node_id': node_id
            }

        result = results.get(language, None)

        if not result and fallback and results:
            for fallback_language in self._language_fallback_order:
                result = results.get(fallback_language)
                if result:
                    break
            if not result:
                result = results.itervalues().next()

        if result:
            result['edit'] = urllib.quote("/%s/node/%s/edit" %
                                          (language, str(result['node_id'])))
            result['body'] = literal(result['body'])

        return result
Exemplo n.º 14
0
def show_linked_user(user, maxlength=0, avatar=20):
    if not isinstance(user, model.User):
        user_name = text_type(user)
        user = model.User.get(user_name)
        if not user:
            return user_name
    if user:
        name = user.name if model.User.VALID_NAME.match(user.name) else user.id
        displayname = user.display_name

        if maxlength and len(user.display_name) > maxlength:
            displayname = displayname[:maxlength] + '...'

        return tags.literal(u'{icon} {link}'.format(
            icon=h.gravatar(
                email_hash=user.email_hash,
                size=avatar
            ),
            link=tags.link_to(
                displayname,
                ('/user/show/' + name)
            )
        ))
Exemplo n.º 15
0
    def errorlist(self, name=None, **attrs):
        """
        Renders errors in a <ul> element. Unless specified in attrs, class
        will be "error".

        If no errors present returns an empty string.

        `name` : errors for name. If **None** all errors will be rendered.
        """

        if name is None:
            errors = self.all_errors()
        else:
            errors = self.errors_for(name)

        if not errors:
            return ''

        content = "\n".join(HTML.tag("li", error) for error in errors)
        
        if 'class_' not in attrs:
            attrs['class_'] = "error"

        return HTML.tag("ul", tags.literal(content), **attrs)
Exemplo n.º 16
0
    def errorlist(self, name=None, **attrs):
        """
        Renders errors in a <ul> element. Unless specified in attrs, class
        will be "error".

        If no errors present returns an empty string.

        `name` : errors for name. If **None** all errors will be rendered.
        """

        if name is None:
            errors = self.all_errors()
        else:
            errors = self.errors_for(name)

        if not errors:
            return ''

        content = "\n".join(HTML.tag("li", error) for error in errors)

        if 'class_' not in attrs:
            attrs['class_'] = "error"

        return HTML.tag("ul", tags.literal(content), **attrs)
Exemplo n.º 17
0
def _user_image(user, size):
    url = _get_user_image(user) or ""
    return literal(
        '<img src="%s" width="%s" height="%s" class="media-image" />' %
        (url, size, size))
Exemplo n.º 18
0
class TeamsCrudController(FilterCrudRestController):
    '''CrudController for Teams'''

    model = Team

    __table_options__ = {
        #'__omit_fields__': ['lesson_id'],
        '__field_order__': ['name', 'lesson', 'members', 'email', 'submissions'],
        '__omit_fields__': ['id', 'lesson_id'],
        '__search_fields__': ['id', 'lesson_id', 'name'],
        '__xml_fields__': ['name', 'lesson', 'members', 'email', 'submissions'],
        'name': lambda filler, obj:
            literal(u'<span title="id=%d">%s</span>' % (obj.id, obj.name)),
        'lesson': lambda filler, obj:
            link_to(obj.lesson.name, '../lessons/%d/edit' % obj.lesson.id, title='lesson_id=%d' % (obj.lesson_id)),
        'members': lambda filler, obj:
            ', '.join(link_to(student.display_name, '../students/%d/edit' % student.id)
                for student in obj.members),
        'email': _email_team,
        'submissions': _submissions,
        '__base_widget_args__': {'sortList': [[2, 0]]},
    }
    __form_options__ = {
        '__omit_fields__': ['id'],
        '__field_order__': ['id', 'name', 'lesson', 'members'],
        '__possible_field_names__': ['user_name', '_name', 'name', 'title'],
    }

    def _actions(self, obj):
        actions = super(TeamsCrudController, self)._actions(obj)
        actions.insert(1,
            (u'<a href="%d/rename" class="btn btn-mini" title="Rename Team with its member usernames">'
                u'<i class="icon-screenshot"></i></a>') % (obj.id))
        return actions

    def _bulk_actions(self):
        bulk_actions = super(TeamsCrudController, self)._bulk_actions()
        bulk_actions.append(
            (u'<a href="rename" class="btn" title="Rename all Teams with their member usernames">'
                u'<i class="icon-screenshot"></i>&nbsp;Rename all</a>'))
        return bulk_actions

    @expose()
    def rename(self, obj=None):
        if obj is not None:
            try:
                obj = EntityValidator(self.provider, self.model).to_python(obj)
            except Invalid:
                flash('Could not rename Team "%s"' % (obj), 'error')
                return redirect('../')
            else:
                oldname = obj.name
                newname = obj.rename()
                flash('Renamed Team "%s" to "%s"' % (oldname, newname), 'ok')
                return redirect('../')
        elif obj is None:
            q = self.query_modifier(Team.query)
            l = q.count()
            for t in q:
                t.rename()
            flash('Renamed %d teams' % (l), 'ok')
            return redirect('./')
        flash('Could not rename Team "%s"' % (obj), 'error')
        return redirect('./')
Exemplo n.º 19
0
Arquivo: plugin.py Projeto: haphut/ytp
def _user_image(user, size):
    url = _get_user_image(user) or ""
    return literal('<img src="%s" width="%s" height="%s" class="media-image" />' % (url, size, size))
Exemplo n.º 20
0
class TestsCrudController(FilterCrudRestController):
    '''CrudController for Tests'''

    model = Test

    __table_options__ = {
        '__omit_fields__': [
            'assignment_id',
            'argv',
            '_visible',
            'input_data',
            'output_data',
            'input_filename',
            'output_filename',
            'ignore_case',
            'ignore_returncode',
            'show_partial_match',
            'splitlines',
            'split',
            'comment_prefix',
            'separator',
            'strip_parse_errors',
            'parse_int',
            'parse_float',
            'float_precision',
            'sort',
            'user_id',
            'user',
            'testruns',
        ],
        '__field_order__': [
            'id',
            'assignment',
            'name',
            'visibility',
            '_timeout',
            'input_type',
            'output_type',
        ],
        '__search_fields__': ['id', 'assignment_id', 'name'],
        # '__headers__': {'_timeout': 'Timeout'},
        '__xml_fields__': ['assignment'],
        'assignment':
        lambda filler, obj: literal(
            u'''<a href="%d/test" class="btn btn-mini btn-inverse" title="Re-run all tests for this assignment"
                onclick="show_processing_modal('Testing %d Submission(s) in %d Test(s)...'); return true;">
                <i class="icon-repeat icon-white"></i>
            </a>&nbsp;''' %
            (obj.id, len(obj.assignment.submissions),
             len(obj.assignment.submissions) * len(obj.assignment.tests))) +
        link_to(obj.assignment.name,
                '../assignments/%d/edit' % obj.assignment.id,
                title='assignment_id=%d' % (obj.assignment_id)),
        '__base_widget_args__': {
            'sortList': [[1, 0], [2, 0], [3, 0]]
        },
    }
    __form_options__ = {
        '__omit_fields__': ['id', 'testruns', '_visible'],
        '__hide_fields__': ['user'],
        '__add_fields__': {
            'docs':
            twb.Label(
                'docs',
                text='Please read the <a href="%s">' % lurl('/docs/tests') +
                'Test configuration documentation</a>!',
                css_class='bold',
                escape=False),
            'ignore_opts':
            twb.Label('ignore_opts',
                      text='Output ignore options',
                      css_class='label'),
            'split_opts':
            twb.Label('split_opts',
                      text='Output splitting options',
                      css_class='label'),
            'parse_opts':
            twb.Label('parse_opts',
                      text='Output parsing options',
                      css_class='label'),
        },
        '__field_order__': [
            'id',
            'docs',
            'assignment',
            'name',
            'visibility',
            'input_data',
            'output_data',
            'input_type',
            'output_type',
            'input_filename',
            'output_filename',
            '_timeout',
            'argv',
            'ignore_opts',
            'ignore_case',
            'comment_prefix',
            'ignore_returncode',
            'show_partial_match',
            'split_opts',
            'splitlines',
            'split',
            'separator',
            'sort',
            'parse_opts',
            'strip_parse_errors',
            'parse_int',
            'parse_float',
            'float_precision',
        ],
        '__field_widget_types__': {
            # 'name': twb.TextField,
            'argv': twb.TextField,
            'input_filename': twb.TextField,
            'output_filename': twb.TextField,
            'input_type': twjc.ChosenSingleSelectField,
            'output_type': twjc.ChosenSingleSelectField,
            'visibility': twb.RadioButtonTable,
            # 'input_data': FileField,
            # 'output_data': FileField,
            'input_data': SourceEditor,
            'output_data': SourceEditor,
        },
        '__field_widget_args__': {
            'argv': {
                'help_text':
                u'''
Command line arguments

Possible variables are:
    {path}: Absolute path to temporary working directory
    {infile}: Full path to test input file
    {outfile}: Full path to test output file'''
            },
            'visibility':
            dict(
                help_text=
                u'Whether testrun results and/or data is shown to students or not',
                options=[('visible', 'Visible'), ('invisible', 'Invisible'),
                         ('result_only', 'Show only the testrun result'),
                         ('data_only', 'Show only the testrun data')],
                value='visible',
                prompt_text=None,
                cols=2,
                name='visibility',
                id='visibility'),
            '_timeout': {
                'help_text':
                u'Timeout value, leave empty to use value from assignment'
            },
            'input_type':
            dict(options=[('stdin', 'stdin'), ('file', 'file')],
                 value='stdin',
                 prompt_text=None),
            'output_type':
            dict(options=[('stdout', 'stdout'), ('file', 'file')],
                 value='stdout',
                 prompt_text=None),
            'input_data':
            dict(css_class='span7', rows=8),
            'output_data':
            dict(css_class='span7', rows=8),
            'input_filename':
            dict(css_class='span7'),
            'output_filename':
            dict(css_class='span7'),
            'argv':
            dict(css_class='span7'),
            'separator': {
                'help_text':
                u'The separator string used for splitting and joining, default is None (whitespace)'
            },
            'ignore_case': {
                'help_text': u'Call .lower() on output before comparison',
                'default': True
            },
            'ignore_returncode': {
                'help_text': u'Ignore test process returncode',
                'default': True
            },
            'comment_prefix': {
                'help_text': u'Ignore all lines that start with comment_prefix'
            },
            'show_partial_match': {
                'help_text': u'Recognize partial match and show to user',
                'default': True
            },
            'splitlines': {
                'help_text':
                u'Call .splitlines() on full output before comparison',
                'default': False
            },
            'split': {
                'help_text':
                u'Call .split() on full output of output before comparison or on each line from .splitlines() if splitlines is set'
            },
            'strip_parse_errors': {
                'help_text':
                u'Strip (True) or leave (False) unparsed fragments'
            },
            'parse_int': {
                'help_text':
                u'Parse every substring in output to int before comparison',
                'default': False
            },
            'parse_float': {
                'help_text':
                u'Parse every substring in output to float before comparison',
                'default': False
            },
            'float_precision': {
                'help_text':
                u'''The precision (number of decimal digits) to compare for floats'''
            },
            'parallel_sort': {
                'help_text':
                u'''If set, output will be sorted with the help of the thread ID inside of '[]' '''
            },
            'sort': {
                'help_text':
                u'''Sort output and test data before comparison. Parsing is performed first, if enabled.''',
                'default': False
            },
        },
    }
    __setters__ = {
        'test': ('null', lambda test: run_tests(test.assignment.submissions)),
    }
Exemplo n.º 21
0
class SheetsCrudController(FilterCrudRestController):
    '''CrudController for Sheets'''

    model = Sheet

    __table_options__ = {
        '__omit_fields__': [
            'id',
            'description',
            'event_id',
            'event',
            'teacher',
            '_teacher',
            'teacher_id',
            '_url',
            '_start_time',
            '_end_time',
        ],
        '__field_order__': [
            'sheet_id',
            'name',
            'public',
            'start_time',
            'end_time',
            'assignments',
            'submissions',
        ],
        '__search_fields__':
        ['id', 'sheet_id', 'name', ('assignments', 'assignment_id')],
        '__xml_fields__': ['sheet_id', 'name', 'assignments', 'submissions'],
        '__headers__': {
            'sheet_id': ''
        },
        'start_time':
        lambda filler, obj: h.strftime(obj.start_time, False),
        'end_time':
        lambda filler, obj: h.strftime(obj.end_time, False),
        'sheet_id':
        lambda filler, obj: literal(u'<span title="sheet_id=%d">%d</span>' %
                                    (obj.sheet_id, obj.sheet_id)),
        'name':
        lambda filler, obj: literal(u'<span title="sheet_id=%d">%s</span>' %
                                    (obj.sheet_id, obj.name)),
        'assignments':
        lambda filler, obj: ', '.join(
            link_to(ass.name, '../assignments/%d/edit' % ass.id)
            for ass in obj.assignments),
        'submissions':
        _submissions,
        '__base_widget_args__': {
            'sortList': [[1, 0]]
        },
    }
    __form_options__ = {
        '__omit_fields__': [
            'id',
            '_url',
            'assignments',
            'teacher',
            '_teacher',
        ],
        '__hide_fields__': ['event'],
        '__field_order__': [
            'id',
            'sheet_id',
            'name',
            'description',
            'public',
            '_start_time',
            '_end_time',
        ],
        '__field_widget_args__': {
            '_start_time': {
                'help_text': u'Leave empty to use value from event',
            },
            '_end_time': {
                'help_text': u'Leave empty to use value from event',
            },
            'sheet_id': {
                'label':
                u'Sheet Id',
                'help_text':
                u'This id will be part of the url and has to be unique for the parent event',
            },
            'public': {
                'help_text': u'Make sheet visible for students',
            },
        },
        '__require_fields__': ['sheet_id'],
    }
    __setters__ = {
        'test': ('null', lambda sheet: run_tests(
            (submission for assignment in sheet.assignments
             for submission in assignment.submissions))),
    }

    def _actions(self, obj):
        actions = super(SheetsCrudController, self)._actions(obj)
        actions.insert(
            1, u'''
<a href="%d/test" class="btn btn-mini btn-inverse" title="Re-run all tests for this assignment"
    onclick="show_processing_modal('Testing %d Submission(s) in %d Test(s)...'); return true;">
    <i class="icon-repeat icon-white"></i>
</a>''' % (obj.id,
           sum((len(assignment.submissions)
                for assignment in obj.assignments)),
           sum((len(assignment.submissions) * len(assignment.tests)
                for assignment in obj.assignments))))
        return actions
Exemplo n.º 22
0
class AssignmentsCrudController(FilterCrudRestController):
    '''CrudController for Assignments'''

    model = Assignment

    __table_options__ = {
        '__omit_fields__': [
            'id',
            'event_id',
            '_event',
            '_url',
            'teacher_id',
            'teacher',
            #'allowed_languages',
            '_teacher',
            'description',
            'tests',
            'show_compiler_msg',
            '_start_time',
            '_end_time',
            'submission_filename',
            'submission_template',
            'submission_scaffold_show',
            'submission_scaffold_head',
            'submission_scaffold_foot',
            '_lti',
        ],
        '__field_order__': [
            'sheet_id',
            'sheet',
            'assignment_id',
            'name',
            'public',
            'start_time',
            'end_time',
            'timeout',
            'allowed_languages',
            'submissions',
        ] + (['lti_url'] if _lti else []),
        '__search_fields__': ['id', 'sheet_id', 'assignment_id', 'name'],
        '__xml_fields__': [
            'name', 'sheet_id', 'assignment_id', 'sheet', 'allowed_languages',
            'submissions', 'lti_url'
        ],
        '__headers__': {
            'sheet_id': '',
            'assignment_id': '',
        },
        'start_time':
        lambda filler, obj: h.strftime(obj.start_time, False),
        'end_time':
        lambda filler, obj: h.strftime(obj.end_time, False),
        'name':
        lambda filler, obj: literal(u'<span title="assignment_id=%d">%s</span>'
                                    % (obj.assignment_id, obj.name)),
        'sheet_id':
        lambda filler, obj: literal(u'<span title="sheet_id=%d">%d</span>' %
                                    (obj.sheet_id, obj.sheet_id)),
        'assignment_id':
        lambda filler, obj: literal(u'<span title="assignment_id=%d">%d</span>'
                                    % (obj.assignment_id, obj.assignment_id)),
        'sheet':
        lambda filler, obj: link_to(obj.sheet.name,
                                    '../sheets/%d/edit' % obj.sheet.id,
                                    title='sheet_id=%d' % (obj.sheet_id)),
        'allowed_languages':
        lambda filler, obj: ', '.join(
            link_to(l.name, '/languages/%d' % l.id)
            for l in obj.allowed_languages),
        'lti_url':
        lambda filler, obj: u'<span title="%s:%s">%s</span>' %
        (obj.lti.oauth_key, obj.lti.oauth_secret,
         url(obj.lti_url, qualified=True)) if obj.lti else u'',
        'submissions':
        _submissions,
        '__base_widget_args__': {
            'sortList': [[1, 0], [3, 0]]
        },
    }
    __form_options__ = {
        '__omit_fields__': [
            'id',
            'tests',
            'submissions',
            '_event',
            'teacher',
            '_url',
            '_teacher',
            '_lti',
        ],
        '__add_fields__': {
            'submission_note':
            twb.Label(
                'submission_note',
                label='Note',
                css_class='bold',
                text='For obvious reasons, it might not be the best idea to '
                'pre-define submission data here, '
                'when multiple languages are allowed.'),
        },
        '__field_order__': [
            'id',
            'sheet',
            'assignment_id',
            'name',
            'description',
            'public',
            '_start_time',
            '_end_time',
            'timeout',
            'allowed_languages',
            'show_compiler_msg',
            'submission_note',
            'submission_filename',
            'submission_template',
            'submission_scaffold_show',
            'submission_scaffold_head',
            'submission_scaffold_foot',
        ],
        '__field_widget_types__': {
            'submission_template': SourceEditor,
            'submission_scaffold_head': SourceEditor,
            'submission_scaffold_foot': SourceEditor,
        },
        '__field_widget_args__': {
            'assignment_id': {
                'label':
                u'Assignment Id',
                'help_text':
                u'Will be part of the url and has to be unique for the parent sheet',
            },
            'public': {
                'help_text': u'Make assignment visible for students',
            },
            '_start_time': {
                'help_text': u'Leave empty to use value from sheet',
            },
            '_end_time': {
                'help_text': u'Leave empty to use value from sheet',
            },
            'timeout': {
                'help_text':
                u'Default timeout value for test cases, leave empty for no time limit',
            },
            'show_compiler_msg': {
                'help_text':
                u'Show error messages or warnings from the compiler run',
            },
            'submission_filename': {
                'help_text': u'Default filename for submission',
            },
            'submission_template': {
                'help_text': u'Template for submission source body',
                'css_class': 'span7',
                'cols': 80,
                'rows': 6,
            },
            'submission_scaffold_show': {
                'help_text':
                u'Whether to show head and foot scaffold to student',
            },
            'submission_scaffold_head': {
                'help_text': u'Enforced head for submission source',
                'css_class': 'span7',
                'cols': 80,
                'rows': 6,
            },
            'submission_scaffold_foot': {
                'help_text': u'Enforced foot for submission source',
                'css_class': 'span7',
                'cols': 80,
                'rows': 6,
            },
        },
        '__require_fields__': ['assignment_id', 'sheet'],
    }
    __setters__ = {
        'test': ('null', lambda assignment: run_tests(assignment.submissions)),
    }

    def _actions(self, obj):
        actions = super(AssignmentsCrudController, self)._actions(obj)
        actions.insert(
            1, u'''
<a href="%d/test" class="btn btn-mini btn-inverse" title="Re-run all tests for this assignment"
    onclick="show_processing_modal('Testing %d Submission(s) in %d Test(s)...'); return true;">
    <i class="icon-repeat icon-white"></i>
</a>''' % (obj.id, len(
                obj.submissions), len(obj.submissions) * len(obj.tests)))
        return actions