Beispiel #1
0
class ContactSchema(OriginContactSchema):

    public_phone = colander.SchemaNode(
        DictSchemaType(),
        validator=colander.All(
            PhoneValidator()),
        missing="",
        widget=PhoneWidget(css_class="contact-phone"),
        title=_('Public phone'),
        description=_("Indicate the public phone number. Only spaces are allowed as separator for phone numbers.")
        )

    professional_phone = colander.SchemaNode(
        DictSchemaType(),
        validator=colander.All(
            PhoneValidator()),
        missing="",
        widget=PhoneWidget(css_class="contact-phone"),
        title=_('Professional phone'),
        description=_("Indicate the professional phone number. Only spaces are allowed as separator for phone numbers.")
        )

    person_to_contact = colander.SchemaNode(
        colander.String(),
        title=_('Person to contact'),
        )

    @invariant
    def contact_invariant(self, appstruct):
        pass
Beispiel #2
0
class OrganizationSchema(GroupSchema):
    """Schema for Organization"""

    name = NameSchemaNode(editing=context_is_a_organization, )

    function = colander.SchemaNode(
        colander.String(),
        widget=function_widget,
        title=_('Function'),
    )

    logo = colander.SchemaNode(
        ObjectData(Image),
        widget=get_file_widget(),
        required=False,
        missing=None,
        title=_('Logo'),
    )

    email = colander.SchemaNode(
        colander.String(),
        widget=EmailInputWidget(),
        validator=colander.All(colander.Email(), colander.Length(max=100)),
        missing='',
        title=_('Email'),
    )

    phone = colander.SchemaNode(
        DictSchemaType(),
        validator=colander.All(PhoneValidator()),
        missing="",
        widget=PhoneWidget(css_class="contact-phone"),
        title=_("Phone number"),
        description=
        _("Indicate the phone number. Only spaces are allowed as separator for phone numbers."
          ))

    fax = colander.SchemaNode(
        DictSchemaType(),
        validator=colander.All(
            PhoneValidator(
                _('${phone} fax number not valid for the selected country (${country})'
                  ))),
        widget=PhoneWidget(css_class="contact-fax"),
        title=_("Fax"),
        missing='',
        description=
        _("Indicate the fax number. Only spaces are allowed as separator for fax numbers."
          ))

    managers = colander.SchemaNode(
        colander.Set(),
        widget=members_choice,
        title=_('Managers'),
    )
Beispiel #3
0
class CreationCulturelleApplicationSchema(VisualisableElementSchema):
    """Schema for application configuration."""

    name = NameSchemaNode(editing=context_is_a_root, )

    titles = colander.SchemaNode(
        colander.Sequence(),
        colander.SchemaNode(colander.String(), name=_("Title")),
        widget=SequenceWidget(),
        default=DEFAULT_TITLES,
        title=_('List of titles'),
    )

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        validator=colander.All(keywords_validator),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        title=_('Categories'),
    )

    organizations = colander.SchemaNode(
        colander.Sequence(),
        omit(
            OrganizationSchema(factory=Organization,
                               editable=True,
                               name=_('Organization'),
                               widget=SimpleMappingWidget(
                                   css_class='object-well default-well'),
                               omit=['managers']), ['_csrf_token_']),
        widget=organizations_choice,
        title=_('Organizations'),
    )
Beispiel #4
0
class SearchableEntitySchema(Schema):
    typ_factory = ObjectData

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        validator=colander.All(keywords_validator),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        title=_('Categories'),
        description=_('Indicate the category of the event. Please specify a second keyword level for each category chosen.')
        )

    metadata = omit(MetadataSchema(widget=SimpleMappingtWidget(
                                mapping_css_class='controled-form'
                                                  ' object-well default-well hide-bloc',
                                control_css_class='alert alert-success',
                                ajax=True,
                                activator_css_class="glyphicon glyphicon-cog",
                                activator_title=_('Manage metadata'))),
                        ["_csrf_token_"])

    def deserialize(self, cstruct=colander.null):
        appstruct = super(SearchableEntitySchema, self).deserialize(cstruct)
        if 'metadata' not in appstruct:
            return appstruct

        metadata = appstruct.pop('metadata', {})
        appstruct.update(metadata)
        return appstruct
