def test_call(self):
        inst = namedtemplate.implementation(None)

        nt = namedtemplate.NamedTemplate('name')
        nti = inst(nt)

        self.assertEqual(nti.descriptor, nt)
Esempio n. 2
0
class FormBase(zope.publisher.browser.BrowserPage):

    label = u''

    prefix = 'form'

    status = ''

    errors = ()

    ignoreContext = False

    method = None

    protected = False

    csrftoken = None

    def setPrefix(self, prefix):
        self.prefix = prefix

    def setUpToken(self):
        self.csrftoken = self.request.getCookies().get('__csrftoken__')
        if self.csrftoken is None:
            # It is possible another form, that is rendered as part of
            # this request, already set a csrftoken. In that case we
            # should find it in the response cookie and use that.
            setcookie = self.request.response.getCookie('__csrftoken__')
            if setcookie is not None:
                self.csrftoken = setcookie['value']
            else:
                # Ok, nothing found, we should generate one and set
                # it in the cookie ourselves. Note how we ``str()``
                # the hex value of the ``os.urandom`` call here, as
                # Python-3 will return bytes and the cookie roundtrip
                # of a bytes values gets messed up.
                self.csrftoken = str(binascii.hexlify(os.urandom(32)))
                self.request.response.setCookie(
                    '__csrftoken__',
                    self.csrftoken,
                    path='/',
                    expires=None,  # equivalent to "remove on browser quit"
                    httpOnly=True,  # no javascript access please.
                )

    def checkToken(self):
        cookietoken = self.request.getCookies().get('__csrftoken__')
        if cookietoken is None:
            # CSRF is enabled, so we really should get a token from the
            # cookie. We didn't get it, so this submit is invalid!
            raise InvalidCSRFTokenError(_('Invalid CSRF token'))
        if cookietoken != self.request.form.get('__csrftoken__', None):
            # The token in the cookie is different from the one in the
            # form data. This submit is invalid!
            raise InvalidCSRFTokenError(_('Invalid CSRF token'))

    def setUpWidgets(self, ignore_request=False):
        self.adapters = {}
        self.widgets = setUpWidgets(self.form_fields,
                                    self.prefix,
                                    self.context,
                                    self.request,
                                    form=self,
                                    adapters=self.adapters,
                                    ignore_request=ignore_request)

    def validate(self, action, data):
        if self.method is not None:
            # Verify the correct request method was used.
            if self.method.upper() != self.request.method.upper():
                raise MethodNotAllowed(self.context, self.request)
        if self.protected:
            self.checkToken()  # This form has CSRF protection enabled.
        if self.ignoreContext:
            context = None
        else:
            context = self.context
        return (getWidgetsData(self.widgets, self.prefix, data) +
                checkInvariants(self.form_fields, data, context))

    template = namedtemplate.NamedTemplate('default')

    # TODO also need to be able to show disabled actions
    def availableActions(self):
        return availableActions(self, self.actions)

    def resetForm(self):
        self.setUpWidgets(ignore_request=True)

    form_result = None
    form_reset = True

    def update(self):
        if self.protected:
            self.setUpToken()  # This form has CSRF protection enabled.
        self.setUpWidgets()
        self.form_reset = False

        data = {}
        errors, action = handleSubmit(self.actions, data, self.validate)
        # the following part will make sure that previous error not
        # get overriden by new errors. This is usefull for subforms. (ri)
        if self.errors is None:
            self.errors = errors
        else:
            if errors is not None:
                self.errors += tuple(errors)

        if errors:
            self.status = _('There were errors')
            result = action.failure(data, errors)
        elif errors is not None:
            self.form_reset = True
            result = action.success(data)
        else:
            result = None

        self.form_result = result

    def render(self):
        # if the form has been updated, it will already have a result
        if self.form_result is None:
            if self.form_reset:
                # we reset, in case data has changed in a way that
                # causes the widgets to have different data
                self.resetForm()
                self.form_reset = False
            self.form_result = self.template()

        return self.form_result

    def __call__(self):
        self.update()
        if self.request.response.getStatus() in [301, 302, 303, 307]:
            # Avoid rendering if the action caused a redirect.
            result = self.form_result or ''
        else:
            result = self.render()
        return result

    def error_views(self):
        for error in self.errors:
            if isinstance(error, basestring):
                yield error
            else:
                view = component.getMultiAdapter((error, self.request),
                                                 IWidgetInputErrorView)
                title = getattr(error, 'widget_title', None)  # duck typing
                if title:
                    if isinstance(title, zope.i18n.Message):
                        title = zope.i18n.translate(title,
                                                    context=self.request)
                    yield '%s: %s' % (title, view.snippet())
                else:
                    yield view.snippet()
