Esempio n. 1
0
    def __init__(self, *args, **kw):
        super(CompositeField, self).__init__(*args, **kw)

        if not self.fields:
            raise ValueError('Fields are required for composite field.')

        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        self.fields.prefix = '%s.' % self.name
Esempio n. 2
0
    def __init__(self, *args, **kw):
        super(OptionsField, self).__init__(*args, **kw)

        voc = vocabulary.Vocabulary(
            *[vocabulary.Term(fname, fname, field.title)
              for fname, field in self.fields.items()])

        if not self.key:
            self.key = self.name

        self.fields = Fieldset(
            RadioField(
                self.key,
                missing = voc[0].value,
                default = voc[0].value,
                required = False,
                vocabulary = voc)) + self.fields
Esempio n. 3
0
    def __init__(self, context, request, **kw):
        self.__dict__.update(kw)

        self.context = context
        self.request = request
        self.__parent__ = context

        if self.buttons is None:
            self.buttons = Buttons()

        # convert fields to Fieldset
        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        # set tmpl_widget
        for fieldset in self.fields.fieldsets():
            for field in fieldset.fields():
                if field.cls.tmpl_widget is None:
                    field.cls.tmpl_widget = self.tmpl_widget
Esempio n. 4
0
    def __init__(self, *args, **kw):
        super(CompositeField, self).__init__(*args, **kw)

        if not self.fields:
            raise ValueError('Fields are required for composite field.')

        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        self.fields.prefix = '%s.'%self.name
Esempio n. 5
0
    def __init__(self, context, request, **kw):
        self.__dict__.update(kw)

        self.context = context
        self.request = request
        self.__parent__ = context

        if self.buttons is None:
            self.buttons = Buttons()

        # convert fields to Fieldset
        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        # set tmpl_widget
        for fieldset in self.fields.fieldsets():
            for field in fieldset.fields():
                if field.cls.tmpl_widget is None:
                    field.cls.tmpl_widget = self.tmpl_widget
Esempio n. 6
0
class Form(object):
    """ A form

    ``id``: Form id

    ``name``: Form name

    ``label``: Form label

    ``description``: Form description

    ``prefix``: Form prefix, it used for html elements `id` generations.

    ``fields``: Form fields :py:class:`ptah.form.Fieldset`

    ``buttons``: Form buttons :py:class:`ptah.form.Buttons`

    ``actions``: Instance of :py:class:`ptah.form.Actions` class

    ``widgets``: Instance of :py:class:`FormWidgets` class

    ``content``: Form content, it should be `None` or dictionary with
    data for fields.

    ``params``: Form request parameters

    ``action``: Form action, by default ``request.url``

    ``method``: HTML Form method (`post`, `get`)

    ``csrf``: Enable/disable form csrf protection

    ``csrf_name``: Form csrf field name

    ``csrf_token``: Form csrf token value
    """

    label = None
    description = ''
    prefix = 'form.'

    actions = None
    widgets = None

    buttons = None
    fields = Fieldset()

    content = None

    method = 'post'
    enctype = 'multipart/form-data'
    accept = None
    accept_charset = 'utf-8'
    params = None
    context = None
    klass = 'form-horizontal'

    csrf = False
    csrf_name = 'csrf-token'
    csrf_token = ''

    tmpl_view = 'form:form'
    tmpl_actions = 'form:form-actions'
    tmpl_widget = 'form:widget'

    __name__ = ''
    __parent__ = None
    __view_mapper__ = FormViewMapper

    def __init__(self, context, request, **kw):
        self.__dict__.update(kw)

        self.context = context
        self.request = request
        self.__parent__ = context

        if self.buttons is None:
            self.buttons = Buttons()

        # convert fields to Fieldset
        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        # set tmpl_widget
        for fieldset in self.fields.fieldsets():
            for field in fieldset.fields():
                if field.cls.tmpl_widget is None:
                    field.cls.tmpl_widget = self.tmpl_widget

    @reify
    def id(self):
        return self.name.replace('.', '-')

    @reify
    def name(self):
        return self.prefix.strip('.')

    @reify
    def action(self):
        return self.request.url

    @reify
    def csrf_token(self):
        return self.request.session.get_csrf_token()

    def form_content(self):
        """ Return form content.
        By default it returns ``Form.content`` attribute. """
        return self.content

    def form_params(self):
        """ get form request params """
        if self.params is not None:
            if not isinstance(self.params, MultiDict):
                return MultiDict(self.params)
            return self.params

        if self.method == 'post':
            return self.request.POST
        elif self.method == 'get':
            return self.request.GET
        else:
            return self.params

    def update_widgets(self):
        """ prepare form widgets """
        self.widgets = FormWidgets(self.fields, self, self.request)
        self.widgets.update()

    def update_actions(self):
        """ Prepare form actions, this method should be called directly.
        ``Form.update`` calls this method during initialization."""
        self.actions = Actions(self, self.request)
        self.actions.update()

    def update_form(self, data=None):
        """ update form """
        if not self.content and data:
            self.content = data

        self.update_widgets()
        self.update_actions()

        ac_result = self.actions.execute()
        if IResponse.providedBy(ac_result):
            raise HTTPResponseIsReady(ac_result)

        result = self.update()
        if IResponse.providedBy(result):
            raise HTTPResponseIsReady(result)

        if result is None:
            result = {}

        if ac_result is not None:
            result.update(ac_result)

        return result

    def update(self):
        """ Update form """
        return {}

    def render(self):
        """ render form """
        return render(self.request,
                      self.tmpl_view,
                      self,
                      actions=self.actions,
                      widgets=self.widgets)

    def validate(self, data, errors):
        """ Custom form validation """

    def validate_form(self, data, errors):
        """ Form validation """
        self.validate_csrf_token()
        try:
            self.validate(data, errors)
        except Invalid as err:
            errors.append(err)

    def validate_csrf_token(self):
        """ csrf token validation """
        if self.csrf:
            token = self.form_params().get(self.csrf_name, None)
            if token is not None:
                if self.csrf_token == token:
                    return

            raise HTTPForbidden("Form authenticator is not found.")

    def extract(self):
        """ extract form values """
        return self.widgets.extract()

    def add_error_message(self, msg):
        """ add form error message """
        add_message(self.request, msg, 'form:error')

    def __call__(self):
        """ update form and render form to response """
        try:
            result = self.update_form()
        except HTTPResponseIsReady as result:
            return result.args[0]
        except HTTPException as result:
            return result

        response = self.request.registry.queryAdapterOrSelf(result, IResponse)
        if response is not None:
            return response

        body = self.render()

        response = self.request.response
        if isinstance(body, bytes):
            response.body = body
        else:
            response.text = body
        return response
