class IMailAction(Interface): """Definition of the configuration available for a mail action """ subject = schema.TextLine(title=_(u'Subject'), description=_(u'Subject of the message'), required=True) source = schema.TextLine( title=_(u'Email source'), description=_( 'The email address that sends the email. If no email is provided ' 'here, it will use the portal from address.'), required=False) recipients = schema.TextLine( title=_(u'Email recipients'), description=_( 'The email where you want to send this message. To send it to ' 'different email addresses, just separate them with ,'), required=True) exclude_actor = schema.Bool( title=_(u'Exclude actor from recipients'), description=_( 'Do not send the email to the user that did the action.')) message = schema.Text(title=_(u'Message'), description=_(u'The message that you want to mail.'), required=True)
def ruleTypesToShow(self): selector = [] for event in self._events(): eventname = translate(event.token, context=self.request, domain='plone') selector.append( dict(id="trigger-" + event.value.__identifier__, title=_(u"Trigger: ${name}", mapping={'name': eventname})), ) selector += ( { 'id': 'state-enabled', 'title': _(u"label_rule_enabled", default=u"Enabled") }, { 'id': 'state-disabled', 'title': _(u"label_rule_disabled", default=u"Disabled"), }, # {'id': 'state-rule-assigned', 'title': _(u"Rule is in use")}, # {'id': 'state-rule-not-assigned', 'title': _(u"Rule is not assigned anywhere"), }, ) return selector
def __call__(self): context = aq_inner(self.context) request = aq_inner(self.request) form = request.form status = IStatusMessage(self.request) operation = request.get('operation', None) if operation == 'move_up': assignable = IRuleAssignmentManager(context) rule_id = request.get('rule_id') keys = list(assignable.keys()) idx = keys.index(rule_id) del keys[idx] keys.insert(idx - 1, rule_id) assignable.updateOrder(keys) elif operation == 'move_down': assignable = IRuleAssignmentManager(context) rule_id = request.get('rule_id') keys = list(assignable.keys()) idx = keys.index(rule_id) del keys[idx] keys.insert(idx + 1, rule_id) assignable.updateOrder(keys) elif 'form.button.AddAssignment' in form: rule_id = form.get('rule_id') api.assign_rule(self.context, rule_id) elif 'form.button.Delete' in form: rule_ids = form.get('rule_ids', ()) for r in rule_ids: api.unassign_rule(self.context, r) status.addStatusMessage(_(u'Assignments deleted.'), type='info') elif 'form.button.Enable' in form: rule_ids = form.get('rule_ids', ()) for r in rule_ids: api.edit_rule_assignment(context, r, enabled=True) status.addStatusMessage(_(u'Assignments enabled.'), type='info') elif 'form.button.Disable' in form: rule_ids = form.get('rule_ids', ()) for r in rule_ids: api.edit_rule_assignment(context, r, enabled=False) status.addStatusMessage(_(u'Assignments disabled.'), type='info') elif 'form.button.Bubble' in form: rule_ids = form.get('rule_ids', ()) for r in rule_ids: api.edit_rule_assignment( context, r, bubbles=True, enabled=True) status.addStatusMessage(_(u'Changes saved.'), type='info') elif 'form.button.NoBubble' in form: rule_ids = form.get('rule_ids', ()) for r in rule_ids: api.edit_rule_assignment(context, r, bubbles=False) status.addStatusMessage(_(u'Changes saved.'), type='info') return self.template()
class IMailAction(Interface): """Definition of the configuration available for a mail action """ subject = schema.TextLine(title=_(u"Subject"), description=_(u"Subject of the message"), required=True) source = schema.TextLine(title=_(u"Email source"), description=_( "The email address that sends the " "email. If no email is provided here, " "it will use the portal from address."), required=False) recipients = schema.TextLine(title=_(u"Email recipients"), description=_( "The email where you want to " "send this message. To send it to " "different email addresses, " "just separate them with ,"), required=True) exclude_actor = schema.Bool(title=_(u"Exclude actor from recipients"), description=_( "Do not send the email to the user " "that did the action.")) message = schema.Text(title=_(u"Message"), description=_(u"The message that you want to mail."), required=True)
class CopyAddForm(ActionAddForm): """An add form for move-to-folder actions. """ schema = ICopyAction label = _(u'Add Copy Action') description = _(u'A copy action can copy an object to a different folder.') Type = CopyAction
class WebSocketAddForm(ActionAddForm): """ An add form for the websocket action """ schema = IWebSocketAction label = _(u"Add WebSocket Action") description = _(u"A websocket action can publish an " u"interpolated JSON payload.") form_name = _(u"Configure element") Type = WebSocketAction if PLONE_4: form_fields = form.FormFields(IWebSocketAction) template = ViewPageTemplateFile( os.path.join("templates", "websocket_p4.pt")) def create(self, data): a = WebSocketAction() form.applyChanges(a, self.form_fields, data) return a else: template = ViewPageTemplateFile( os.path.join("templates", "websocket.pt"))
class PortalTypeEditForm(EditForm): """An edit form for portal type conditions """ form_fields = form.FormFields(IPortalTypeCondition) label = _(u"Edit Content Type Condition") description = _(u"A portal type condition makes the rule apply only to certain content types.") form_name = _(u"Configure element")
class RuleAddForm(AddForm): """An add form for rules. """ schema = IRuleConfiguration ignoreContext = True label = _(u'Add Rule') description = _(u'Add a new rule. Once complete, you can manage the ' u"rule's actions and conditions separately.") def nextURL(self): context = aq_parent(aq_inner(self.context)) url = str( getMultiAdapter((context, self.request), name=u'absolute_url')) if base_hasattr(self.context, '_chosen_name'): return '{0}/++rule++{1}/@@manage-elements'.format( url, self.context._chosen_name, ) else: return '{0}/@@rules-controlpanel'.format(url) def create(self, data): rule = Rule() applyChanges(self, rule, data) return rule
class SubstitutionWorkflowTransitionRelatedItems(CommentSubstitution): """ Add substitution option to find the workflow transition. """ category = _(u'All Content') description = _(u'Workflow transition of the related items.') attribute = u'workflow_transition'
class SubstitutionFailedRelatedItems(CommentSubstitution): """ Add substitution option for workflow transition chnaged with failure. """ category = _(u'All Content') description = _(u'All the items that failed to changed transition.') attribute = u'workflow_transition_items_unchanged'
class SubstitutionSucceededRelatedItems(CommentSubstitution): """ Add substitution option for workflow transition changed with success. """ category = _(u'All Content') description = _(u'All the items that changed transition with success.') attribute = u'workflow_transition_items_changed'
class AddForm(AutoExtensibleForm, form.AddForm): """A base add form for content rule. Use this for rule elements that require configuration before being added to a rule. Element types that do not should use NullAddForm instead. Sub-classes should define create() and set the form_fields class variable. Notice the suble difference between AddForm and NullAddform in that the create template method for AddForm takes as a parameter a dict 'data': def create(self, data): return MyAssignment(data.get('foo')) whereas the NullAddForm has no data parameter: def create(self): return MyAssignment() """ implements(IContentRulesForm) ignoreContext = True def updateActions(self): super(AddForm, self).updateActions() self.actions['save'].addClass("context") self.actions['cancel'].addClass("standalone") def nextURL(self): rule = aq_parent(aq_inner(self.context)) context = aq_parent(aq_inner(rule)) url = str( getMultiAdapter((context, self.request), name=u"absolute_url")) focus = self.context.id.strip('+') return '%s/++rule++%s/@@manage-elements#%s' % (url, rule.__name__, focus) def add(self, content): self.context.add(content) @button.buttonAndHandler(_(u"label_save", default=u"Save"), name='save') def handle_save_action(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return content = self.create(data) self.add(content) nextURL = self.nextURL() if nextURL: self.request.response.redirect(self.nextURL()) @button.buttonAndHandler(_(u"label_cancel", default=u"Cancel"), name='cancel') def handle_cancel_action(self, action): nextURL = self.nextURL() if nextURL: self.request.response.redirect(self.nextURL()) return ''
def summary(self): skos = self.skos if not skos: msg = _(u"Nenhum termo selecionado") else: msg = _(u"VCGE contém ${skos}", mapping=dict(skos=" or ".join(skos))) return msg
class SetEffectiveDateEditForm(EditForm): """An edit form for the action """ label = _(u"Edit Set effective/publishing date action") description = _(u"Set effective/publishing date if missing; " + u"add an entry in object's workflow history") form_name = _(u"Configure action") form_fields = form.FormFields(ISetEffectiveDateAction)
class TalesExpressionEditForm(EditForm): """An edit form for TALES expression condition """ form_fields = form.FormFields(ITalesExpressionCondition) label = _(u"Edit TALES Expression Condition") description = _(u"A TALES expression condition makes the rule apply " "only if TALES expression is not False in context.") form_name = _(u"Configure element")
class GroupEditForm(EditForm): """An edit form for group conditions """ form_fields = form.FormFields(IGroupCondition) label = _(u"Edit Group Condition") description = _(u"A group condition can prevent a rule from executing " "unless the current user is a member of a particular group.") form_name = _(u"Configure element")
def summary(self): skos = self.skos if not skos: msg = _(u'Nenhum termo selecionado') else: msg = _(u'VCGE contém ${skos}', mapping=dict(skos=' or '.join(skos))) return msg
class WorkflowEditForm(ActionEditForm): """An edit form for workflow rule actions. """ schema = IWorkflowAction label = _(u'Edit Workflow Action') description = _( u'A workflow action triggers a workflow transition on an object.') form_name = _(u'Configure element')
class RelatedItemsEditForm(EditForm): """ An add form for the related items action """ form_fields = form.FormFields(IRelatedItemsAction) label = _(u"Add Related Items Action") description = _(u"Change workflow state for related items.") form_name = _(u"Configure element")
class WorkflowEditForm(EditForm): """An edit form for workflow rule actions. """ form_fields = form.FormFields(IWorkflowAction) label = _(u"Edit Workflow Action") description = _( u"A workflow action triggers a workflow transition on an object.") form_name = _(u"Configure element")
class MoveAddForm(ActionAddForm): """An add form for move-to-folder actions. """ schema = IMoveAction label = _(u'Add Move Action') description = _(u'A move action can move an object to a different folder.') form_name = _(u'Configure element') Type = MoveAction
class TalesExpressionEditForm(EditForm): """An edit form for TALES expression condition """ schema = ITalesExpressionCondition label = _(u'Edit TALES Expression Condition') description = _(u'A TALES expression condition makes the rule apply ' u'only if TALES expression is not False in context.') form_name = _(u'Configure element')
class NotifyAddForm(ActionAddForm): """An add form for notify rule actions. """ schema = INotifyAction label = _(u'Add Notify Action') description = _(u'A notify action can show a message to the user.') form_name = _(u'Configure element') Type = NotifyAction
def summary(self): subject = self.subject if not subject: msg = _(u"No tags selected") else: msg = _(u"Tags contains ${tags}", mapping=dict(tags=" or ".join(subject))) return msg
class LoggerAddForm(ActionAddForm): """An add form for logger rule actions. """ schema = ILoggerAction label = _(u'Add Logger Action') description = _(u'A logger action can output a message to the system log.') form_name = _(u'Configure element') Type = LoggerAction
class LoggerEditForm(ActionEditForm): """An edit form for logger rule actions. z3c.form does all the magic here. """ schema = ILoggerAction label = _(u'Edit Logger Action') description = _(u'A logger action can output a message to the system log.') form_name = _(u'Configure element')
class IFileExtensionCondition(Interface): """Interface for the configurable aspects of a portal type condition. This is also used to create add and edit forms, below. """ file_extension = schema.TextLine(title=_(u"File extension"), description=_(u"The file extension to check for"), required=True)
def summary(self): same_as_parent = self.same_as_parent skos = self.skos if same_as_parent: msg = _(u"Aplica termos da pasta no conteúdo.") else: msg = _(u"Aplica os termos ${skos}", mapping=dict(skos=", ".join(skos))) return msg
def summary(self): same_as_parent = self.same_as_parent skos = self.skos if same_as_parent: msg = _(u'Aplica termos da pasta no conteúdo.') else: msg = _(u'Aplica os termos ${skos}', mapping=dict(skos=', '.join(skos))) return msg
class WorkflowAddForm(ActionAddForm): """An add form for workflow actions. """ schema = IWorkflowAction label = _(u'Add Workflow Action') description = _( u'A workflow action triggers a workflow transition on an object.') form_name = _(u'Configure element') Type = WorkflowAction
class PortalTypeEditForm(EditForm): """An edit form for portal type conditions """ schema = IPortalTypeCondition label = _(u'Edit Content Type Condition') description = _( u'A portal type condition makes the rule apply only to certain ' u'content types.') form_name = _(u'Configure element')
def statesToShow(self): return ( { 'id': 'state-enabled', 'title': _(u'label_rule_enabled', default=u'Enabled'), }, { 'id': 'state-disabled', 'title': _(u'label_rule_disabled', default=u'Disabled'), }, )
def __call__(self): redirect = False form = self.request.form idx = form.get('element_id', 0) rule = aq_inner(self.context) status = IStatusMessage(self.request) if 'form.button.Save' in form: self.authorize() rule.title = form.get('title', rule.title) rule.description = form.get('description', rule.description) rule.stop = bool(form.get('stopExecuting', False)) rule.cascading = bool(form.get('cascading', False)) rule.enabled = bool(form.get('enabled', False)) status.addStatusMessage(_(u'Changes saved.'), type='info') elif 'form.button.EditCondition' in form: editview = self.conditions()[idx]['editview'] self.request.response.redirect(editview) redirect = True elif 'form.button.DeleteCondition' in form: self.authorize() del rule.conditions[idx] status.addStatusMessage(_(u'Condition deleted.'), type='info') elif 'form.button.MoveConditionUp' in form: self._move_up(rule.conditions, idx) status.addStatusMessage(_(u'Condition moved up.'), type='info') elif 'form.button.MoveConditionDown' in form: self._move_down(rule.conditions, idx) status.addStatusMessage(_(u'Condition moved down.'), type='info') elif 'form.button.EditAction' in form: editview = self.actions()[idx]['editview'] self.request.response.redirect(editview) redirect = True elif 'form.button.DeleteAction' in form: self.authorize() del rule.actions[idx] status.addStatusMessage(_(u'Action deleted.'), type='info') elif 'form.button.MoveActionUp' in form: self._move_up(rule.actions, idx) status.addStatusMessage(_(u'Action moved up.'), type='info') elif 'form.button.MoveActionDown' in form: self._move_down(rule.actions, idx) status.addStatusMessage(_(u'Action moved down.'), type='info') elif 'form.button.ApplyOnWholeSite' in form: self.globally_assign() IStatusMessage(self.request).add( _(u'The rule has been enabled on site root ' u'and all its subfolders') ) self.view_url = self.base_url + '/@@manage-elements' self.rule_title = self.context.title self.rule_description = self.context.description self.rule_stop = self.context.stop self.rule_cascading = self.context.cascading self.rule_enabled = self.context.enabled if not redirect: return self.template()
def ruleTypesToShow(self): selector = [] for event in self._events(): eventname = translate(event.token, context=self.request, domain='plone') selector.append(dict(id = "trigger-" + event.value.__identifier__, title = _(u"Trigger: ${name}", mapping = {'name': eventname})), ) selector += ({'id': 'state-enabled', 'title': _(u"label_rule_enabled", default=u"Enabled")}, {'id': 'state-disabled', 'title': _(u"label_rule_disabled", default=u"Disabled"), }, # {'id': 'state-rule-assigned', 'title': _(u"Rule is in use")}, # {'id': 'state-rule-not-assigned', 'title': _(u"Rule is not assigned anywhere"), }, ) return selector
def __call__(self): portal_url = getToolByName(self.context, 'portal_url', None) if portal_url is None: return False obj = self.event.object parent = aq_parent(aq_inner(obj)) path = self.element.target_folder if len(path) > 1 and path[0] == '/': path = path[1:] target = portal_url.getPortalObject().unrestrictedTraverse(str(path), None) if target is None: self.error(obj, _(u"Target folder ${target} does not exist.", mapping={'target': path})) return False if target.absolute_url() == parent.absolute_url(): # We're already here! return True try: obj._notifyOfCopyTo(target, op=1) except ConflictError: raise except Exception, e: self.error(obj, str(e)) return False
def __call__(self): """ """ request = aq_inner(self.request) form = request.form if not 'form.button.Delete' in form: return super(PatchedManageAssignments, self).__call__() context = aq_inner(self.context) assignable = IRuleAssignmentManager(context) storage = getUtility(IRuleStorage) status = IStatusMessage(self.request) rule_ids = form.get('rule_ids', ()) path = '/'.join(context.getPhysicalPath()) for r in rule_ids: del assignable[r] assignments = get_assignments(storage[r]) if path in assignments: msg = 'Try to remove from %r' % ( assignments ) logger.info(msg) try: assignments.remove(path, None) except: assignments.remove(path) status.addStatusMessage(_(u"Assignments deleted."), type='info') return self.template()
def error(self, obj, error): request = getattr(self.context, 'REQUEST', None) if request is not None: title = utils.pretty_title_or_id(obj, obj) message = _(u"Unable to move ${name} as part of content rule 'move' action: ${error}", mapping={'name': title, 'error': error}) IStatusMessage(request).addStatusMessage(message, type="error")
def test_summary_with_vcge(self): from plone.app.contentrules import PloneMessageFactory as _ e = VCGEAction() e.skos = [self.term] msg = _(u'Aplica os termos ${skos}', mapping=dict(skos=' or '.join(e.skos))) self.assertEqual(e.summary, msg)
def error(self, obj, error): request = getattr(self.context, 'REQUEST', None) if request is not None: title = utils.safe_unicode(utils.pretty_title_or_id(obj, obj)) error = utils.safe_unicode(error) message = _( u"Unable to change state of ${name} as part of content rule 'workflow' action: ${error}", # noqa mapping={'name': title, 'error': error}) IStatusMessage(request).addStatusMessage(message, type='error')
def summary(self): portal = getSite() portal_types = getToolByName(portal, 'portal_types') titles = [] for name in self.check_types: fti = getattr(portal_types, name, None) if fti is not None: title = translate(fti.Title(), context=portal.REQUEST) titles.append(title) return _(u"Content types are: ${names}", mapping=dict(names=", ".join(titles)))
def test_summary_with_vcge(self): from plone.app.contentrules import PloneMessageFactory as _ e = VCGECondition() e.skos = [self.term, ] msg = _(u"VCGE contém ${skos}", mapping=dict(skos=" or ".join(e.skos))) self.assertEqual( e.summary, msg )
def add(self, content): """Add the rule to the context """ storage = getUtility(IRuleStorage) chooser = INameChooser(storage) name = chooser.chooseName(None, content) self._chosen_name = name storage[name] = content IStatusMessage(self.request).add(_(u"New content rule created. " u"Please add conditions and actions at the bottom of the page."), type=u'info')
def __call__(self): portal_url = getToolByName(self.context, 'portal_url', None) if portal_url is None: return False obj = self.event.object path = self.element.target_folder if len(path) > 1 and path[0] == '/': path = path[1:] target = portal_url.getPortalObject().unrestrictedTraverse( str(path), None, ) if target is None: self.error( obj, _( u'Target folder ${target} does not exist.', mapping={'target': path} ) ) return False try: obj._notifyOfCopyTo(target, op=0) except ConflictError: raise except Exception as e: self.error(obj, str(e)) return False old_id = obj.getId() new_id = self.generate_id(target, old_id) orig_obj = obj obj = obj._getCopy(target) obj._setId(new_id) notify(ObjectCopiedEvent(obj, orig_obj)) target._setObject(new_id, obj) obj = target._getOb(new_id) obj.wl_clearLocks() obj._postCopy(target, op=0) OFS.subscribers.compatibilityCall('manage_afterClone', obj, obj) notify(ObjectClonedEvent(obj)) return True
def breadcrumbs(self): portal_url = getToolByName(self.context, 'portal_url')() return ( { 'absolute_url': '{0}/@@rules-controlpanel'.format(portal_url), 'Title': _( 'title_manage_contentrules', default=u'Content Rules', ), }, { 'absolute_url': '{0}/@@manage-elements'.format( self.context.absolute_url(), ), 'Title': self.context.title or self.context.id, }, )
def __call__(self): redirect = False form = self.request.form idx = form.get('element_id', 0) rule = aq_inner(self.context) status = IStatusMessage(self.request) if 'form.button.Save' in form: rule.title = form.get('title', rule.title) rule.description = form.get('description', rule.description) rule.stop = bool(form.get('stopExecuting', False)) status.addStatusMessage(_(u"Changes saved."), type='info') elif 'form.button.EditCondition' in form: editview = self.conditions()[idx]['editview'] self.request.response.redirect(editview) redirect = True elif 'form.button.DeleteCondition' in form: del rule.conditions[idx] status.addStatusMessage(_(u"Condition deleted."), type='info') elif 'form.button.MoveConditionUp' in form: self._move_up(rule.conditions, idx) status.addStatusMessage(_(u"Condition moved up."), type='info') elif 'form.button.MoveConditionDown' in form: self._move_down(rule.conditions, idx) status.addStatusMessage(_(u"Condition moved down."), type='info') elif 'form.button.EditAction' in form: editview = self.actions()[idx]['editview'] self.request.response.redirect(editview) redirect = True elif 'form.button.DeleteAction' in form: del rule.actions[idx] status.addStatusMessage(_(u"Action deleted."), type='info') elif 'form.button.MoveActionUp' in form: self._move_up(rule.actions, idx) status.addStatusMessage(_(u"Action moved up."), type='info') elif 'form.button.MoveActionDown' in form: self._move_down(rule.actions, idx) status.addStatusMessage(_(u"Action moved down."), type='info') if not redirect: return self.template()
from plone.app.contentrules.browser.formhelper import AddForm from plone.app.contentrules.browser.formhelper import EditForm from plone.contentrules.rule.interfaces import IExecutable from plone.contentrules.rule.interfaces import IRuleElementData from zope.component import adapts from zope.formlib import form from zope.interface import implements from zope.interface import Interface from zope.schema import Bool from zope.schema import Choice from zope.schema import Set VOCAB = 'brasil.gov.vcge' FORM_NAME = _(u"Configurar a ação") FORM_DESC = _(u'Uma ação que aplica termos do VGCE a um conteúdo') class IVCGEAction(Interface): """ Interface utilizada para descrever os elementos configuraveis desta ação. """ same_as_parent = Bool(title=_(u"Utilizar os termos da pasta"), description=_(u"Selecione esta opção para que os " u"termos VCGE sejam herdados da " u"pasta que abriga o conteúdo. " u"Selecionar esta opção ignora " u"os termos do campo a seguir."))
def summary(self): return _(u"File extension is ${ext}", mapping=dict(ext=self.file_extension))
def summary(self): return _(u"The next label will be assigned ${message}", mapping=dict(message=self.message))
def __call__(self): mailhost = getToolByName(aq_inner(self.context), "MailHost") if not mailhost: raise ComponentLookupError, "You must have a Mailhost utility to \ execute this action" urltool = getToolByName(aq_inner(self.context), "portal_url") portal = urltool.getPortalObject() email_charset = portal.getProperty('email_charset') obj = self.event.object interpolator = IStringInterpolator(obj) source = self.element.source if source: source = interpolator(source).strip() if not source: # no source provided, looking for the site wide from email # address from_address = portal.getProperty('email_from_address') if not from_address: # the mail can't be sent. Try to inform the user request = getRequest() if request: messages = IStatusMessage(request) msg = _(u"Error sending email from content rule. You must " "provide a source address for mail " "actions or enter an email in the portal properties") messages.add(msg, type=u"error") return False from_name = portal.getProperty('email_from_name').strip('"') source = '"%s" <%s>' % (from_name, from_address) recip_string = interpolator(self.element.recipients) if recip_string: # check recipient is not None or empty string recipients = [str(mail.strip()) for mail in recip_string.split(',') \ if mail.strip()] else: recipients = [] if self.element.exclude_actor: mtool = getToolByName(aq_inner(self.context), "portal_membership") actor_email = mtool.getAuthenticatedMember().getProperty('email', '') if actor_email in recipients: recipients.remove(actor_email) # prepend interpolated message with \n to avoid interpretation # of first line as header message = "\n%s" % interpolator(self.element.message) subject = interpolator(self.element.subject) for email_recipient in recipients: try: # XXX: We're using "immediate=True" because otherwise we won't # be able to catch SMTPException as the smtp connection is made # as part of the transaction apparatus. # AlecM thinks this wouldn't be a problem if mail queuing was # always on -- but it isn't. (stevem) # so we test if queue is not on to set immediate mailhost.send(message, email_recipient, source, subject=subject, charset=email_charset, immediate=not mailhost.smtp_queue) except (MailHostError, SMTPException): logger.error( """mailing error: Attempt to send mail in content rule failed.\n%s""" % traceback.format_exc()) return True
def summary(self): return _(u"Execute transition ${transition}", mapping=dict(transition=self.transition))
def summary(self): """ Action summary """ return _(u"Send the '${body}' message to RabbitMQ service using the " "'${queue_name}' queue.", mapping=dict(queue_name=self.queue_name, body=self.body))
def summary(self): return _(u"Move to folder ${folder}", mapping=dict(folder=self.target_folder))
def summary(self): return _(u"Email report to ${recipients}", mapping=dict(recipients=self.recipients))
def summary(self): return _(u"TALES expression is: ${tales_expression}", mapping={'tales_expression': self.tales_expression})
def __call__(self): mailhost = getToolByName(aq_inner(self.context), 'MailHost') if not mailhost: raise ComponentLookupError( 'You must have a Mailhost utility to execute this action' ) email_charset = self.mail_settings.email_charset obj = self.event.object interpolator = IStringInterpolator(obj) source = self.element.source if source: source = interpolator(source).strip() if not source: # no source provided, looking for the site wide from email # address from_address = self.mail_settings.email_from_address if not from_address: # the mail can't be sent. Try to inform the user request = getRequest() if request: messages = IStatusMessage(request) msg = _( u'Error sending email from content rule. You must ' u'provide a source address for mail ' u'actions or enter an email in the portal properties' ) messages.add(msg, type=u'error') return False from_name = self.mail_settings.email_from_name.strip('"') if six.PY2 and isinstance(from_name, six.text_type): from_name = from_name.encode('utf8') source = '"{0}" <{1}>'.format(from_name, from_address) recip_string = interpolator(self.element.recipients) if recip_string: # check recipient is not None or empty string recipients = set([ str(mail.strip()) for mail in recip_string.split(',') if mail.strip() ]) else: recipients = set() if self.element.exclude_actor: mtool = getToolByName(aq_inner(self.context), 'portal_membership') actor_email = mtool.getAuthenticatedMember().getProperty( 'email', '' ) if actor_email in recipients: recipients.remove(actor_email) # prepend interpolated message with \n to avoid interpretation # of first line as header message = u'\n{0}'.format(interpolator(self.element.message)) subject = interpolator(self.element.subject) for email_recipient in recipients: try: # XXX: We're using "immediate=True" because otherwise we won't # be able to catch SMTPException as the smtp connection is made # as part of the transaction apparatus. # AlecM thinks this wouldn't be a problem if mail queuing was # always on -- but it isn't. (stevem) # so we test if queue is not on to set immediate mailhost.send(message, email_recipient, source, subject=subject, charset=email_charset, immediate=not mailhost.smtp_queue) except (MailHostError, SMTPException): logger.exception( 'mail error: Attempt to send mail in content rule failed' ) return True
def summary(self): return _( u'Groups are: ${names}', mapping=dict(names=', '.join(self.group_names)) )