From 5f738a32143f98a99ec1b5b017d7bac5f489f91b Mon Sep 17 00:00:00 2001 From: Bruno Tikami <bruno@tikami.com.br> Date: Tue, 16 Feb 2016 15:49:40 -0200 Subject: [PATCH] Too much in one commit ! Splitting responsibilities when parsing email messages so we can decide when to create a Ticket and when to create a FollowUp. --- helpdesk/management/commands/get_email.py | 272 ++++++++++++---------- 1 file changed, 151 insertions(+), 121 deletions(-) diff --git a/helpdesk/management/commands/get_email.py b/helpdesk/management/commands/get_email.py index 7233a3f8..d442b17b 100644 --- a/helpdesk/management/commands/get_email.py +++ b/helpdesk/management/commands/get_email.py @@ -124,7 +124,7 @@ def process_queue(q, quiet=False): msgSize = msg.split(" ")[1] full_message = "\n".join(server.retr(msgNum)[1]) - ticket = ticket_from_message(message=full_message, queue=q, quiet=quiet) + ticket = object_from_message(message=full_message, queue=q, quiet=quiet) if ticket: server.dele(msgNum) @@ -147,7 +147,7 @@ def process_queue(q, quiet=False): msgnums = data[0].split() for num in msgnums: status, data = server.fetch(num, '(RFC822)') - ticket = ticket_from_message(message=data[0][1], queue=q, quiet=quiet) + ticket = object_from_message(message=data[0][1], queue=q, quiet=quiet) if ticket: server.store(num, '+FLAGS', '\\Deleted') @@ -168,10 +168,146 @@ def decode_mail_headers(string): decoded = decode_header(string) return u' '.join([unicode(msg, charset or 'utf-8') for msg, charset in decoded]) -def ticket_from_message(message, queue, quiet): +def create_object_from_email_message(message, ticket_id, payload, files, quiet): + + ticket, new = None, False + now = timezone.now() + + queue = payload['queue'] + sender_email = payload['sender_email'] + + message_id = message.get('Message-Id') + in_reply_to = message.get('In-Reply-To') + + query_set = Ticket.objects.filter(Q(id=ticket_id)|Q(submitter_email_id=message_id)) + if query_set.count() == 0: + ticket = None + new = True + else: + t = query_set.first() + + # New issue, create a new <Ticket> instance + if ticket is None: + t = Ticket.objects.create( + title=payload['subject'], + queue=queue, + submitter_email=sender_email, + submitter_email_id=message_id, + created=now, + description=payload['body'], + priority=payload['priority'], + ) + t.save() + + new = True + update = '' + + # Old issue being re-openned + elif t.status == Ticket.CLOSED_STATUS: + t.status = Ticket.REOPENED_STATUS + t.save() + + f = FollowUp( + ticket = t, + title = _('E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}), + date = now, + public = True, + comment = payload['body'], + ) + + if t.status == Ticket.REOPENED_STATUS: + f.new_status = Ticket.REOPENED_STATUS + f.title = _('Ticket Re-Opened by E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}) + + f.save() + + if not quiet: + print (" [%s-%s] %s" % (t.queue.slug, t.id, t.title,)).encode('ascii', 'replace') + + for file in files: + if file['content']: + filename = file['filename'].encode('ascii', 'replace').replace(' ', '_') + filename = re.sub('[^a-zA-Z0-9._-]+', '', filename) + a = Attachment( + followup=f, + filename=filename, + mime_type=file['type'], + size=len(file['content']), + ) + a.file.save(filename, ContentFile(file['content']), save=False) + a.save() + if not quiet: + print " - %s" % filename + + + context = safe_template_context(t) + + if new: + + if sender_email: + send_templated_mail( + 'newticket_submitter', + context, + recipients=sender_email, + sender=queue.from_address, + fail_silently=True, + extra_headers={'In-Reply-To': message_id}, + ) + + if queue.new_ticket_cc: + send_templated_mail( + 'newticket_cc', + context, + recipients=queue.new_ticket_cc, + sender=queue.from_address, + fail_silently=True, + extra_headers={'In-Reply-To': message_id}, + ) + + if queue.updated_ticket_cc and queue.updated_ticket_cc != queue.new_ticket_cc: + send_templated_mail( + 'newticket_cc', + context, + recipients=queue.updated_ticket_cc, + sender=queue.from_address, + fail_silently=True, + extra_headers={'In-Reply-To': message_id}, + ) + + else: + context.update(comment=f.comment) + + if t.status == Ticket.REOPENED_STATUS: + update = _(' (Reopened)') + else: + update = _(' (Updated)') + + if t.assigned_to: + send_templated_mail( + 'updated_owner', + context, + recipients=t.assigned_to.email, + sender=queue.from_address, + fail_silently=True, + ) + + if queue.updated_ticket_cc: + send_templated_mail( + 'updated_cc', + context, + recipients=queue.updated_ticket_cc, + sender=queue.from_address, + fail_silently=True, + ) + + return t + +def object_from_message(message, queue, quiet): # 'message' must be an RFC822 formatted message. msg = message + + #import ipdb;ipdb.set_trace() message = email.message_from_string(msg) subject = message.get('subject', _('Created from e-mail')) @@ -196,9 +332,9 @@ def ticket_from_message(message, queue, quiet): matchobj = re.match(r".*\["+queue.slug+"-(?P<id>\d+)\]", subject) if matchobj: # This is a reply or forward. - ticket = matchobj.group('id') + ticket_id = matchobj.group('id') else: - ticket = None + ticket_id = None counter = 0 files = [] @@ -241,14 +377,7 @@ def ticket_from_message(message, queue, quiet): 'type': 'text/html', }) - now = timezone.now() - - if ticket: - try: - t = Ticket.objects.get(id=ticket) - new = False - except Ticket.DoesNotExist: - ticket = None + priority = 3 @@ -260,116 +389,17 @@ def ticket_from_message(message, queue, quiet): if smtp_priority in high_priority_types or smtp_importance in high_priority_types: priority = 2 - if ticket is None: - t = Ticket( - title=subject, - queue=queue, - submitter_email=sender_email, - submitter_email_id=message.get('message-id'), - created=now, - description=body, - priority=priority, - ) - t.save() - new = True - update = '' - - elif t.status == Ticket.CLOSED_STATUS: - t.status = Ticket.REOPENED_STATUS - t.save() - - f = FollowUp( - ticket = t, - title = _('E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}), - date = timezone.now(), - public = True, - comment = body, - ) - - if t.status == Ticket.REOPENED_STATUS: - f.new_status = Ticket.REOPENED_STATUS - f.title = _('Ticket Re-Opened by E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}) - - f.save() - - if not quiet: - print (" [%s-%s] %s" % (t.queue.slug, t.id, t.title,)).encode('ascii', 'replace') - - for file in files: - if file['content']: - filename = file['filename'].encode('ascii', 'replace').replace(' ', '_') - filename = re.sub('[^a-zA-Z0-9._-]+', '', filename) - a = Attachment( - followup=f, - filename=filename, - mime_type=file['type'], - size=len(file['content']), - ) - a.file.save(filename, ContentFile(file['content']), save=False) - a.save() - if not quiet: - print " - %s" % filename + payload = { + 'body': body, + 'subject': subject, + 'queue': queue, + 'sender_email': sender_email, + 'priority': priority, + 'files': files, + } - context = safe_template_context(t) - - if new: - - if sender_email: - send_templated_mail( - 'newticket_submitter', - context, - recipients=sender_email, - sender=queue.from_address, - fail_silently=True, - ) - - if queue.new_ticket_cc: - send_templated_mail( - 'newticket_cc', - context, - recipients=queue.new_ticket_cc, - sender=queue.from_address, - fail_silently=True, - ) - - if queue.updated_ticket_cc and queue.updated_ticket_cc != queue.new_ticket_cc: - send_templated_mail( - 'newticket_cc', - context, - recipients=queue.updated_ticket_cc, - sender=queue.from_address, - fail_silently=True, - ) - - else: - context.update(comment=f.comment) - - if t.status == Ticket.REOPENED_STATUS: - update = _(' (Reopened)') - else: - update = _(' (Updated)') - - if t.assigned_to: - send_templated_mail( - 'updated_owner', - context, - recipients=t.assigned_to.email, - sender=queue.from_address, - fail_silently=True, - ) - - if queue.updated_ticket_cc: - send_templated_mail( - 'updated_cc', - context, - recipients=queue.updated_ticket_cc, - sender=queue.from_address, - fail_silently=True, - ) - - return t - + return create_object_from_email_message(message, ticket_id, payload, files, quiet=quiet) if __name__ == '__main__': process_email()