Beispiel #5
0
class KeywordsConfSchema(Schema):

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        validator=colander.All(keywords_validator),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        title=_('Keywords'),
    )

    can_add_keywords = colander.SchemaNode(
        colander.Boolean(),
        widget=deform.widget.CheckboxWidget(),
        label=_('Authorize the addition of keywords'),
        title='',
        default=True,
        missing=True)

    @invariant
    def contact_invariant(self, appstruct):
        can_add_keywords = appstruct.get('can_add_keywords', 'false')
        can_add_keywords = False if can_add_keywords == 'false' else True
        keywords = appstruct.get('tree', colander.null)
        if not can_add_keywords and keywords is colander.null:
            raise colander.Invalid(self,
                                   _('You must enter at least one keyword.'))
Beispiel #6
0
class WebAdvertisingSchema(AdvertisingSchema):
    """Schema for Web advertising"""

    name = NameSchemaNode(editing=context_is_a_webadvertising, )

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        missing=None,
        title=_('Categories'),
    )

    home_page = colander.SchemaNode(
        colander.Boolean(),
        default=False,
        missing=False,
        label=_('Not'),
        title=None,
        description=_('Home page'),
    )

    picture = colander.SchemaNode(
        ObjectData(File),
        widget=get_file_widget(item_css_class="advertising-file-content",
                               css_class="file-content",
                               file_type=['image', 'flash']),
        title=_('Advertisement file'),
        description=_("Only image and flash files are supported."),
        missing=None)

    html_content = colander.SchemaNode(
        colander.String(),
        widget=RichTextWidget(item_css_class="advertising-html-content",
                              css_class="html-content-text"),
        title=_("Or HTML content"),
        missing="")

    advertisting_url = colander.SchemaNode(colander.String(),
                                           title=_('URL'),
                                           missing="#")

    positions = colander.SchemaNode(colander.Set(),
                                    widget=advertisting_widget,
                                    title=_('Positions'))

    @invariant
    def content_invariant(self, appstruct):
        if not (appstruct['html_content'] or appstruct['picture']):
            raise colander.Invalid(self, _('Content will be defined.'))

    @invariant
    def banner_invariant(self, appstruct):
        positions = appstruct['positions']
        if positions:
            for position in positions:
                ADVERTISING_CONTAINERS[position]['validator'](
                    self.get('picture'), appstruct)
class FindMetadataFilter(MetadataFilter):

    content_types = colander.SchemaNode(
        typ=DictSchemaType(),
        widget=keyword_widget,
        default={},
        missing={},
        title=_('Content type'),
    )
Beispiel #8
0
class FilterSchema(FilterSchemaOrigine):

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        widget=core.keyword_widget,
        title=_('Categories'),
        description=_(
            'You can select the categories of the contents to be displayed.'),
        default=DEFAULT_TREE,
        missing=None,
    )
Beispiel #9
0
class SearchableEntitySchema(Schema):

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        validator=colander.All(keywords_validator),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        title=_('Keywords'),
        description=
        _('Indicate keywords. You can specify a second keyword level for each keyword chosen.'
          ))
Beispiel #10
0
class KeywordsConfSchema(Schema):

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        validator=colander.All(keywords_validator),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        title=_('Categories'),
        )

    keywords_mapping = omit(KeywordsMappingSchema(widget=SimpleMappingWidget()),
                            ["_csrf_token_"])
Beispiel #11
0
class BriefSchema(SearchableEntitySchema):
    """Brief schema"""

    name = NameSchemaNode(
        editing=context_is_a_brief,
        )

    title = colander.SchemaNode(
        colander.String(),
        widget=TextInputWidget(),
        title=_('Title')
        )

    picture = colander.SchemaNode(
        ObjectData(Image),
        widget=picture_widget,
        title=_('Picture'),
        )

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        missing=DEFAULT_TREE,
        title=_('Categories'),
        )

    details = colander.SchemaNode(
        colander.String(),
        widget=RichTextWidget(),
        title=_("Details")
        )

    informations = colander.SchemaNode(
        colander.String(),
        widget=RichTextWidget(),
        title=_("Additional information")
        )

    publication_number = colander.SchemaNode(
        colander.Integer(),
        default=publication_number_value,
        missing=publication_number_value,
        title=_('Publication number'),
        )