Esempio n. 7
0
class CompositeField(Field):
    """ Composit field """

    fields = None
    tmpl_input = 'form:composite'
    tmpl_widget = 'form:widget-composite'

    inline = False
    consolidate_errors = False

    def __init__(self, *args, **kw):
        super(CompositeField, self).__init__(*args, **kw)

        if not self.fields:
            raise ValueError('Fields are required for composite field.')

        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        self.fields.prefix = '%s.'%self.name

    @reify
    def default(self):
        return dict(
            [(name,
              field.default if field.default is not null else field.missing)
             for name, field in self.fields.items()])

    def bind(self, request, prefix, value, params, context=None):
        """ Bind field to value and request params """
        if value in (null, None):
            value = {}

        clone = super(CompositeField, self).bind(
            request, prefix, value, params, context)

        clone.fields = self.fields.bind(request, value, params, '', context)
        return clone

    def set_id_prefix(self, prefix):
        self.id = ('%s%s'%(prefix, self.name)).replace('.', '-')

        prefix = '%s%s.'%(prefix, self.name)

        for name, field in self.fields.items():
            field.set_id_prefix(prefix)

    def update(self):
        """ Update field, prepare field for rendering """
        super(CompositeField, self).update()

        for field in self.fields.values():
            field.update()

    def to_field(self, value):
        """ convert form value to field value """
        result = {}
        errors = []
        for name, val in value.items():
            field = self.fields[name]
            try:
                result[name] = field.to_field(val)
            except Invalid as error:
                error.name = name
                errors.append(error)
                if field.error is None:
                    field.error = error

        if errors:
            if self.consolidate_errors:
                raise CompositeError(errors[0].msg, field=self)
            else:
                raise CompositeError(field=self, errors=errors)

        return result

    def validate(self, value):
        """ validate value """
        errors = []
        for name, val in value.items():
            field = self.fields[name]
            try:
                field.validate(val)
            except Invalid as error:
                error.name = name
                errors.append(error)
                if field.error is None:
                    field.error = error

        if errors:
            if self.consolidate_errors:
                raise CompositeError(errors[0].msg, field=self)
            else:
                raise CompositeError(field=self, errors=errors)

        if self.validator is not None:
            self.validator(self, value)

    def extract(self):
        value = {}
        for name, field in self.fields.items():
            val = field.extract()
            if val is null and field.missing is not null:
                val = copy.copy(field.missing)

            value[name] = val

        return value

    def flatten(self, value):
        for name, field in self.fields.items():
            if field.flat and name in value:
                value.update(field.flatten(value.pop(name)))

        return value