Esempio n. 3
0
class Action(object):
    """See `zope.formlib.interfaces.IAction`"""
    _identifier = re.compile('[A-Za-z][a-zA-Z0-9_]*$')

    def __init__(self,
                 label,
                 success=None,
                 failure=None,
                 condition=None,
                 validator=None,
                 prefix='actions',
                 name=None,
                 data=None):

        self.label = label
        self.setPrefix(prefix)
        self.setName(name)
        self.bindMethods(success_handler=success,
                         failure_handler=failure,
                         condition=condition,
                         validator=validator)

        if data is None:
            data = {}
        self.data = data

    def bindMethods(self, **methods):
        """Bind methods to the action"""
        for k, v in methods.items():
            setattr(self, k, _callify(v))

    def setName(self, name):
        """Make sure name is ASCIIfiable.
           Use action label if name is None
        """
        if name is None:
            name = self.label
            if self._identifier.match(name):
                name = name.lower()
            else:
                if isinstance(name, unicode):
                    name = name.encode("utf-8")
                name = binascii.hexlify(name).decode()
        self.name = name
        self.__name__ = self.prefix + name

    def setPrefix(self, prefix):
        """Set prefix"""
        self.prefix = expandPrefix(prefix)

    def __get__(self, form, class_=None):
        if form is None:
            return self
        result = self.__class__.__new__(self.__class__)
        result.__dict__.update(self.__dict__)
        result.form = form
        result.__name__ = expandPrefix(form.prefix) + result.__name__
        interface.alsoProvides(result, interfaces.IBoundAction)
        return result

    def available(self):
        condition = self.condition
        return (condition is None) or condition(self.form, self)

    def validate(self, data):
        if self.validator is not None:
            return self.validator(self.form, self, data)

    def success(self, data):
        if self.success_handler is not None:
            return self.success_handler(self.form, self, data)

    def failure(self, data, errors):
        if self.failure_handler is not None:
            return self.failure_handler(self.form, self, data, errors)

    def submitted(self):
        return (self.__name__ in self.form.request.form) and self.available()

    def update(self):
        pass

    render = namedtemplate.NamedTemplate('render')
Esempio n. 4
0
class FormBase(zope.publisher.browser.BrowserPage):

    label = u''

    prefix = 'form'

    status = ''

    errors = ()

    interface.implements(interfaces.IForm)

    def setPrefix(self, prefix):
        self.prefix = prefix

    def setUpWidgets(self, ignore_request=False):
        self.adapters = {}
        self.widgets = setUpWidgets(self.form_fields,
                                    self.prefix,
                                    self.context,
                                    self.request,
                                    form=self,
                                    adapters=self.adapters,
                                    ignore_request=ignore_request)

    def validate(self, action, data):
        return (getWidgetsData(self.widgets, self.prefix, data) +
                checkInvariants(self.form_fields, data))

    template = namedtemplate.NamedTemplate('default')

    # TODO also need to be able to show disabled actions
    def availableActions(self):
        return availableActions(self, self.actions)

    def resetForm(self):
        self.setUpWidgets(ignore_request=True)

    form_result = None
    form_reset = True

    def update(self):
        self.setUpWidgets()
        self.form_reset = False

        data = {}
        errors, action = handleSubmit(self.actions, data, self.validate)
        # the following part will make sure that previous error not
        # get overriden by new errors. This is usefull for subforms. (ri)
        if self.errors is None:
            self.errors = errors
        else:
            if errors is not None:
                self.errors += tuple(errors)

        if errors:
            self.status = _('There were errors')
            result = action.failure(data, errors)
        elif errors is not None:
            self.form_reset = True
            result = action.success(data)
        else:
            result = None

        self.form_result = result

    def render(self):
        # if the form has been updated, it will already have a result
        if self.form_result is None:
            if self.form_reset:
                # we reset, in case data has changed in a way that
                # causes the widgets to have different data
                self.resetForm()
                self.form_reset = False
            self.form_result = self.template()

        return self.form_result

    def __call__(self):
        self.update()
        if self.request.response.getStatus() in [301, 302]:
            # Avoid rendering if the action caused a redirect.
            result = self.form_result or ''
        else:
            result = self.render()
        return result

    def error_views(self):
        for error in self.errors:
            if isinstance(error, basestring):
                yield error
            else:
                view = component.getMultiAdapter((error, self.request),
                                                 IWidgetInputErrorView)
                title = getattr(error, 'widget_title', None)  # duck typing
                if title:
                    if isinstance(title, zope.i18n.Message):
                        title = zope.i18n.translate(title,
                                                    context=self.request)
                    yield '%s: %s' % (title, view.snippet())
                else:
                    yield view.snippet()
 class X(object):
     nt = namedtemplate.NamedTemplate('name')