Beispiel #12
0
class ContentsByKeywordsSchema(Schema):

    content_types = colander.SchemaNode(
        colander.Set(),
        widget=content_types_choices,
        title=_('Types'),
        description=_('You can select the content types to be displayed.'),
        default=default_content_types,
        missing=default_content_types)

    states = colander.SchemaNode(
        colander.Set(),
        widget=states_choices,
        title=_('States'),
        description=_(
            'You can select the states of the contents to be displayed.'),
        default=['published'],
        missing=['published'])

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        widget=core.keyword_widget,
        default=DEFAULT_TREE,
        title=_('Keywords'),
        description=
        _('Indicate keywords. You can specify a second keyword level for each keyword chosen.'
          ))

    author = colander.SchemaNode(
        ObjectType(),
        widget=authors_choices,
        title=_('Author'),
        description=_(
            'You can enter the author name of the contents to be displayed.'),
        default=None,
        missing=None)

    dates = omit(
        PublicationDates(widget=SimpleMappingWidget(css_class="filter-block"
                                                    " object-well"
                                                    " default-well")),
        ["_csrf_token_"])
Beispiel #13
0
class ContactSchema(Schema):

    email = colander.SchemaNode(
        colander.String(),
        widget=EmailInputWidget(),
        missing="",
        validator=colander.All(colander.Email(), colander.Length(max=100)),
    )

    phone = colander.SchemaNode(
        DictSchemaType(),
        missing="",
        validator=colander.All(PhoneValidator()),
        widget=PhoneWidget(css_class="contact-phone"),
        title=_('Phone'),
        description=
        _("Indicate the phone number. Only spaces are allowed as separator for phone numbers."
          ))

    surtax = colander.SchemaNode(
        colander.String(),
        missing="0",
        widget=TextInputWidget(item_css_class="hide-bloc"),
        default="0",
        title=_('Surtax'),
        description=
        _('Indicate the amount of the surcharge (for the premium-rate number).'
          ),
    )

    fax = colander.SchemaNode(
        DictSchemaType(),
        validator=colander.All(
            PhoneValidator(
                _('${phone} fax number not valid for the selected country (${country})'
                  ))),
        missing="",
        widget=PhoneWidget(css_class="contact-fax"),
        title=_('Fax'),
        description=
        _("Indicate the fax number. Only spaces are allowed as separator for fax numbers."
          ))

    website = colander.SchemaNode(
        colander.String(),
        missing="",
        title=_('Website'),
    )

    @invariant
    def contact_invariant(self, appstruct):
        appstruct_copy = appstruct.copy()
        appstruct_copy.pop('surtax')
        if 'title' in appstruct_copy:
            appstruct_copy.pop('title')

        if not any(v != "" and v != colander.null
                   for v in list(appstruct_copy.values())):
            raise colander.Invalid(self, _('One value must be entered.'))

        if 'phone' in appstruct and appstruct['phone'] and \
            ('surtax' not in appstruct or \
             'surtax' in appstruct and not appstruct['surtax']):
            raise colander.Invalid(self, _('Surtax field must be filled in.'))