Esempio n. 8
0
class Form(object):
    """ A form

    ``id``: Form id

    ``name``: Form name

    ``label``: Form label

    ``description``: Form description

    ``prefix``: Form prefix, it used for html elements `id` generations.

    ``fields``: Form fields :py:class:`ptah.form.Fieldset`

    ``buttons``: Form buttons :py:class:`ptah.form.Buttons`

    ``actions``: Instance of :py:class:`ptah.form.Actions` class

    ``widgets``: Instance of :py:class:`FormWidgets` class

    ``content``: Form content, it should be `None` or dictionary with
    data for fields.

    ``params``: Form request parameters

    ``action``: Form action, by default ``request.url``

    ``method``: HTML Form method (`post`, `get`)

    ``csrf``: Enable/disable form csrf protection

    ``csrf_name``: Form csrf field name

    ``csrf_token``: Form csrf token value
    """

    label = None
    description = ''
    prefix = 'form.'

    actions = None
    widgets = None

    buttons = None
    fields = Fieldset()

    content = None

    method = 'post'
    enctype = 'multipart/form-data'
    accept = None
    accept_charset = 'utf-8'
    params = None
    context = None
    klass = 'form-horizontal'

    csrf = False
    csrf_name = 'csrf-token'
    csrf_token = ''

    tmpl_view = 'form:form'
    tmpl_actions = 'form:form-actions'
    tmpl_widget = 'form:widget'

    __name__ = ''
    __parent__ = None
    __view_mapper__ = FormViewMapper

    def __init__(self, context, request, **kw):
        self.__dict__.update(kw)

        self.context = context
        self.request = request
        self.__parent__ = context

        if self.buttons is None:
            self.buttons = Buttons()

        # convert fields to Fieldset
        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        # set tmpl_widget
        for fieldset in self.fields.fieldsets():
            for field in fieldset.fields():
                if field.cls.tmpl_widget is None:
                    field.cls.tmpl_widget = self.tmpl_widget

    @reify
    def id(self):
        return self.name.replace('.', '-')

    @reify
    def name(self):
        return self.prefix.strip('.')

    @reify
    def action(self):
        return self.request.url

    @reify
    def csrf_token(self):
        return self.request.session.get_csrf_token()

    def form_content(self):
        """ Return form content.
        By default it returns ``Form.content`` attribute. """
        return self.content

    def form_params(self):
        """ get form request params """
        if self.params is not None:
            if not isinstance(self.params, MultiDict):
                return MultiDict(self.params)
            return self.params

        if self.method == 'post':
            return self.request.POST
        elif self.method == 'get':
            return self.request.GET
        else:
            return self.params

    def update_widgets(self):
        """ prepare form widgets """
        self.widgets = FormWidgets(self.fields, self, self.request)
        self.widgets.update()

    def update_actions(self):
        """ Prepare form actions, this method should be called directly.
        ``Form.update`` calls this method during initialization."""
        self.actions = Actions(self, self.request)
        self.actions.update()

    def update_form(self, data=None):
        """ update form """
        if not self.content and data:
            self.content = data

        self.update_widgets()
        self.update_actions()

        ac_result = self.actions.execute()
        if IResponse.providedBy(ac_result):
            raise HTTPResponseIsReady(ac_result)

        result = self.update()
        if IResponse.providedBy(result):
            raise HTTPResponseIsReady(result)

        if result is None:
            result = {}

        if ac_result is not None:
            result.update(ac_result)

        return result

    def update(self):
        """ Update form """
        return {}

    def render(self):
        """ render form """
        return render(self.request, self.tmpl_view, self,
                      actions = self.actions,
                      widgets = self.widgets)

    def validate(self, data, errors):
        """ Custom form validation """

    def validate_form(self, data, errors):
        """ Form validation """
        self.validate_csrf_token()
        try:
            self.validate(data, errors)
        except Invalid as err:
            errors.append(err)

    def validate_csrf_token(self):
        """ csrf token validation """
        if self.csrf:
            token = self.form_params().get(self.csrf_name, None)
            if token is not None:
                if self.csrf_token == token:
                    return

            raise HTTPForbidden("Form authenticator is not found.")

    def extract(self):
        """ extract form values """
        return self.widgets.extract()

    def add_error_message(self, msg):
        """ add form error message """
        add_message(self.request, msg, 'form:error')

    def __call__(self):
        """ update form and render form to response """
        try:
            result = self.update_form()
        except HTTPResponseIsReady as result:
            return result.args[0]
        except HTTPException as result:
            return result

        response = self.request.registry.queryAdapterOrSelf(result, IResponse)
        if response is not None:
            return response

        body = self.render()

        response = self.request.response
        if isinstance(body, bytes):
            response.body = body
        else:
            response.text = body
        return response
