Example #1
0
class FormQuestion(Question):
    """
    FormQuestion's defines a question with multiple fields that can be
    naturally represented in a web form. A FormQuestion thus expect a response
    """
    form_data = models.StreamField(
        [
            #('numeric', blocks.NumericAnswerBlock()),
            #('boolean', blocks.BooleanAnswerBlock()),
            #('string', blocks.StringAnswerBlock()),
            #('date', blocks.DateAnswerBlock()),
            #('file', blocks.TextFileAnswerBlock()),
            #('script', blocks.ScriptGraderAnswerBlock()),
            (
                'content',
                blocks.StreamBlock([
                    ('description', blocks.RichTextBlock()),
                    #('code', blocks.CodeBlock()),
                    #('markdown', blocks.MarkdownBlock()),
                    ('image', blocks.ImageChooserBlock()),
                    ('document', blocks.DocumentChooserBlock()),
                    ('page', blocks.PageChooserBlock()),
                ])),
        ],
        verbose_name=_('Fields'),
        help_text=_(
            'You can insert different types of fields for the student answers. '
            'This works as a simple form that accepts any combination of the'
            'different types of answer fields.'))

    def clean(self):
        super().clean()
        data = list(self.form_values())
        if not data:
            raise ValidationError({
                'body':
                _('At least one form entry is necessary.'),
            })

        # Test if ref keys are unique: when we implement this correctly, there
        # will have a 1 in 10**19 chance of collision. So we wouldn't expect
        # this to ever fail.
        ref_set = {value['ref'] for value in data}
        if len(ref_set) < len(data):
            raise ValidationError({
                'body':
                _('Answer block ref keys are not unique.'),
            })

    def submit(self, raw_data=None, **kwargs):
        # Transform all values received as strings and normalize them to the
        # correct python objects.
        if raw_data is not None:
            response_data = {}
            children = self.stream_children_map()
            for key, value in raw_data.items():
                child = children[key]
                block = child.block
                blk_value = child.value
                response_data[key] = block.normalize_response(blk_value, value)
            kwargs['response_data'] = response_data
        return super().submit(**kwargs)

    def stream_children(self):
        """
        Iterates over AnswerBlock based stream children.
        """

        return (blk for blk in self.form_data if blk.block_type != 'content')

    def stream_items(self):
        """
        Iterates over pairs of (key, stream_child) objects.
        """

        return ((blk.value['ref'], blk) for blk in self.stream_children())

    def form_values(self):
        """
        Iterate over all values associated with the question AnswerBlocks.
        """

        return (blk.value for blk in self.stream_children())

    def form_blocks(self):
        """
        Iterate over all AnswerBlock instances in the question.
        """

        return (blk.block for blk in self.stream_children())

    def stream_child(self, key, default=NOT_PROVIDED):
        """
        Return the StreamChild instance associated with the given key.

        If key is not found, return the default value, if given, or raises a
        KeyError.
        """

        for block in self.form_data:
            if block.block_type != 'content' and block.value['ref'] == key:
                return block

        if default is NOT_PROVIDED:
            raise KeyError(key)
        return default

    def form_block(self, key, default=NOT_PROVIDED):
        """
        Return the AnswerBlock instance for the given key.
        """

        try:
            return self.stream_child(key).block
        except KeyError:
            if default is NOT_PROVIDED:
                raise
            return default

    def form_value(self, ref, default=NOT_PROVIDED):
        """
        Return the form data for the given key.
        """

        try:
            return self.stream_child(key).value
        except KeyError:
            if default is NOT_PROVIDED:
                raise
            return default

    def stream_children_map(self):
        """
        Return a dictionary mapping keys to the corresponding stream values.
        """

        return {blk.value['ref']: blk for blk in self.form_data}

    # Serving pages and routing
    @srvice.route(r'^submit-response/$')
    def route_submit(self, client, fileData=None, **kwargs):
        """
        Handles student responses via AJAX and a srvice program.
        """

        data = {}
        file_data = fileData or {}
        for key, value in kwargs.items():
            if key.startswith('response__') and value:
                key = key[10:]  # strips the heading 'response__'
                data[key] = value

                # We check the stream child type and take additional measures
                # depending on the type
                stream_child = self.stream_child(key)
                if stream_child.block_type == 'file':
                    data[key] = file_data.get(value[0], '')

        super().route_submit(
            client=client,
            response_context=kwargs['response_context'],
            raw_data=data,
        )

    def get_response_form(self):
        block = self.form_data[0]
        return block.render()

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        context['form'] = self.get_response_form()
        return context

    # Wagtail admin
    content_panels = Question.content_panels[:]
    content_panels.insert(-1, panels.StreamFieldPanel('form_data'))
Example #2
0
from codeschool import blocks

RESOURCE_BLOCKS = [
    ('paragraph', blocks.RichTextBlock()),
    ('image', blocks.ImageChooserBlock()),
    ('embed', blocks.EmbedBlock()),
    # ('markdown', blocks.MarkdownBlock()),
    ('url', blocks.URLBlock()),
    ('text', blocks.TextBlock()),
    ('char', blocks.CharBlock()),
    # ('ace', blocks.AceBlock()),
    ('bool', blocks.BooleanBlock()),
    ('doc', blocks.DocumentChooserBlock()),
    # ('snippet', blocks.SnippetChooserBlock(GradingMethod)),
    ('date', blocks.DateBlock()),
    ('time', blocks.TimeBlock()),
    ('stream',
     blocks.StreamBlock([('page', blocks.PageChooserBlock()),
                         ('html', blocks.RawHTMLBlock())])),
]