Beispiel #14
0
class CulturalEventSchema(VisualisableElementSchema, SearchableEntitySchema):
    """Schema for cultural event"""

    name = NameSchemaNode(editing=context_is_a_cultural_event, )

    title = colander.SchemaNode(
        colander.String(),
        title=_('Title'),
        description=_('Enter a title for your announcement.'))

    description = colander.SchemaNode(
        colander.String(),
        widget=LimitedTextAreaWidget(rows=5,
                                     cols=30,
                                     limit=350,
                                     alert_values={'limit': 350},
                                     css_class="ce-field-description"),
        title=_("Brief description"),
        description=_('Describe succinctly the event.'),
    )

    details = colander.SchemaNode(
        colander.String(),
        widget=RichTextWidget(css_class="ce-field-details"),
        missing="",
        description=_('You can describe in detail the event. (Recommended)'),
        title=_('Details'),
        oid='detailed_description')

    artists_ids = colander.SchemaNode(
        colander.Set(),
        widget=artists_choice,
        title=_('Artists'),
        description=_('You can enter the artists names.'),
        missing=[])

    artists = colander.SchemaNode(
        colander.Sequence(),
        omit(
            select(
                ArtistInformationSheetSchema(
                    editable=True,
                    factory=ArtistInformationSheet,
                    omit=('id', ),
                    widget=SimpleMappingWidget(
                        css_class='artist-data object-well'
                        ' default-well'),
                    name=_('artist')), [
                        'id', 'origin_oid', 'title', 'description', 'picture',
                        'biography', 'is_director'
                    ]), ['_csrf_token_', '__objectoid__']),
        widget=SequenceWidget(css_class='artists-values',
                              template='lac:views/'
                              'templates/sequence_modal.pt',
                              item_template='lac:views/'
                              'templates/sequence_modal_item.pt'),
        title=_('Artists'),
    )

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        validator=colander.All(keywords_validator),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        title=_('Categories'),
        description=
        _('Indicate the category of the event. Please specify a second keyword level for each category chosen.'
          ))

    contacts = colander.SchemaNode(
        colander.Sequence(),
        omit(
            select(
                ContactSchema(
                    name='contact',
                    widget=SimpleMappingWidget(
                        css_class='contact-well object-well default-well')),
                ['phone', 'surtax', 'email', 'website', 'fax']),
            ['_csrf_token_']),
        widget=SimpleSequenceWidget(
            add_subitem_text_template=_('Add a new contact'),
            remove_subitem_text_template=_('Remove the contact')),
        title=_('Contacts'),
        description=
        _('Indicate contacts of the event. If none is specified, venues contacts will be assigned to the event.'
          ),
        oid='contacts')

    picture = colander.SchemaNode(
        ObjectData(Image),  #Pontus
        widget=picture_widget,
        title=_('Picture'),
        description=_(
            'You can choose a picture to illustrate your announcement.'),
        missing=None,
    )

    schedules = colander.SchemaNode(
        colander.Sequence(),
        omit(
            select(
                ScheduleSchema(
                    name='schedule',
                    factory=Schedule,
                    editable=True,
                    widget=SimpleMappingWidget(
                        css_class='schedule-well object-well default-well'),
                    omit=('venue', )),
                ['dates', 'venue', 'ticket_type', 'price', 'ticketing_url']),
            ['_csrf_token_']),
        widget=SimpleSequenceWidget(
            min_len=1,
            add_subitem_text_template=_('Add a new schedule'),
            remove_subitem_text_template=_('Remove the schedule')),
        description=
        _('If the event takes place in several locations, add a session by clicking the plus sign on the bottom right of the block "sessions".'
          ),
        title=_('Schedules'),
    )

    selling_tickets = colander.SchemaNode(
        colander.Boolean(),
        widget=deform.widget.CheckboxWidget(),
        label=_('Selling tickets'),
        title='',
        description=
        _('Check this box if you want to be accompanied or to receive information on selling tickets online.'
          ),
        default=False,
        missing=False)

    ticketing_url = colander.SchemaNode(
        colander.String(),
        title=_('Ticketing URL'),
        description=_('For the online ticket sales.'),
        missing=None)

    accept_conditions = colander.SchemaNode(
        colander.Boolean(),
        widget=conditions_widget,
        label=_('I have read and accept the terms and conditions'),
        title='',
        missing=False)

    @invariant
    def contacts_invariant(self, appstruct):
        if not appstruct['contacts'] and \
           any(not s['venue']['other_conf']['contacts']
               for s in appstruct['schedules']):
            raise colander.Invalid(
                self.get('contacts'),
                _("Event's contact or all venues's contacts must be defined."))
