Beispiel #1
0
class ChoiceInteraction(ductmodels.BaseDuctModel):
    ns = 'http://wikiotics.org/ns/2011/flashcards'
    nsmap = {'flashcards': ns}

    prompt = ductmodels.Attribute(validator=_column_validator('+'))
    answer = ductmodels.Attribute(validator=_column_validator(''))

    def get_columns_referenced(self):
        return [int(a) for a in (self.prompt.split(',') + [self.answer])]
Beispiel #2
0
class WikiBlobElement(ductmodels.TextBlobElement):
    allowed_markup_languages = ('creole-1.0', 'ductus-html5',)
    allowed_natural_languages = (None, '') + tuple(settings.DUCTUS_NATURAL_LANGUAGES)
    markup_language = ductmodels.Attribute(validator=ductmodels.allowed_values_attribute_validator(allowed_markup_languages))
    natural_language = ductmodels.Attribute(validator=ductmodels.allowed_values_attribute_validator(allowed_natural_languages), optional=True, blank_is_null=True)

    def __init__(self):
        # fixme: if Attribute had a "default" argument, we wouldn't need to
        # override this constructor to set such a default
        super(WikiBlobElement, self).__init__()
        self.markup_language = "ductus-html5"
Beispiel #3
0
class AudioLessonInteraction(ductmodels.BaseDuctModel):
    ns = 'http://wikiotics.org/ns/2011/flashcards'
    nsmap = {'flashcards': ns}

    audio = ductmodels.Attribute(validator=_column_validator(''))
    transcript = ductmodels.Attribute(validator=_column_validator('?'), optional=True)

    def get_columns_referenced(self):
        rv = [int(self.audio)]
        if self.transcript:
            rv.append(int(self.transcript))
        return rv
Beispiel #4
0
class FlashcardDeck(ductmodels.DuctModel):
    ns = 'http://wikiotics.org/ns/2011/flashcards'
    nsmap = {'flashcards': ns}

    cards = ductmodels.ArrayElement(ductmodels.ResourceElement(Flashcard))
    headings = ductmodels.ArrayElement(ductmodels.TextElement())
    column_order = ductmodels.Attribute(validator=_column_order_validator, optional=True)

    interactions = ductmodels.OptionalArrayElement(ductmodels.ResourceElement(ChoiceInteraction, AudioLessonInteraction, StoryBookInteraction))

    # dividers will be placed just before each index given here.  they are
    # zero-indexed to match row numbers, e.g., a divider value of 3 means the
    # divider will be placed before row 3 (visually before 4 on the editor)
    #   * there is never an explicit divider before the first card (index 0),
    #   though one is implied, obviously.
    #   * there is never a divider after the final row (but one is implied)
    #   * there are never two dividers in the same location
    #   * dividers must be specified in order
    dividers = ductmodels.Attribute(validator=_divider_validator, optional=True)

    def validate(self, strict=True):
        super(FlashcardDeck, self).validate(strict)

        headings_length = len(self.headings)

        if headings_length == 0:
            raise ductmodels.ValidationError("there are no sides")

        if strict:
            if any(len(card.get().sides) != headings_length for card in self.cards):
                raise ductmodels.ValidationError("each card must have the same number of sides as headers given")

        nonempty_headings = [h.text for h in self.headings if h.text]
        if len(frozenset(nonempty_headings)) != len(nonempty_headings):
            raise ductmodels.ValidationError("all nonempty headings must be unique")

        r = set(range(headings_length))
        for interaction in self.interactions.array:
            if not all(c in r for c in interaction.get().get_columns_referenced()):
                raise ductmodels.ValidationError("all referenced columns must exist in the FlashcardDeck")

        if self.dividers:
            first_divider_index = int(self.dividers.partition(',')[0])
            last_divider_index = int(self.dividers.rpartition(',')[2])
            if first_divider_index < 1 or last_divider_index >= len(self.cards):
                raise ductmodels.ValidationError("divider index out of range")

        if self.column_order:
            highest_column_index = max(int(a) for a in self.column_order.split(','))
            if highest_column_index >= headings_length:
                raise ductmodels.ValidationError("column index out of range")
Beispiel #5
0
class Picture(ductmodels.DuctModel):
    ns = 'http://wikiotics.org/ns/2009/picture'
    blob = ductmodels.TypedBlobElement(
        allowed_mime_types=allowed_picture_types)
    credit = CreditElement()
    rotation = ductmodels.Attribute(optional=True,
                                    blank_is_null=True,
                                    validator=rotation_validator)

    def patch_from_blueprint(self, blueprint, save_context):
        ductmodels.blueprint_expects_dict(blueprint)
        blueprint = dict(blueprint)
        if "credit" in blueprint:
            del blueprint["credit"]

        super(Picture, self).patch_from_blueprint(blueprint, save_context)

        if 'flickr_photo_id' in blueprint:
            flickr_photo_id = blueprint['flickr_photo_id']
            flickr_photo_id = ductmodels.blueprint_cast_to_string(
                flickr_photo_id)
            # FIXME TEMPORARY
            from ductus.modules.picture.flickr import FlickrUriHandler
            url = 'http://flickr.com/photos/0/%s' % flickr_photo_id
            if FlickrUriHandler.handles(url):
                fuh = FlickrUriHandler(url)
                fuh.validate()
                fuh.save(save_context, picture=self, return_before_saving=True)

        if 'rotation' in blueprint:
            rotation = blueprint['rotation']
            rotation = ductmodels.blueprint_cast_to_string(rotation)
            rotation_validator(rotation)
            self.rotation = rotation

        if 'net_rotation' in blueprint:
            net_rotation = blueprint['net_rotation']
            net_rotation = ductmodels.blueprint_cast_to_string(net_rotation)
            rotation_validator(net_rotation)
            self.rotation = str(
                (int(self.rotation or 0) + int(net_rotation or 0)) % 360)