Make it possible to install custom contact forms anywhere
This commit is contained in:
parent
f44db052ba
commit
f4032b7a69
|
@ -1,29 +1,33 @@
|
|||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:grok="http://namespaces.zope.org/grok"
|
||||
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
|
||||
xmlns:five="http://namespaces.zope.org/five"
|
||||
xmlns:i18n="http://namespaces.zope.org/i18n"
|
||||
xmlns:browser="http://namespaces.zope.org/browser"
|
||||
i18n_domain="tabellio.contact">
|
||||
|
||||
<!-- Include configuration for dependencies listed in setup.py -->
|
||||
<includeDependencies package="." />
|
||||
|
||||
<!-- Grok the package to initialise schema interfaces and content classes -->
|
||||
<grok:grok package="." />
|
||||
|
||||
|
||||
<five:registerPackage package="." initialize=".initialize" />
|
||||
|
||||
<browser:page
|
||||
name="contact"
|
||||
for="Products.CMFPlone.interfaces.siteroot.IPloneSiteRoot"
|
||||
class=".form.ContactForm"
|
||||
permission = "zope.Public" />
|
||||
|
||||
<!-- Captcha factory -->
|
||||
<adapter
|
||||
for="Products.CMFPlone.interfaces.siteroot.IPloneSiteRoot"
|
||||
provides=".form.IContactForm"
|
||||
factory=".form.Contact" />
|
||||
<!-- Register an extension profile to make the product installable -->
|
||||
<genericsetup:registerProfile
|
||||
name="default"
|
||||
title="Tabellio Contact Support"
|
||||
description="..."
|
||||
directory="profiles/default"
|
||||
provides="Products.GenericSetup.interfaces.EXTENSION"
|
||||
/>
|
||||
|
||||
<!-- Captcha validator -->
|
||||
<adapter
|
||||
factory=".form.CaptchaValidator"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
</configure>
|
||||
|
|
|
@ -1,20 +1,46 @@
|
|||
from five import grok
|
||||
from Acquisition import aq_inner
|
||||
from zope.interface import implements
|
||||
|
||||
from zope import interface
|
||||
from zope import schema
|
||||
|
||||
from zope.component import getMultiAdapter, provideAdapter
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
|
||||
from z3c.form import form, field, button, validator
|
||||
|
||||
from plone.z3cform.layout import wrap_form
|
||||
from z3c.form.ptcompat import ViewPageTemplateFile
|
||||
from plone.dexterity.content import Item
|
||||
|
||||
from plone.formwidget.captcha.widget import CaptchaFieldWidget
|
||||
from plone.formwidget.captcha.validator import CaptchaValidator
|
||||
|
||||
from tabellio.agenda.interfaces import MessageFactory as _
|
||||
|
||||
|
||||
class IContactForm(interface.Interface):
|
||||
title = schema.TextLine(title=_(u'Title'))
|
||||
description = schema.Text(title=_(u'Description'))
|
||||
subjects = schema.Text(title=_(u'Available Subjects'))
|
||||
|
||||
class ContactForm(Item):
|
||||
implements(IContactForm)
|
||||
|
||||
|
||||
class View(grok.View):
|
||||
grok.context(IContactForm)
|
||||
grok.require('zope2.View')
|
||||
|
||||
def contact_form(self):
|
||||
effective_contact = EffectiveContact(self.context)
|
||||
effective_form = EffectiveContactForm(effective_contact, self.request)
|
||||
effective_form.update()
|
||||
return effective_form.render()
|
||||
|
||||
|
||||
class IEffectiveContact(interface.Interface):
|
||||
subject = schema.TextLine(title=_(u'Subject'), required=True)
|
||||
name = schema.TextLine(title=_(u'Name'), required=True)
|
||||
email = schema.TextLine(title=_(u'Name'), required=True)
|
||||
|
@ -22,26 +48,35 @@ class IContactForm(interface.Interface):
|
|||
message = schema.Text(title=_(u'Message'), required=True)
|
||||
captcha = schema.TextLine(title=u'Captcha', required=False)
|
||||
|
||||
class Contact(object):
|
||||
def __init__(self, context):
|
||||
class EffectiveContact(object):
|
||||
implements(IEffectiveContact)
|
||||
|
||||
def __init__(self, context=None):
|
||||
self.context = context
|
||||
|
||||
class BaseForm(form.Form):
|
||||
fields = field.Fields(IContactForm)
|
||||
def absolute_url(self):
|
||||
# this is used by the captcha
|
||||
return self.context.absolute_url()
|
||||
|
||||
|
||||
class EffectiveContactForm(form.Form):
|
||||
fields = field.Fields(IEffectiveContact)
|
||||
fields['captcha'].widgetFactory = CaptchaFieldWidget
|
||||
template = ViewPageTemplateFile('form_templates/view_effectivecontact.pt')
|
||||
|
||||
@button.buttonAndHandler(u'Send')
|
||||
def handleApply(self, action):
|
||||
data, errors = self.extractData()
|
||||
if data.has_key('captcha'):
|
||||
if not errors and data.has_key('captcha'):
|
||||
# Verify the user input against the captcha
|
||||
captcha = CaptchaValidator(self.context, self.request, None, IContactForm['captcha'], None)
|
||||
if data.has_key('subject') and captcha.validate(data['captcha']):
|
||||
# if captcha validation passes, print the subject
|
||||
print data['subject']
|
||||
captcha = CaptchaValidator(self.context, self.request, None, IEffectiveContact['captcha'], None)
|
||||
if captcha.validate(data['captcha']):
|
||||
# if captcha validation passes, send the email.
|
||||
plone_utils = getToolByName(self.context.context, 'plone_utils')
|
||||
plone_utils.addPortalMessage(_('Your message has been sent successfully.'))
|
||||
return self.request.response.redirect('./')
|
||||
return
|
||||
|
||||
ContactForm = wrap_form(BaseForm)
|
||||
|
||||
# Register Captcha validator for the captcha field in the IContactForm
|
||||
validator.WidgetValidatorDiscriminators(CaptchaValidator, field=IContactForm['captcha'])
|
||||
validator.WidgetValidatorDiscriminators(CaptchaValidator, field=IEffectiveContact['captcha'])
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
|
||||
xmlns:tal="http://xml.zope.org/namespaces/tal"
|
||||
xmlns:metal="http://xml.zope.org/namespaces/metal"
|
||||
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
|
||||
lang="en"
|
||||
metal:use-macro="context/main_template/macros/master"
|
||||
i18n:domain="tabellio.contact">
|
||||
<body>
|
||||
|
||||
<metal:main fill-slot="main">
|
||||
<tal:main-macro metal:define-macro="main"
|
||||
tal:define="toLocalizedTime nocall:context/@@plone/toLocalizedTime">
|
||||
|
||||
<div tal:replace="structure provider:plone.abovecontenttitle" />
|
||||
|
||||
<h1 class="documentFirstHeading" tal:content="context/title" />
|
||||
|
||||
<div tal:replace="structure provider:plone.belowcontenttitle" />
|
||||
|
||||
<div tal:replace="structure view/contact_form"/>
|
||||
|
||||
<div tal:replace="structure provider:plone.belowcontentbody" />
|
||||
|
||||
</tal:main-macro>
|
||||
</metal:main>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:tal="http://xml.zope.org/namespaces/tal">
|
||||
<body>
|
||||
<form method="post" action="." tal:attributes="action context/absolute_url">
|
||||
<metal:use use-macro="context/@@ploneform-macros/fields" />
|
||||
<metal:use use-macro="context/@@ploneform-macros/actions" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,6 @@
|
|||
<metadata>
|
||||
<version>1</version>
|
||||
<dependencies>
|
||||
<dependency>profile-plone.app.dexterity:default</dependency>
|
||||
</dependencies>
|
||||
</metadata>
|
|
@ -0,0 +1,3 @@
|
|||
<object name="portal_types">
|
||||
<object name="tabellio.contact.form" meta_type="Dexterity FTI" />
|
||||
</object>
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0"?>
|
||||
<object name="tabellio.contact.form" meta_type="Dexterity FTI"
|
||||
i18n:domain="tabellio.contact" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
|
||||
|
||||
<!-- Basic metadata -->
|
||||
<property name="title" i18n:translate="">Contact Form</property>
|
||||
<property name="description" i18n:translate="">A contact form</property>
|
||||
<property name="content_icon">document_icon.gif</property>
|
||||
<property name="allow_discussion">False</property>
|
||||
<property name="global_allow">True</property>
|
||||
<property name="filter_content_types">False</property>
|
||||
<property name="allowed_content_types"/>
|
||||
|
||||
<!-- schema interface -->
|
||||
<property name="schema">tabellio.contact.form.IContactForm</property>
|
||||
|
||||
<!-- class used for content items -->
|
||||
<property name="klass">tabellio.contact.form.ContactForm</property>
|
||||
|
||||
<!-- add permission -->
|
||||
<property name="add_permission">cmf.AddPortalContent</property>
|
||||
|
||||
<!-- enabled behaviors -->
|
||||
<property name="behaviors">
|
||||
<element value="plone.app.content.interfaces.INameFromTitle" />
|
||||
</property>
|
||||
|
||||
<!-- View information -->
|
||||
<property name="default_view">view</property>
|
||||
<property name="default_view_fallback">False</property>
|
||||
<property name="view_methods">
|
||||
<element value="view"/>
|
||||
</property>
|
||||
|
||||
<!-- Method aliases -->
|
||||
<alias from="(Default)" to="(dynamic view)"/>
|
||||
<alias from="edit" to="@@edit"/>
|
||||
<alias from="sharing" to="@@sharing"/>
|
||||
<alias from="view" to="(selected layout)"/>
|
||||
|
||||
<!-- Actions -->
|
||||
<action title="View" action_id="view" category="object" condition_expr=""
|
||||
url_expr="string:${object_url}" visible="True">
|
||||
<permission value="View"/>
|
||||
</action>
|
||||
<action title="Edit" action_id="edit" category="object" condition_expr=""
|
||||
url_expr="string:${object_url}/edit" visible="True">
|
||||
<permission value="Modify portal content"/>
|
||||
</action>
|
||||
</object>
|
Reference in New Issue