Beispiel #15
0
class PersonSchema(VisualisableElementSchema, UserSchema,
                   SearchableEntitySchema):
    """Schema for Person"""

    name = NameSchemaNode(editing=context_is_a_person, )

    function = colander.SchemaNode(colander.String(),
                                   widget=deform.widget.TextInputWidget(),
                                   title=_('Function'),
                                   missing='')

    description = colander.SchemaNode(colander.String(),
                                      widget=LimitedTextAreaWidget(
                                          rows=5,
                                          cols=30,
                                          limit=1200,
                                          alert_values={'limit': 1200}),
                                      title=_("Description"),
                                      missing="")

    tree = colander.SchemaNode(
        typ=DictSchemaType(),
        widget=keyword_widget,
        default=DEFAULT_TREE,
        missing=DEFAULT_TREE,
        title=_('Topics of interest'),
        description=
        _('Indicate keywords. You can specify a second keyword level for each keyword chosen.'
          ))

    email = colander.SchemaNode(colander.String(),
                                validator=colander.All(
                                    colander.Email(), email_validator,
                                    colander.Length(max=100)),
                                title=_('Login (email)'))

    picture = colander.SchemaNode(
        ObjectData(Image),
        widget=picture_widget,
        title=_('Picture'),
        description=
        _('You see a square on the top left of the image if it exceeds the maximum'
          ' size allowed. Move and enlarge it if necessary, to determine an area of'
          ' interest. Several images will be generated from this area.'),
        required=False,
        missing=None,
    )

    cover_picture = colander.SchemaNode(
        ObjectData(File),
        widget=get_file_widget(file_extensions=['png', 'jpg', 'svg']),
        title=_('Cover picture'),
        missing=None,
        description=_("Only PNG and SVG files are supported."),
    )

    first_name = colander.SchemaNode(
        colander.String(),
        title=_('Given name(s)'),
        description=
        _("Given name(s), as it(they) appear(s) on your official identity documents"
          ))

    last_name = colander.SchemaNode(
        colander.String(),
        title=_('Family name(s)'),
        description=
        _("Family name(s), as it(they) appear(s) on your official identity documents"
          ))

    birth_date = colander.SchemaNode(colander.Date(), title=_('Date of birth'))

    citizenship = colander.SchemaNode(
        colander.String(),
        widget=citizenship_choice,
        title=_('Citizenship'),
        description=
        _('What is the Member State of the European Union of which you are a citizen? Only citizens of the European Union can be members of the CosmoPolitical Cooperative.'
          ),
    )

    birthplace = colander.SchemaNode(
        colander.String(),
        title=_('Place of birth'),
        description=_(
            "Place of birth (city or municipality + country if relevant), "
            "as it appears on your official identity documents"))

    user_title = colander.SchemaNode(
        colander.String(),
        widget=titles_choice,
        title=_('Title', context='user'),
        description=
        _('Please do not select anything if you do not want to communicate this information.'
          ),
        missing='')

    locale = colander.SchemaNode(
        colander.String(),
        title=_('Locale'),
        widget=locale_widget,
        missing=locale_missing,
        validator=colander.OneOf(AVAILABLE_LANGUAGES),
    )

    password = colander.SchemaNode(
        colander.String(),
        widget=deform.widget.CheckedPasswordWidget(),
        validator=colander.Length(min=3, max=100),
        title=_("Password"))

    organization = colander.SchemaNode(
        ObjectType(),
        widget=organization_choice,
        missing=None,
        title=_('Organization'),
    )

    pseudonym = colander.SchemaNode(
        colander.String(),
        widget=deform.widget.TextInputWidget(item_css_class='pseudonym-input'),
        validator=colander.All(pseudonym_validator, ),
        title=_('Pseudonym'),
        description=
        _("Please choose the pseudonym that will identify you for the whole duration of your "
          "activity on the platform. We STRONGLY recommend that you select a pseudonym that makes "
          "tracking back to your real identity impossible (or extremely difficult). Thereby, you "
          "protect the confidentiality of your political opinions (i.e. personal data that are the "
          "purpose of a specific protection under the General Data Protection Regulation - GDPR) "
          "against any form of external pressure in real life (e.g. by your employer or your customers). "
          "Be very careful! Once you have chosen it, you will NEVER be able to change this pseudonym afterwards. "
          "Choose it with care!"),
    )

    accept_conditions = colander.SchemaNode(
        colander.Boolean(),
        widget=conditions_widget,
        label=_('I have read and accept the terms and conditions of use'),
        title='',
        missing=False)

    @invariant
    def user_invariant(self, appstruct):
        context = self.bindings['context']
        first_name = appstruct.get('first_name', None)
        last_name = appstruct.get('last_name', None)
        birth_date = appstruct.get('birth_date', None)
        birthplace = appstruct.get('birthplace', None)
        if first_name and last_name and birth_date and birthplace:
            try:
                birth_date = colander.iso8601.parse_date(birth_date)
                birth_date = birth_date.date()
            except colander.iso8601.ParseError as e:
                return

            key = first_name + last_name + birthplace + birth_date.strftime(
                "%d/%m/%Y")
            key = normalize_title(key).replace(' ', '')
            novaideo_catalog = find_catalog('novaideo')
            identifier_index = novaideo_catalog['identifier']
            query = identifier_index.any([key])
            users = list(query.execute().all())
            if context in users:
                users.remove(context)

            if users:
                raise colander.Invalid(self, _('User already exists'))
