class SetMeetingTitleOnApproved(BaseSubstitution): category = _(u'Approve Subscriber') description = _(u'Meeting title') def safe_call(self): """ Safe call """ if self.context.portal_type == 'eea.meeting.subscriber': """ This is the case for approving a subscriber: - Thank you for your registration """ meeting = self.context.aq_parent.aq_parent elif self.context.portal_type == 'eea.meeting': """ This is the case for new subscriber registered: - A new participant has registered to the meeting - You have registered to the meeting """ meeting = self.context try: title = meeting.title except Exception: title = "" return title
class SendEmail(form.Form): fields = field.Fields(IEmail) ignoreContext = True label = _(u"Send email") fields['receiver'].widgetFactory = CheckBoxFieldWidget prefix = 'send_email' template = FPT('main_form.pt') def update(self): super(SendEmail, self).update() self.search_user = SearchUser(self.context, self.request, self) self.search_user.update() self.widgets['body'].rows = 10 if (not self.actions.executedActions and not self.widgets['receiver'].items): for widget in self.widgets.values(): widget.disabled = 'disabled' self.actions['send_email'].disabled = 'disabled' msg = 'There are no subscribed users. Cannot send email.' IStatusMessage(self.request).addStatusMessage(msg, type='error') @button.buttonAndHandler(_('Send Email'), name='send_email') def handleSave(self, action): data, errors = self.extractData() if errors: return False types = api.portal.get_tool('portal_types') type_info = types.getTypeInfo('eea.meeting.email') name_chooser = INameChooser(self.context) content_id = name_chooser.chooseName(data['subject'], self.context) obj = type_info._constructInstance(self.context, content_id) obj.title = data['subject'] obj.sender = data['sender'] obj.receiver = data['receiver'] obj.cc = data['cc'] obj.subject = data['subject'] obj.body = data['body'] obj.reindexObject() notify(SendEmailAddEvent(self.context, data)) msg = _(u"Email successfully sent") IStatusMessage(self.request).addStatusMessage(msg, type='info') self.request.response.redirect( self.context.getParentNode().absolute_url()) @button.buttonAndHandler(_('Cancel'), name='cancel_send') def cancel_send(self, action): return self.request.response.redirect( self.context.aq_parent.absolute_url())
class ISubscriber(Interface): """ Meeting subscriber """ userid = schema.TextLine(title=_("User id"), required=True) email = schema.TextLine(title=_(u"Email"), required=True, constraint=validate_email)
class IEmail(Interface): """ Email """ sender = Email( title=_(u"From"), required=True, ) receiver = schema.Set( title=u'Recipients', value_type=schema.Choice( vocabulary='eea.meeting.vocabularies.RecipientsVocabulary')) cc = schema.Text( title=_(u"CC"), description=_(u'Add CC addresses one per line, no separator'), constraint=cc_constraint, required=False, ) subject = schema.TextLine( title=_(u"Subject"), required=True, ) body = RichText( title=_(u"Body"), required=True, output_mime_type='text/plain', allowed_mime_types=('text/html', 'text/structured', 'text/plain'), ) directives.widget('sender', TextFieldWidget, klass=u'mail_widget')
class SearchUser(form.Form): fields = field.Fields(ISearchUser) ignoreContext = True fields['results'].widgetFactory = CustomCheckBoxFieldWidget prefix = 'search_user' template = FiveViewPageTemplateFile('search_user.pt') _parent_form = None def __init__(self, context, request, parent_form=None): super(SearchUser, self).__init__(context, request) self._parent_form = parent_form @button.buttonAndHandler(_('Search'), name='search_user') def handleSave(self, action): data, errors = self.extractData() if errors: return False @button.buttonAndHandler(_('Add'), name='addCC') def handle_addCC(self, action): data, errors = self.extractData() self._parent_form.widgets['cc'].value += '\n'+"\n".join(data['results']) del self.widgets['results'].items self.widgets['results'].value = '' if errors: return False
class SendEmail(form.Form): fields = field.Fields(IEmail) ignoreContext = True label = _(u"Send email") fields['receiver'].widgetFactory = CheckBoxFieldWidget prefix = 'send_email' template = FiveViewPageTemplateFile('main_form.pt') def update(self): super(SendEmail, self).update() self.search_user = SearchUser(self.context, self.request, self) self.search_user.update() @button.buttonAndHandler(_('Send Email'), name='send_email') def handleSave(self, action): data, errors = self.extractData() if errors: return False types = api.portal.get_tool('portal_types') type_info = types.getTypeInfo('eea.meeting.email') name_chooser = INameChooser(self.context) content_id = name_chooser.chooseName(data['subject'], self.context) obj = type_info._constructInstance(self.context, content_id) obj.title = data['subject'] obj.sender = data['sender'] obj.receiver = "\r\n".join(data['receiver']) data['receiver'] = obj.receiver obj.cc = data['cc'] obj.subject = data['subject'] obj.body = data['body'] obj.reindexObject() notify(SendEmailAddEvent(self.context, data)) msg = _(u"Email successfully sent") IStatusMessage(self.request).addStatusMessage(msg, type='info') self.request.response.redirect(self.context.getParentNode().absolute_url())
class SetMeetingContactEmail(BaseSubstitution): category = _(u'eea.meeting') description = _(u'Meeting contact email') def safe_call(self): """ Safe call """ try: email = self.context.contact_email except Exception: email = '' return email
class SetMeetingPlaceOnApproved(BaseSubstitution): category = _(u'Approve Subscriber') description = _(u'Meeting place') def safe_call(self): """ Safe call """ try: location = self.context.aq_parent.aq_parent.location except Exception: location = "" return location
class SetNameReceiverOnApproved(BaseSubstitution): category = _(u'Approve Subscriber') description = _(u'Subscriber Name') def safe_call(self): """ Safe call """ try: return self.context.get_details().get('fullname', 'user') except Exception: name = 'user' return name
class SetEmailReceiverOnApproved(BaseSubstitution): category = _(u'Approve Subscriber') description = _(u'Subscriber Email') def safe_call(self): """ Safe call """ try: email = self.context.email except Exception: email = '' return email
class SetMeetingURL(BaseSubstitution): category = _(u'eea.meeting') description = _(u'Finds the closest meeting and returns it\'s URL.') def safe_call(self): """ Safe call """ def find_meeting(context): return ( IMeeting.providedBy(context) and context or find_meeting(context.aq_parent) ) meeting = find_meeting(self.context) return meeting.absolute_url() if meeting else ''
def cc_constraint(value): for idx, email in enumerate(value): idx += 1 if not re.match(r"[^@]+@[^@]+\.[^@]+", email): raise Invalid(_(u"Invalid email address on line %d" % idx)) return True
def handleSave(self, action): data, errors = self.extractData() if errors: return False types = api.portal.get_tool('portal_types') type_info = types.getTypeInfo('eea.meeting.email') name_chooser = INameChooser(self.context) content_id = name_chooser.chooseName(data['subject'], self.context) obj = type_info._constructInstance(self.context, content_id) obj.title = data['subject'] obj.sender = data['sender'] obj.receiver = data['receiver'] obj.cc = data['cc'] obj.subject = data['subject'] obj.body = data['body'] obj.reindexObject() notify(SendEmailAddEvent(self.context, data)) msg = _(u"Email successfully sent") IStatusMessage(self.request).addStatusMessage(msg, type='info') self.request.response.redirect( self.context.getParentNode().absolute_url())
def handleSave(self, action): data, errors = self.extractData() if errors: return False types = api.portal.get_tool('portal_types') type_info = types.getTypeInfo('eea.meeting.email') name_chooser = INameChooser(self.context) content_id = name_chooser.chooseName(data['subject'], self.context) obj = type_info._constructInstance(self.context, content_id) obj.title = data['subject'] obj.sender = data['sender'] obj.receiver = "\r\n".join(data['receiver']) data['receiver'] = obj.receiver obj.cc = data['cc'] obj.subject = data['subject'] obj.body = data['body'] obj.reindexObject() notify(SendEmailAddEvent(self.context, data)) msg = _(u"Email successfully sent") IStatusMessage(self.request).addStatusMessage(msg, type='info') self.request.response.redirect(self.context.getParentNode().absolute_url())
def cc_constraint(value): data_lines = value.split('\r\n') for idx, email in enumerate(data_lines): idx += 1 if not re.match(r"[^@]+@[^@]+\.[^@]+", email): raise Invalid(_(u"Invalid email address on line %d" % idx)) return True
class IMeeting(Interface): """ Meeting """ text = RichText( title=_(u"Body text"), required=True, ) meeting_type = schema.Choice( title=_(u"Meeting type"), vocabulary=meeting_types, required=True, ) allow_register = schema.Bool( title=_(u"Allow users to register to the meeting"), required=True, ) restrict_content_access = schema.Bool( title=(u"Restrict user access to the contents in the meeting"), required=True) auto_approve = schema.Bool( title=_(u"Automatically approve registrations"), required=True, ) max_participants = schema.Int( title=_(u"Maximum number of participants"), required=True, ) contact_name = schema.TextLine( title=_(u"Contact person"), required=True, ) contact_email = schema.TextLine(title=_(u"Contact email"), required=True, constraint=validate_email) location = schema.TextLine(title=_(u'label_event_location', default=u'Location'), description=_( u'help_event_location', default=u'Location of the event.'), required=True, default=None)
class ISearchUser(Interface): """ Search user """ containing = schema.TextLine( title=_(u"Add users to E-mail CC"), required=True, ) results = schema.Set( required=False, value_type=schema.Choice( vocabulary='eea.meeting.vocabularies.LDAPListingVocabulary'))
class IEmail(Interface): """ Email """ sender = Email( title=_(u"From"), required=True, ) receiver = schema.Set( title=u'Recipients', missing_value=set(), value_type=schema.Choice( vocabulary='eea.meeting.vocabularies.RecipientsVocabulary', required=True, ), required=True, ) cc = schema.List( title=_(u"CC"), description=_(u'Add CC addresses one per line, no separator'), value_type=schema.TextLine(), constraint=cc_constraint, required=False, ) subject = schema.TextLine( title=_(u"Subject"), required=True, ) body = schema.Text( title=_(u"Body"), required=True, ) email_type = schema.TextLine( title=_(u"Email type"), required=False, ) directives.widget('sender', TextFieldWidget, klass=u'mail_widget')
class RegisterUser(BrowserView): """ Register a user """ label = _(u"Register user") def __init__(self, context, request): super(RegisterUser, self).__init__(context, request) self._searchString = '' @property def searchString(self): """ Search string """ if not self._searchString: self._searchString = self.request.get('searchstring', '') return self._searchString @property def users(self): """ Users """ if not self.searchString: return [] site = getSite() cpanel = getMultiAdapter((site, self.request), name=u"usergroup-userprefs") return cpanel.doSearch(self.searchString) def _register(self, users): """ Register users """ subscribers = self.context.get('subscribers') emails = [sub.email for sub in subscribers.values()] for username in users: user = api.user.get(username) fullname = user.getProperty('fullname', username) email = user.getProperty('email') if email in emails: continue createContentInContainer(subscribers, 'eea.meeting.subscriber', checkConstraints=False, title=fullname, id=username, userid=username, email=email) IStatusMessage(self.request).addStatusMessage( "Users registered to this meeting", type="info") return self.request.response.redirect(self.context.absolute_url() + '/register_user') def __call__(self, *args, **kwargs): if self.request.method.lower() != 'post': return self.index() if not self.request.get('form.button.register', None): return self.index() users = self.request.get('users', []) if not users: return self.index() return self._register(users)
# -*- coding: utf-8 -*- from eea.meeting import _ from eea.meeting.interfaces.util import validate_email from plone.app.textfield import RichText from zope import schema from zope.interface import Interface from zope.interface import invariant, Invalid from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm meeting_types = SimpleVocabulary([ SimpleTerm(value=u'meeting', title=_(u'Meeting')), SimpleTerm(value=u'conference', title=_(u'Conference')), SimpleTerm(value=u'workshop', title=_(u'Workshop')), SimpleTerm(value=u'webinar', title=_(u'Webinar')) ]) meeting_levels = SimpleVocabulary([ SimpleTerm(value=u'national', title=_(u'National Level')), SimpleTerm(value=u'regional', title=_(u'Regional Level')), SimpleTerm(value=u'other', title=_(u'Other')) ]) class IMeeting(Interface): """ Meeting """ text = RichText( title=_(u"Body text"), required=True, )
def validate_location_required(data): if data.meeting_type != 'webinar' and data.location is None: raise Invalid(_( u"Event location input is missing." + " This field is not required only in " + "'Meeting type: webinar' case."))
from eea.meeting.interfaces.util import validate_userid from plone.app.textfield import RichText from plone.namedfile.field import NamedBlobFile from zope import schema from zope.interface import Interface from zope.interface import invariant, Invalid from zope.interface import provider from zope.schema.interfaces import IVocabularyFactory from zope.schema.vocabulary import SimpleTerm from zope.schema.vocabulary import SimpleVocabulary import datetime meeting_types = SimpleVocabulary( [ SimpleTerm(value=u'conference', title=_(u'Conference')), SimpleTerm(value=u'meeting', title=_(u'Meeting')), SimpleTerm(value=u'workshop', title=_(u'Workshop')), SimpleTerm(value=u'webinar', title=_(u'Webinar')), SimpleTerm(value=u'eionet-copernicus-nrc-lc-meeting', title=_(u'EIONET Copernicus NRC LC Meeting')), SimpleTerm(value=u'other', title=_(u'Other')), ] ) class IMeeting(Interface): """ Meeting """ text = RichText( title=_(u"Body text"), required=True,
class IMeeting(Interface): """ Meeting """ text = RichText( title=_(u"Body text"), required=True, ) meeting_type = schema.Choice( title=_(u"Meeting type"), vocabulary=meeting_types, required=True, ) allow_register = schema.Bool( title=_(u"Allow users to register for the meeting"), required=True, ) allow_register_above_max = schema.Bool( title=_(u"Continue to allow registration when maximum number of" " participants is reached"), required=True, ) allow_register_start = schema.Datetime( title=_(u"From"), description=_(u"Allow registration starting with this datetime."), required=False, min=datetime.datetime(2018, 1, 1), max=datetime.datetime(datetime.datetime.now().year + 10, 12, 31) ) allow_register_end = schema.Datetime( title=_(u"To"), description=_(u"Allow registration until this datetime."), required=False, min=datetime.datetime(2018, 1, 1), max=datetime.datetime(datetime.datetime.now().year + 10, 12, 31) ) need_e_pass = schema.Bool( title=_(u"E-pass is required"), required=True, ) is_unlisted = schema.Bool( title=_(u"Make this event unlisted"), required=True, ) restrict_content_access = schema.Bool( title=_(u"Hide the content of Additional materials table for not " "registered users"), required=True ) auto_approve = schema.Bool( title=_(u"Automatically approve registrations"), required=True, ) max_participants = schema.Int( title=_(u"Maximum number of subscribers"), required=True, ) hosting_organisation = schema.TextLine( title=_(u"Supporting organisations"), required=True, default=None, ) contact_name = schema.TextLine( title=_(u"Contact name"), required=True, ) contact_email = schema.TextLine( title=_(u"Contact email"), required=True, constraint=validate_email ) location = schema.TextLine( title=_( u'label_event_location', default=u'Event location' ), description=_( u'help_event_location', default=u'Location of the event.' ), required=False, default=None ) agenda = NamedBlobFile( title=_(u"Event agenda"), description=_(u"Upload your agenda file."), required=False, ) event_timezone = schema.TextLine( title=_(u"Event timezone info"), description=_(u"Human readable info about timezone for this event."), required=False, default=_(u"Time zone: Copenhagen, Denmark"), ) @invariant def validate_location_required(data): if data.meeting_type != 'webinar' and data.location is None: raise Invalid(_( u"Event location input is missing." + " This field is not required only in " + "'Meeting type: webinar' case."))
class ISubscriber(Interface): """ Meeting subscriber """ userid = schema.TextLine( title=_("User id"), required=True, constraint=validate_userid, ) email = schema.TextLine( title=_(u"Email"), required=True, constraint=validate_email ) # directives.widget(reimbursed=RadioFieldWidget) # reimbursed = schema.Bool( # title=_(u"Reimbursed participation"), # required=True # ) role = schema.Choice( title=_(u"Role"), vocabulary="subscriber_roles", required=True, ) role_other = schema.TextLine( title=_(u"Role (other)"), required=False, ) delegate_type = schema.Choice( title=_(u"Delegate type"), vocabulary="subscriber_delegate_types", required=True, ) date_of_birth = schema.Date( title=_(u"DATE OF BIRTH"), required=False, min=datetime.date(1900, 1, 1), max=datetime.date(2050, 1, 1), ) nationality = schema.TextLine( title=_(u"NATIONALITY"), required=False, ) id_card_nbr = schema.TextLine( title=_(u"ID CARD NBR"), required=False, ) id_valid_date = schema.Date( title=_(u"ID VALID DATE"), required=False, min=datetime.date(1900, 1, 1), max=datetime.date(2050, 1, 1), ) request_data_deletion = schema.Bool( title=_(u"Request account deletion"), description=_(u"Please delete my account on the website after the " "event has ended, latest after 4 weeks.") )
class SetEmailReceiver(SetEmailSubstitution): category = _(u'Email Send') description = _(u'Email receiver address') attribute = u'receiver'
class IMeeting(Interface): """ Meeting """ text = RichText( title=_(u"Body text"), required=True, ) meeting_type = schema.Choice( title=_(u"Meeting type"), vocabulary=meeting_types, required=True, ) meeting_level = schema.Choice( title=_(u"Meeting level"), vocabulary=meeting_levels, required=True, ) allow_register = schema.Bool( title=_(u"Allow users to register to the meeting"), required=True, ) allow_register_start = schema.Datetime( title=_(u"From"), description=_(u"Allow registration starting with this datetime."), required=False, ) allow_register_end = schema.Datetime( title=_(u"To"), description=_(u"Allow registration until this datetime."), required=False, ) restrict_content_access = schema.Bool(title=_( u"Hide the content of Additional materials table for not " "registered users"), required=True) auto_approve = schema.Bool( title=_(u"Automatically approve registrations"), required=True, ) max_participants = schema.Int( title=_(u"Maximum number of participants"), required=True, ) hosting_organisation = schema.TextLine( title=_(u"Hosting organisation"), required=True, default=None, ) contact_name = schema.TextLine( title=_(u"Contact person"), required=True, ) contact_email = schema.TextLine(title=_(u"Contact email"), required=True, constraint=validate_email) location = schema.TextLine(title=_(u'label_event_location', default=u'Event location'), description=_( u'help_event_location', default=u'Location of the event.'), required=False, default=None) @invariant def validate_location_required(data): if data.meeting_type != 'webinar' and data.location is None: raise Invalid( _(u"Event location input is missing." + " This field is not required only in " + "'Meeting type: webinar' case."))
from zope.interface import Interface from zope.publisher.interfaces.browser import IDefaultBrowserLayer from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm from Products.CMFDefault.utils import checkEmailAddress from Products.CMFDefault.exceptions import EmailAddressInvalid from plone.app.textfield import RichText from plone.schema import Email from plone.autoform import directives from z3c.form.browser.text import TextFieldWidget from zope.interface import Invalid import re meeting_types = SimpleVocabulary([ SimpleTerm(value=u'meeting', title=_(u'Meeting')), SimpleTerm(value=u'conference', title=_(u'Conference')), SimpleTerm(value=u'workshop', title=_(u'Workshop')) ]) def validate_email(email): try: checkEmailAddress(email) except EmailAddressInvalid: raise EmailAddressInvalid(email) return True def cc_constraint(value): data_lines = value.split('\r\n')
class SetEmailSubject(SetEmailSubstitution): category = _(u'Email Send') description = _(u'Email subject') attribute = u'subject'
def validate_userid(userid): user = api.user.get(userid=userid) if user: return True raise Invalid(_(u'User does not exist!'))
class SetEmailCC(SetEmailSubstitution): category = _(u'Email Send') description = _(u'Email CC addresses') attribute = u'cc'
class SetEmailBody(SetEmailSubstitution): category = _(u'Email Send') description = _(u'Email body') attribute = u'body'