Esempio n. 9
0
class OptionsField(CompositeField):
    """ Options field

    ``key``: Name of group key name

    ``defaults``: Build defaults for unselected groups

    ``extract_all``: Extract values for all groups

    """

    key = ''
    defaults = False
    extract_all = False
    tmpl_input = 'form:options'

    def __init__(self, *args, **kw):
        super(OptionsField, self).__init__(*args, **kw)

        voc = vocabulary.Vocabulary(
            *[vocabulary.Term(fname, fname, field.title)
              for fname, field in self.fields.items()])

        if not self.key:
            self.key = self.name

        self.fields = Fieldset(
            RadioField(
                self.key,
                missing = voc[0].value,
                default = voc[0].value,
                required = False,
                vocabulary = voc)) + self.fields

    def to_field(self, value):
        value = super(OptionsField, self).to_field(value)

        if self.defaults:
            for name, f in self.fields.items():
                if name not in value:
                    value[name] = (f.default
                                   if f.default is not null else f.missing)

        return value

    def validate(self, value):
        key = value.get(self.key)

        if key not in self.fields:
            key = self.fields[self.key].default

        super(OptionsField, self).validate(
            {key: value.get(key, self.fields[key].missing)})

    def extract(self):
        value = super(OptionsField, self).extract()

        if not self.extract_all:
            opotion = value[self.key]
            if opotion in value:
                return {self.key: opotion, opotion: value[opotion]}
            else:
                return {}

        return value
Esempio n. 10
0
class CompositeField(Field):
    """ Composit field """

    fields = None
    tmpl_input = 'form:composite'
    tmpl_widget = 'form:widget-composite'

    inline = False
    consolidate_errors = False

    def __init__(self, *args, **kw):
        super(CompositeField, self).__init__(*args, **kw)

        if not self.fields:
            raise ValueError('Fields are required for composite field.')

        if not isinstance(self.fields, Fieldset):
            self.fields = Fieldset(*self.fields)

        self.fields.prefix = '%s.' % self.name

    @reify
    def default(self):
        return dict([
            (name,
             field.default if field.default is not null else field.missing)
            for name, field in self.fields.items()
        ])

    def bind(self, request, prefix, value, params, context=None):
        """ Bind field to value and request params """
        if value in (null, None):
            value = {}

        clone = super(CompositeField, self).bind(request, prefix, value,
                                                 params, context)

        clone.fields = self.fields.bind(request, value, params, '', context)
        return clone

    def set_id_prefix(self, prefix):
        self.id = ('%s%s' % (prefix, self.name)).replace('.', '-')

        prefix = '%s%s.' % (prefix, self.name)

        for name, field in self.fields.items():
            field.set_id_prefix(prefix)

    def update(self):
        """ Update field, prepare field for rendering """
        super(CompositeField, self).update()

        for field in self.fields.values():
            field.update()

    def to_field(self, value):
        """ convert form value to field value """
        result = {}
        errors = []
        for name, val in value.items():
            field = self.fields[name]
            try:
                result[name] = field.to_field(val)
            except Invalid as error:
                error.name = name
                errors.append(error)
                if field.error is None:
                    field.error = error

        if errors:
            if self.consolidate_errors:
                raise CompositeError(errors[0].msg, field=self)
            else:
                raise CompositeError(field=self, errors=errors)

        return result

    def validate(self, value):
        """ validate value """
        errors = []
        for name, val in value.items():
            field = self.fields[name]
            try:
                field.validate(val)
            except Invalid as error:
                error.name = name
                errors.append(error)
                if field.error is None:
                    field.error = error

        if errors:
            if self.consolidate_errors:
                raise CompositeError(errors[0].msg, field=self)
            else:
                raise CompositeError(field=self, errors=errors)

        if self.validator is not None:
            self.validator(self, value)

    def extract(self):
        value = {}
        for name, field in self.fields.items():
            val = field.extract()
            if val is null and field.missing is not null:
                val = copy.copy(field.missing)

            value[name] = val

        return value

    def flatten(self, value):
        for name, field in self.fields.items():
            if field.flat and name in value:
                value.update(field.flatten(value.pop(name)))

        return value