Beispiel #16
0
class SmartFolderSchema(VisualisableElementSchema):
    """Schema for keyword"""

    name = NameSchemaNode(editing=context_is_a_smartfolder, )

    title = colander.SchemaNode(
        colander.String(),
        widget=TextInputWidget(css_class="smartfolder-title-field"),
        title=_('Title'),
    )

    icon_data = colander.SchemaNode(DictSchemaType(),
                                    widget=BootstrapIconInputWidget(),
                                    title=_('Icon'),
                                    default={
                                        'icon': 'glyphicon-folder-open',
                                        'icon_class': 'glyphicon'
                                    },
                                    description=_('Select an icon.')
                                    # description="Sélectionner une icône."
                                    )

    description = colander.SchemaNode(
        colander.String(),
        widget=deform.widget.TextAreaWidget(rows=4, cols=60),
        title=_("Description"),
    )

    filters = colander.SchemaNode(
        colander.Sequence(),
        omit(
            select(
                FilterSchema(name='filter',
                             title=_('Filter'),
                             widget=SimpleMappingWidget(
                                 css_class='object-well default-well')),
                [
                    'metadata_filter', 'geographic_filter', 'temporal_filter',
                    'contribution_filter', 'text_filter', 'other_filter'
                ]), ["_csrf_token_"]),
        widget=SequenceWidget(min_len=1,
                              add_subitem_text_template=_('Add a new filter')))

    classifications = colander.SchemaNode(
        colander.Sequence(),
        colander.SchemaNode(colander.String(),
                            widget=classifications_widget,
                            name=_("Classification")),
        widget=classifications_seq_widget,
        title=_('Classifications'),
        description=_('You can select one or more options of classification.'),
        missing=[])

    add_as_a_block = colander.SchemaNode(
        colander.Boolean(),
        widget=deform.widget.CheckboxWidget(),
        label=_('Add as a block'),
        title='',
        description=_('You can add as a block to the home page.'),
        # description=('Vous pouvez ajouter en tant que bloc sur la page d\'accueil'),
        default=False,
        missing=False)

    style = omit(CssSchema(widget=SimpleMappingWidget()), ["_csrf_token_"])

    view_type = colander.SchemaNode(colander.String(),
                                    widget=view_type_widget,
                                    title=_("View type"),
                                    default='default')

    @invariant
    def classification_invariant(self, appstruct):
        if appstruct.get('view_type', 'default') == 'bloc' and\
           appstruct['classifications']:
            raise colander.Invalid(
                self,
                _('The bloc view is not classifiable! Please remove all classifications.'
                  ))
Beispiel #17
0
class SmartFolderSchema(VisualisableElementSchema):
    """Schema for keyword"""

    name = NameSchemaNode(editing=context_is_a_smartfolder, )

    title = colander.SchemaNode(
        colander.String(),
        widget=TextInputWidget(css_class="smartfolder-title-field"),
        title=_('Title'),
    )

    description = colander.SchemaNode(
        colander.String(),
        widget=deform.widget.TextAreaWidget(rows=4, cols=60),
        title=_("Description"),
    )

    locale = colander.SchemaNode(
        colander.String(),
        title=_('Locale'),
        description=_('The language for which the folder will be displayed'),
        widget=locale_widget,
        missing='')

    cover_picture = colander.SchemaNode(
        ObjectData(File),
        widget=get_file_widget(file_extensions=['png', 'jpg', 'svg']),
        title=_('Cover picture'),
        missing=None,
        description=_("Only PNG and SVG files are supported."),
    )

    filters = colander.SchemaNode(
        colander.Sequence(),
        omit(
            select(
                FilterSchema(name='filter',
                             title=_('Filter'),
                             widget=SimpleMappingWidget(
                                 css_class='object-well default-well')),
                [
                    'metadata_filter', 'temporal_filter',
                    'contribution_filter', 'text_filter', 'other_filter'
                ]), ["_csrf_token_"]),
        widget=SequenceWidget(add_subitem_text_template=_('Add a new filter')),
        title=_('Filters'),
        description=_('Applied filters'),
        missing=[])

    contents = colander.SchemaNode(
        colander.Set(),
        widget=relatedcontents_choice,
        title=_('Associated contents'),
        description=_('Choose the contents to be associated'),
        missing=[],
        default=[],
    )

    view_type = colander.SchemaNode(colander.String(),
                                    widget=view_type_widget,
                                    title=_("View type"),
                                    description=_('How to display contents'),
                                    default='default')

    icon_data = colander.SchemaNode(DictSchemaType(),
                                    widget=BootstrapIconInputWidget(),
                                    title=_('Icon'),
                                    default={
                                        'icon': 'glyphicon-folder-open',
                                        'icon_class': 'glyphicon'
                                    },
                                    description=_('Select an icon.'))

    style = omit(CssSchema(widget=SimpleMappingWidget()), ["_csrf_token_"])

    @invariant
    def contact_invariant(self, appstruct):
        contents = appstruct.get('contents', [])
        filters = appstruct.get('filters', [])
        if not contents and not filters:
            raise colander.Invalid(
                self, _('Filters or associated contents must be specified.'))