This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
tabellio.contact/tabellio/contact/form.py

319 lines
12 KiB
Python

from five import grok
from Acquisition import aq_inner
from zope.interface import implements
from zope import interface, schema, component
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 Products.Five import BrowserView
from plone.formwidget.captcha.widget import CaptchaFieldWidget
from plone.formwidget.captcha.validator import CaptchaValidator
from zope.schema import ValidationError
from zope.schema.interfaces import IContextSourceBinder
from zope.schema.vocabulary import SimpleVocabulary
from plone.registry.interfaces import IRegistry
from tabellio.config.interfaces import ITabellioSettings
from tabellio.contact.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()
@grok.provider(IContextSourceBinder)
def get_possible_subjects(context):
terms = []
for line in context.context.subjects.splitlines():
if line.count('|') == 1:
topic, email = line.strip().split('|')
elif line.count('|') == 2:
topic, email, service = line.strip().split('|')
else:
continue
if email == '->deputy':
terms.append(SimpleVocabulary.createTerm('-deputy', '-deputy', topic))
else:
terms.append(SimpleVocabulary.createTerm(topic, topic.encode('ascii', 'replace'), topic))
if len(terms) == 0:
terms.append(SimpleVocabulary.createTerm('-', '-', '-'))
return SimpleVocabulary(terms)
def get_email_for_subject(context, selected_topic):
for line in context.context.subjects.splitlines():
if line.count('|') == 1:
topic, email = line.strip().split('|')
elif line.count('|') == 2:
topic, email, service = line.strip().split('|')
else:
continue
if topic == selected_topic:
return email
return None
class ServiceView(BrowserView):
def __call__(self):
selected_topic = self.request.form.get('id')
for line in self.context.subjects.splitlines():
if line.count('|') == 1:
topic, email = line.strip().split('|')
elif line.count('|') == 2:
topic, email, service = line.strip().split('|')
else:
continue
if selected_topic == topic.encode('ascii', 'replace'):
return _(u'Your request will be handled by: %s') % service
return None
class IEffectiveContact(interface.Interface):
subject = schema.Choice(title=_(u'Subject'), required=True,
source=get_possible_subjects)
name = schema.TextLine(title=_(u'Name'), required=True)
email = schema.TextLine(title=_(u'Email'), required=True)
phone = schema.TextLine(title=_(u'Phone'), required=False)
message = schema.Text(title=_(u'Message'), required=True)
captcha = schema.TextLine(title=_(u'Please type the different chars'), required=False)
class EffectiveContact(object):
implements(IEffectiveContact)
def __init__(self, context=None):
self.context = context
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')
def updateWidgets(self):
super(EffectiveContactForm, self).updateWidgets()
self.widgets['message'].rows = 10
@button.buttonAndHandler(_(u'Send'))
def handleApply(self, action):
data, errors = self.extractData()
if not errors and data.has_key('captcha'):
# Verify the user input against the captcha
try:
captcha = CaptchaValidator(self.context, self.request, None, IEffectiveContact['captcha'], None)
if captcha.validate(data['captcha']):
# if captcha validation passes, send the email.
portal = getToolByName(self.context.context, 'portal_url').getPortalObject()
plone_utils = getToolByName(self.context.context, 'plone_utils')
settings = component.getUtility(IRegistry).forInterface(ITabellioSettings, False)
topic_email = get_email_for_subject(self.context, data.get('subject'))
try:
sendmail(self.context.context, data, topic_email)
except: # TODO Too many things could possibly go wrong. So we catch all.
plone_utils = getToolByName(self.context.context, 'plone_utils')
exception = plone_utils.exceptionString()
message = _(u'Unable to send mail: ${exception}',
mapping={u'exception' : exception})
plone_utils.addPortalMessage(message, 'error')
return self.request.response.redirect('.')
plone_utils.addPortalMessage(_(u'Your message has been sent successfully.'))
return self.request.response.redirect(portal.absolute_url())
except ValidationError:
pass
return
def cmp_person(x, y):
t = cmp(x.lastname.lower(), y.lastname.lower())
if t: return t
return cmp(x.firstname.lower(), y.lastname.lower())
@grok.provider(IContextSourceBinder)
def get_deputies(context):
portal = getToolByName(context.context, 'portal_url').getPortalObject()
settings = component.getUtility(IRegistry).forInterface(ITabellioSettings, False)
path = settings.deputiesPath
current = portal
for part in settings.deputiesPath.split('/'):
if not part:
continue
current = getattr(current, part)
deputies = []
for object in current.objectValues():
if object.portal_type != 'themis.datatypes.deputy':
continue
if not object.active:
continue
deputies.append(object)
deputies.sort(cmp_person)
terms = []
for deputy in deputies:
deputy_id = deputy.getId()
terms.append(SimpleVocabulary.createTerm(deputy_id, deputy_id, deputy.Title()))
return SimpleVocabulary(terms)
class Deputy(grok.View):
grok.context(IContactForm)
grok.require('zope2.View')
grok.name('deputy')
def deputy_contact_form(self):
effective_contact = EffectiveDeputyContact(self.context)
effective_form = EffectiveDeputyContactForm(effective_contact, self.request)
effective_form.update()
return effective_form.render()
class IEffectiveDeputyContact(interface.Interface):
deputy = schema.Choice(title=_(u'Deputy'), required=True,
source=get_deputies)
subject = schema.TextLine(title=_(u'Subject'), required=True)
name = schema.TextLine(title=_(u'Name'), required=True)
email = schema.TextLine(title=_(u'Email'), required=True)
phone = schema.TextLine(title=_(u'Phone'), required=False)
message = schema.Text(title=_(u'Message'), required=True)
captcha = schema.TextLine(title=_(u'Please type the different chars'), required=False)
class EffectiveDeputyContact(object):
implements(IEffectiveDeputyContact)
def __init__(self, context=None):
self.context = context
def absolute_url(self):
# this is used by the captcha
return self.context.absolute_url()
class EffectiveDeputyContactForm(form.Form):
fields = field.Fields(IEffectiveDeputyContact)
fields['captcha'].widgetFactory = CaptchaFieldWidget
template = ViewPageTemplateFile('form_templates/view_effectivedeputycontact.pt')
def updateWidgets(self):
super(EffectiveDeputyContactForm, self).updateWidgets()
self.widgets['message'].rows = 10
@button.buttonAndHandler(_(u'Send'))
def handleApply(self, action):
data, errors = self.extractData()
if not errors and data.has_key('captcha'):
# Verify the user input against the captcha
try:
captcha = CaptchaValidator(self.context, self.request, None,
IEffectiveDeputyContact['captcha'], None)
if captcha.validate(data['captcha']):
# if captcha validation passes, send the email.
portal = getToolByName(self.context.context, 'portal_url').getPortalObject()
plone_utils = getToolByName(self.context.context, 'plone_utils')
settings = component.getUtility(IRegistry).forInterface(ITabellioSettings, False)
path = settings.deputiesPath
current = portal
for part in settings.deputiesPath.split('/'):
if not part:
continue
current = getattr(current, part)
deputy = getattr(current, data.get('deputy'))
deputy_email = None
if deputy.work_address:
deputy_email = deputy.work_address.email
if not deputy_email and deputy.work_address_2:
deputy_email = deputy.work_address_2.email
if not deputy_email and deputy.private_address:
deputy_email = deputy.private_address.email
try:
sendmail(self.context.context, data, deputy_email)
except: # TODO Too many things could possibly go wrong. So we catch all.
plone_utils = getToolByName(self.context.context, 'plone_utils')
exception = plone_utils.exceptionString()
message = _(u'Unable to send mail: ${exception}',
mapping={u'exception' : exception})
plone_utils.addPortalMessage(message, 'error')
return self.request.response.redirect('deputy')
plone_utils.addPortalMessage(_(u'Your message has been sent successfully.'))
return self.request.response.redirect(portal.absolute_url())
except ValidationError:
pass
return
# Register Captcha validator for the captcha field in the IContactForm
validator.WidgetValidatorDiscriminators(CaptchaValidator, field=IEffectiveContact['captcha'])
def sendmail(context, data, mto):
urltool = getToolByName(context, 'portal_url')
portal = urltool.getPortalObject()
send_to_address = portal.getProperty('email_from_address')
envelope_from = portal.getProperty('email_from_address')
encoding = portal.getProperty('email_charset')
message = _(u"""De: %(name)s (phone: %(phone)s, email: %(email)s)
Subject: %(subject)s
Message:
%(message)s
""") % data
u_message = message
message = message.encode(encoding)
context.MailHost.send('\n\n'+message, mto, envelope_from,
subject=_(u'New message from %s') % portal.title)
# and now, send a copy to the sender
if data.get('email'):
message = _(u"""Your message has been sent, here's a copy for reference.
%(message)s
""" % {'message': u_message})
try:
context.MailHost.send('\n\n'+message, data.get('email'), envelope_from,
subject=_(u'Your message on %s') % portal.title)
except:
# ignore everything here, as the most important part has been done
# successfully
pass