def notify_followers(obj, event): """Tell our followers when a comment has been added. This method composes and sends emails to all users that have added a comment to this conversation and requested to be notified of follow-ups. """ request = getattr(obj, 'REQUEST', None) if not request: return if not ISlcUnderflow.providedBy(request): return # Get info necessary to send email mail_host = getToolByName(obj, 'MailHost') portal_url = getToolByName(obj, 'portal_url') portal = portal_url.getPortalObject() settings = getSettings() if settings is None or settings.sender is None: sender = portal.getProperty('email_from_address') else: sender = settings.sender # Check if a sender address is available if not sender: return # Compose and send emails to all users that have add a comment to this # conversation and enabled user_notification. conversation = aq_parent(obj) content_object = aq_parent(conversation) # Avoid sending multiple notification emails to the same person # when he has commented multiple times. emails = set() for comment in conversation.getComments(): if (obj != comment and comment.user_notification and comment.author_email): emails.add(comment.author_email) if not emails: return subject = translate(u"A comment has been posted [${uid}#${id}]", mapping={'uid': IUUID(content_object), 'id': obj.id}, context=obj.REQUEST) template = component.getMultiAdapter((obj, obj.REQUEST), name="mail_notification") message = template.render({ 'title': safe_unicode(content_object.title), 'link': content_object.absolute_url() + '/view#' + obj.id, 'text': obj.text }) for email in emails: # Send email try: mail_host.send(message, email, sender, subject, charset='utf-8') except SMTPException: logger.error('SMTP exception while trying to send an ' + 'email from %s to %s', sender, email)
def __call__(self, site, msg): recipient = email.Utils.parseaddr(msg.get('To'))[1] settings = getSettings() if settings is None or settings.sender is None: # Cannot handle email unless we have a dedicated address for it return False if recipient.lower() != settings.sender.strip().lower(): # It is not addressed to us return False sender = msg.get('From') sender = email.Utils.parseaddr(sender)[1].lower() # Drop privileges to the right user acl_users = getToolByName(site, 'acl_users') pm = getToolByName(site, 'portal_membership') props = getToolByName(site, 'portal_properties').site_properties user = None if props.getProperty('use_email_as_login'): # If email logins are used, the user's email might be his id user = pm.getMemberById(sender) if user is not None: if user.getProperty('email') == sender: user = user.getUser() else: user = None if user is None: potential = pm.searchMembers('email', sender) # Email might match more than one user, check for exact match for u in potential: if sender == u['email']: user = pm.getMemberById(u['username']).getUser() break if user is None: raise NotFoundError(_("Sender is not a valid user")) newSecurityManager(None, user.__of__(acl_users)) # Find relevant comment subject = msg.get('subject', '').strip() if not subject: raise NotFoundError(_("Subject is blank")) subject = decodeheader(subject) pat = re.compile('[^[]*\[([^#]+)(#([^\]]+))?\]') m = pat.match(subject) if m is None: raise NotFoundError(_("Unable to match a question")) questionid = m.groups()[0] commentid = m.groups()[2] # Might be None question = uuidToObject(questionid) if question is None: raise NotFoundError(_("Unable to match a question")) can_reply = getSecurityManager().checkPermission( 'Reply to item', question) if not can_reply: raise PermissionError(_("Insufficient privileges")) comment = createObject('plone.Comment') member = pm.getAuthenticatedMember() address = member.getProperty('email') fullname = member.getProperty('fullname') if not fullname or fullname == '': fullname = member.getUserName() elif isinstance(fullname, str): fullname = unicode(fullname, 'utf-8') if address and isinstance(address, str): address = unicode(address, 'utf-8') comment.creator = member.getUserName() comment.author_username = comment.creator comment.author_name = fullname comment.author_email = address comment.creation_date = datetime.utcnow() comment.modification_date = comment.creation_date # Walk the message and get the inline component for part in msg.walk(): if part.is_multipart(): # Ignore multipart envelope if it exists continue if part.get_filename() is not None: # Ignore attachments continue content_type = part.get_content_type() if content_type not in ('text/plain', 'text/html'): # Skip non text/html parts continue payload = part.get_payload(decode=1) if content_type == 'text/html': transforms = getToolByName(site, 'portal_transforms') transform = transforms.convertTo('text/plain', payload, context=site, mimetype='text/html') if transform: payload = transform.getData().strip() else: raise PermanentError(_(u"Could not convert html email")) comment.text = payload.strip() break # Get out of the for loop # Add comment to conversation conversation = IConversation(question) if commentid is not None: # Add a reply to an existing comment conversation_to_reply_to = conversation.get(commentid) replies = IReplies(conversation_to_reply_to) comment_id = replies.addComment(comment) else: # Add a comment to the conversation comment_id = conversation.addComment(comment) return True
def notify_nosy(obj, event): """ Give the nosy list access to the question. Then tell them about the new question. """ request = getattr(obj, 'REQUEST', None) if not request: return if not ISlcUnderflow.providedBy(request): return # Get info necessary to send email mail_host = getToolByName(obj, 'MailHost') portal_url = getToolByName(obj, 'portal_url') membership = getToolByName(obj, 'portal_membership') portal = portal_url.getPortalObject() member = api.user.get_current() user_id = member.getId() username = member.getProperty('fullname') settings = getSettings() if settings is None or settings.sender is None: sender = portal.getProperty('email_from_address') else: sender = settings.sender # Check if a sender address is available if not sender: return # Add Reader role on any nosy principals, remove from non-selected ones. disown = [] for principal, roles in obj.get_local_roles(): if principal not in obj.nosy: disown.append(principal) for principal in obj.nosy: obj.manage_addLocalRoles(principal, ['Reader']) if disown: obj.manage_delLocalRoles(disown) emails = set() groups_tool = getToolByName(obj, 'portal_groups') members = get_nosy_members(obj, obj.nosy) for member in members: if member is not None: email = member.getProperty('email') if email != '' and email != user_id: emails.add(email) if not emails: return # Transform the text of the question transforms = getToolByName(obj, 'portal_transforms') text = obj.question.output if isinstance(text, unicode): text = text.encode('utf8') transform = transforms.convertTo('text/plain', text, context=obj, mimetype='text/html') if transform: text = transform.getData().strip() else: text = '' if isinstance(event, ObjectModifiedEvent): subject = translate(u"A question has been modified in ${container} [${uid}]", mapping={'uid': IUUID(obj), 'container': obj.aq_parent.Title()}, context=obj.REQUEST) else: if obj.inforequest: subject = translate(u"Response required: StarDesk Message from ${username}", mapping={'username': username or user_id}, context=obj.REQUEST) else: subject = translate(u"StarDesk Message from ${username} to ${container} members", mapping={'username': username or user_id, 'container': obj.aq_parent.Title()}, context=obj.REQUEST) if obj.inforequest: template = component.getMultiAdapter((obj, obj.REQUEST), name="mail_notification_nosy_inforequest") else: template = component.getMultiAdapter((obj, obj.REQUEST), name="mail_notification_nosy") message = template.render({ 'username': username or user_id, 'title': safe_unicode(obj.title), 'link': obj.absolute_url(), 'text': safe_unicode(text), 'container': obj.aq_parent.Title() }) # remove the current user from the notification, he doesn't need to receive it, he asked in the first place for email in emails: # Send email try: mail_host.send(message, email, sender, subject, charset='utf-8') except SMTPException: logger.error('SMTP exception while trying to send an ' + 'email from %s to %s', sender, email)