def process_attachments(followup, attached_files): max_email_attachment_size = getattr(settings, 'HELPDESK_MAX_EMAIL_ATTACHMENT_SIZE', 512000) attachments = [] for attached in attached_files: if attached.size: filename = smart_text(attached.name) att = Attachment( followup=followup, file=attached, filename=filename, mime_type=attached.content_type or mimetypes.guess_type(filename, strict=False)[0] or 'application/octet-stream', size=attached.size, ) att.save() if attached.size < max_email_attachment_size: # Only files smaller than 512kb (or as defined in # settings.HELPDESK_MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. attachments.append([filename, att.file]) return attachments
def _attach_files_to_follow_up(self, followup): attachments = [] if self.cleaned_data['attachment']: import mimetypes attachment = self.cleaned_data['attachment'] filename = attachment.name.replace(' ', '_') att = Attachment( followup=followup, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=attachment.size, ) att.file.save(attachment.name, attachment, save=False) att.save() if attachment.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. try: attachments.append([att.filename, att.file]) except NotImplementedError: pass return attachments
def reply_ticket(request, ticket_id): """reply ticket to the client""" if not (request.user.is_authenticated() and request.user.is_active and (request.user.is_staff)): return HttpResponseRedirect('%s?next=%s' % (reverse('staff/login'), request.path)) ticket = get_object_or_404(Ticket, id=ticket_id) if request.method == 'POST': title = request.POST.get('title', '') comment = request.POST.get('comment', '') new_status = int(request.POST.get('new_status', ticket.status)) if not all([title, comment]): return render(request, 'helpdesk/reply_ticket.html', { 'ticket': ticket, }) #save models f = FollowUp(public=True, ticket=ticket, date=timezone.now(), comment=comment, user=request.user) f.title = 'Email:{}'.format(title) if new_status != ticket.status: ticket.status = new_status ticket.save() f.new_status = new_status f.save() #save attachment files = [] if request.FILES: import mimetypes for file in request.FILES.getlist('attachment'): print(dir(file)) filename = file.name a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(filename, file, save=False) a.save() files.append([a.filename, a.file]) if new_status in [Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS]: if new_status == Ticket.RESOLVED_STATUS: ticket.resolution = comment ticket.save() #send email send_reply_email(files=files, subject=title, body=comment, recipients=[ticket.submitter_email], sender=ticket.queue.from_address, fail_silently=True) return HttpResponseRedirect(ticket.get_absolute_url()) return render(request, 'helpdesk/reply_ticket.html', { 'ticket': ticket, })
def save(self, user): task = Task.objects.get(id=int(self.cleaned_data['task'])) if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() task.attachments.add(a) task.save() return None
def _attach_files_to_follow_up(self, followup): attachments = [] if self.cleaned_data["attachment"]: import mimetypes attachment = self.cleaned_data["attachment"] filename = attachment.name.replace(" ", "_") att = Attachment( followup=followup, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or "application/octet-stream", size=attachment.size, ) att.file.save(attachment.name, attachment, save=False) att.save() if attachment.size < getattr(settings, "MAX_EMAIL_ATTACHMENT_SIZE", 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. try: attachments.append([att.filename, att.file]) except NotImplementedError: pass return attachments
def process_attachments(followup, attached_files): max_email_attachment_size = getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000) attachments = [] for attached in attached_files: if attached.size: filename = smart_text(attached.name) att = Attachment( followup=followup, file=attached, filename=filename, mime_type=attached.content_type or mimetypes.guess_type(filename, strict=False)[0] or 'application/octet-stream', size=attached.size, ) att.save() if attached.size < max_email_attachment_size: # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. attachments.append([filename, att.file]) return attachments
def update_ticket(request, ticket_id, public=False): if not (public or (request.user.is_authenticated() and request.user.is_active and request.user.is_staff)): return HttpResponseForbidden(_('Sorry, you need to login to do that.')) ticket = get_object_or_404(Ticket, id=ticket_id) comment = request.POST.get('comment', '') new_status = int(request.POST.get('new_status', ticket.status)) title = request.POST.get('title', ticket.title) public = request.POST.get('public', public) owner = int(request.POST.get('owner', 0)) priority = int(request.POST.get('priority', ticket.priority)) tags = request.POST.get('tags', '') if public: ticket.notify_owner = True else: ticket.notify_owner = False # We need to allow the 'ticket' and 'queue' contexts to be applied to the # comment. from django.template import loader, Context context = safe_template_context(ticket) comment = loader.get_template_from_string(comment).render(Context(context)) if owner is None and ticket.assigned_to: owner = ticket.assigned_to.id f = FollowUp(ticket=ticket, date=datetime.now(), comment=comment) if request.user.is_authenticated(): f.user = request.user f.public = public reassigned = False if owner is not None: if owner != 0 and ( (ticket.assigned_to and owner != ticket.assigned_to.id) or not ticket.assigned_to): new_user = User.objects.get(id=owner) f.title = _('Assigned to %(username)s') % { 'username': new_user.username, } ticket.assigned_to = new_user reassigned = True elif owner == 0 and ticket.assigned_to is not None: f.title = _('Unassigned') ticket.assigned_to = None if new_status != ticket.status: ticket.status = new_status ticket.save() f.new_status = new_status if f.title: f.title += ' and %s' % ticket.get_status_display() else: f.title = '%s' % ticket.get_status_display() if not f.title: if f.comment: f.title = _('Comment') else: f.title = _('Updated') f.save() files = [] if request.FILES: import mimetypes, os for file in request.FILES.getlist('attachment'): filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) if title != ticket.title: c = TicketChange( followup=f, field=_('Title'), old_value=ticket.title, new_value=title, ) c.save() ticket.title = title if priority != ticket.priority: c = TicketChange( followup=f, field=_('Priority'), old_value=ticket.priority, new_value=priority, ) c.save() ticket.priority = priority if HAS_TAG_SUPPORT: if tags != ticket.tags: c = TicketChange( followup=f, field=_('Tags'), old_value=ticket.tags, new_value=tags, ) c.save() ticket.tags = tags if f.new_status == Ticket.RESOLVED_STATUS: ticket.resolution = comment messages_sent_to = [] context.update( resolution=ticket.resolution, comment=f.comment, ) if ticket.submitter_email and public and ( f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))): if f.new_status == Ticket.RESOLVED_STATUS: template = 'resolved_owner' elif f.new_status == Ticket.CLOSED_STATUS: template = 'closed_owner' else: template = 'updated_owner' send_templated_mail( template, context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.submitter_email) for cc in ticket.ticketcc_set.all(): if cc.email_address not in messages_sent_to: send_templated_mail( template, context, recipients=cc.email_address, sender=ticket.queue.from_address, fail_silently=True, ) messages_sent_to.append(cc.email_address) if ticket.assigned_to and request.user.account != ticket.assigned_to and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to: # We only send e-mails to staff members if the ticket is updated by # another user. The actual template varies, depending on what has been # changed. if reassigned: template_staff = 'assigned_to' elif f.new_status == Ticket.RESOLVED_STATUS: template_staff = 'resolved_asigned_to' elif f.new_status == Ticket.CLOSED_STATUS: template_staff = 'closed_assigned_to' else: template_staff = 'updated_assigned_to' if (not reassigned or (reassigned and ticket.assigned_to.usersettings.settings.get( 'email_on_ticket_assign', False))) or ( not reassigned and ticket.assigned_to.usersettings.settings.get( 'email_on_ticket_change', False)): send_templated_mail( template_staff, context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.assigned_to.email) if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to: if reassigned: template_cc = 'assigned_cc' elif f.new_status == Ticket.RESOLVED_STATUS: template_cc = 'resolved_cc' elif f.new_status == Ticket.CLOSED_STATUS: template_cc = 'closed_cc' else: template_cc = 'updated_cc' send_templated_mail( template_cc, context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True, files=files, ) ticket.save() if request.user.is_staff: return HttpResponseRedirect(ticket.get_absolute_url()) else: return HttpResponseRedirect(ticket.ticket_url)
def form_valid(self, form): old_ticket = form.instance ticket = form.save(commit=False) no_changes = all([ not self.request.FILES, not self.request.POST['comment'], ticket.status == old_ticket.status, ticket.title == old_ticket.title, ticket.priority == int(old_ticket.priority), ticket.due_date == old_ticket.due_date, ticket.owner_id != old_ticket.owner_id ]) if no_changes: self.object = old_ticket return HttpResponseRedirect(self.get_success_url()) ticket.save() self.object = ticket followup = FollowUp( ticket_id=ticket.pk, date = timezone.now(), comment = self.request.POST['comment'], user_id = self.request.user.pk, public = self.request.POST['public'], title = '' ) reassigned = False if ticket.owner_id != old_ticket.owner_id: followup.title = _('Asigned to %s' % User.objects.get(id=ticket.owner_id)) reassigned = True if ticket.status != old_ticket.status: if followup.title != '': followup.title += ' and ' followup.title += ticket.get_status_display() followup.save() files = [] if self.request.FILES: import mimetypes, os for file in self.request.FILES.getlist('attachment'): filename = file.name.encode('ascii', 'ignore') a = Attachment( followup_id=followup.pk, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(filename, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append([a.filename, a.file]) if old_ticket.title != ticket.title: change = TicketChange( followup_id=followup.id, field=_('Title'), old_value = old_ticket.title, new_value = ticket.title ) if old_ticket.priority != ticket.priority: change = TicketChange( followup_id=followup.id, field=_('Priority'), old_value = old_ticket.priority, new_value = ticket.priority ) if old_ticket.due_date != ticket.due_date: change = TicketChange( followup_id=followup.id, field=_('Due on'), old_value = old_ticket.due_date, new_value = ticket.due_date ) # We need to allow the 'ticket' and 'queue' contexts to be applied to the # comment. from django.template import loader, Context context = safe_template_context(ticket) # this line sometimes creates problems if code is sent as a comment. # if comment contains some django code, like "why does {% if bla %} crash", # then the following line will give us a crash, since django expects {% if %} # to be closed with an {% endif %} tag. # get_template_from_string was removed in Django 1.8 http://django.readthedocs.org/en/1.8.x/ref/templates/upgrading.html try: from django.template import engines template_func = engines['django'].from_string except ImportError: # occurs in django < 1.8 template_func = loader.get_template_from_string # RemovedInDjango110Warning: render() must be called with a dict, not a Context. if VERSION < (1, 8): context = Context(context) comment = template_func(followup.comment).render(context) if ticket.status in [ Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS ]: if ticket.status == Ticket.RESOLVED_STATUS or ticket.resolution is None: ticket.resolution = comment messages_sent_to = [] if followup.public and (followup.comment or (followup.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))): if followup.new_status == Ticket.RESOLVED_STATUS: template = 'resolved_' elif followup.new_status == Ticket.CLOSED_STATUS: template = 'closed_' else: template = 'updated_' template_suffix = 'submitter' if ticket.submitter_email: send_templated_mail( template + template_suffix, context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.submitter_email) template_suffix = 'cc' for cc in ticket.ticketcc_set.all(): if cc.email_address not in messages_sent_to: send_templated_mail( template + template_suffix, context, recipients=cc.email_address, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(cc.email_address) if old_ticket.assigned_to_id and self.request.user.pk != ticket.assigned_to_id \ and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to: # We only send e-mails to staff members if the ticket is updated by # another user. The actual template varies, depending on what has been # changed. if reassigned: template_staff = 'assigned_owner' elif followup.new_status == Ticket.RESOLVED_STATUS: template_staff = 'resolved_owner' elif followup.new_status == Ticket.CLOSED_STATUS: template_staff = 'closed_owner' else: template_staff = 'updated_owner' if (not reassigned or \ ( reassigned and old_ticket.assigned_to.usersettings.settings.get('email_on_ticket_assign', False))) \ or (not reassigned and old_ticket.assigned_to.usersettings.settings.get('email_on_ticket_change', False)): send_templated_mail( template_staff, context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.assigned_to.email) if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to: if reassigned: template_cc = 'assigned_cc' elif followup.new_status == Ticket.RESOLVED_STATUS: template_cc = 'resolved_cc' elif followup.new_status == Ticket.CLOSED_STATUS: template_cc = 'closed_cc' else: template_cc = 'updated_cc' send_templated_mail( template_cc, context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True, files=files, ) ticket.save() # auto subscribe user if enabled if helpdesk_settings.HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE: ticketcc_string, SHOW_SUBSCRIBE = return_ticketccstring_and_show_subscribe(self.request.user, ticket) if SHOW_SUBSCRIBE: subscribe_staff_member_to_ticket(ticket, self.request.user) return HttpResponseRedirect(self.get_success_url())
def save(self): """ Writes and returns a Ticket() object """ q = Queue.objects.get(id=int(self.cleaned_data['queue'])) t = Ticket( title = self.cleaned_data['title'], submitter_email = self.cleaned_data['submitter_email'], created = datetime.now(), status = Ticket.OPEN_STATUS, queue = q, description = self.cleaned_data['body'], priority = self.cleaned_data['priority'], due_date = self.cleaned_data['due_date'], ) t.save() for field, value in self.cleaned_data.items(): if field.startswith('custom_'): field_name = field.replace('custom_', '') customfield = CustomField.objects.get(name=field_name) cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() f = FollowUp( ticket = t, title = _('Ticket Opened Via Web'), date = datetime.now(), public = True, comment = self.cleaned_data['body'], ) f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = safe_template_context(t) messages_sent_to = [] send_templated_mail( 'newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def save(self, owner=None): """ Writes and returns a Ticket() object """ q = Queue.objects.get(id=int(self.cleaned_data['queue'])) t = Ticket(title=self.cleaned_data['title'], owner=owner, submitter_email=self.cleaned_data['submitter_email'], created=datetime.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data['body'], priority=self.cleaned_data['priority'], account=owner.account) t.save() f = FollowUp(ticket=t, title=_('Ticket Opened Via Web'), date=datetime.now(), public=True, comment=self.cleaned_data['body'], account=owner.account) f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = { 'ticket': t, 'queue': q, } messages_sent_to = [] send_templated_mail( 'newticket_owner', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def save(self, user): """ Writes and returns a Ticket() object """ q = Queue.objects.get(id=int(self.cleaned_data["queue"])) t = Ticket( title=self.cleaned_data["title"], submitter_email=self.cleaned_data["submitter_email"], created=datetime.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data["body"], priority=self.cleaned_data["priority"], due_date=self.cleaned_data["due_date"], ) if HAS_TAG_SUPPORT: t.tags = self.cleaned_data["tags"] if self.cleaned_data["assigned_to"]: try: u = User.objects.get(id=self.cleaned_data["assigned_to"]) t.assigned_to = u except User.DoesNotExist: t.assigned_to = None t.save() for field, value in self.cleaned_data.items(): if field.startswith("custom_"): field_name = field.replace("custom_", "") customfield = CustomField.objects.get(name=field_name) cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() f = FollowUp( ticket=t, title=_("Ticket Opened"), date=datetime.now(), public=True, comment=self.cleaned_data["body"], user=user, ) if self.cleaned_data["assigned_to"]: f.title = _("Ticket Opened & Assigned to %(name)s") % {"name": t.get_assigned_to} f.save() files = [] if self.cleaned_data["attachment"]: import mimetypes file = self.cleaned_data["attachment"] filename = file.name.replace(" ", "_") a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or "application/octet-stream", size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, "MAX_EMAIL_ATTACHMENT_SIZE", 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = safe_template_context(t) context["comment"] = f.comment messages_sent_to = [] if t.submitter_email: send_templated_mail( "newticket_submitter", context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if ( t.assigned_to and t.assigned_to != user and getattr(t.assigned_to.usersettings.settings, "email_on_ticket_assign", False) and t.assigned_to.email and t.assigned_to.email not in messages_sent_to ): send_templated_mail( "assigned_owner", context, recipients=t.assigned_to.email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.assigned_to.email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( "newticket_cc", context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if ( q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to ): send_templated_mail( "newticket_cc", context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def ticket_from_message(message, queue, quiet): # 'message' must be an RFC822 formatted message. msg = message message = email.message_from_string(msg) subject = message.get('subject', _('Created from e-mail')) subject = decode_mail_headers(decodeUnknown(message.get_charset(), subject)) subject = subject.replace("Re: ", "").replace("Fw: ", "").replace("RE: ", "").replace("FW: ", "").strip() sender = message.get('from', _('Unknown Sender')) sender = decode_mail_headers(decodeUnknown(message.get_charset(), sender)) sender_name = parseaddr(sender)[0] sender_email = parseaddr(sender)[1] body_plain, body_html = '', '' for ignore in IgnoreEmail.objects.filter(Q(queues=queue) | Q(queues__isnull=True)): if ignore.test(sender_email): if ignore.keep_in_mailbox: # By returning 'False' the message will be kept in the mailbox, # and the 'True' will cause the message to be deleted. return False return True matchobj = re.match(r"^\[(?P<queue>[-A-Za-z0-9]+)-(?P<id>\d+)\]", subject) if matchobj: # This is a reply or forward. ticket = matchobj.group('id') else: ticket = None counter = 0 files = [] for part in message.walk(): if part.get_content_maintype() == 'multipart': continue name = part.get_param("name") if name: name = collapse_rfc2231_value(name) if part.get_content_maintype() == 'text' and name == None: if part.get_content_subtype() == 'plain': body_plain = decodeUnknown(part.get_content_charset(), part.get_payload(decode=True)) else: body_html = part.get_payload(decode=True) else: if not name: ext = mimetypes.guess_extension(part.get_content_type()) name = "part-%i%s" % (counter, ext) files.append({ 'filename': name, 'content': part.get_payload(decode=True), 'type': part.get_content_type()}, ) counter += 1 if body_plain: body = body_plain else: body = _('No plain-text email body available. Please see attachment email_html_body.html.') if body_html: files.append({ 'filename': _("email_html_body.html"), 'content': body_html, 'type': 'text/html', }) now = datetime.now() if ticket: try: t = Ticket.objects.get(id=ticket) new = False except Ticket.DoesNotExist: ticket = None priority = 3 smtp_priority = message.get('priority', '') smtp_importance = message.get('importance', '') high_priority_types = ('high', 'important', '1', 'urgent') if smtp_priority in high_priority_types or smtp_importance in high_priority_types: priority = 2 update = '' if ticket == None: t = Ticket( title=subject, queue=queue, submitter_name=sender_name, submitter_email=sender_email, created=now, description=body, priority=priority, ) t.save() new = True 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 = datetime.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%s" % (t.queue.slug, t.id, t.title, update)).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, ) """ 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
def update_ticket(request, ticket_id, public=False): ticket = get_object_or_404(Ticket, id=ticket_id,owner=request.user) comment = request.POST.get('comment', '') new_status = int(request.POST.get('new_status', ticket.status)) title = request.POST.get('title', ticket.title) #public = request.POST.get('public', public) public=True owner = ticket.owner #priority = int(request.POST.get('priority', ticket.priority)) tags = request.POST.get('tags', '') # We need to allow the 'ticket' and 'queue' contexts to be applied to the # comment. from django.template import loader, Context context = safe_template_context(ticket) comment = loader.get_template_from_string(comment).render(Context(context)) #if owner is None and ticket.assigned_to: # owner = ticket.assigned_to.id f = FollowUp(ticket=ticket, date=datetime.now(), comment=comment) #if request.user.is_authenticated(): f.account = request.user.account f.public = True reassigned = False if new_status != ticket.status: ticket.status = new_status ticket.save() f.new_status = new_status if f.title: f.title += _(u'%(STATUS)s %(USER)s ') % {'USER': request.user.account, 'STATUS': ticket.get_status_display()} else: f.title = _(u'%(STATUS)s %(USER)s ') % {'USER': request.user.account, 'STATUS': ticket.get_status_display()} if not f.title: if f.comment: f.title = _(u'Добавлен комментарий от %(USER)s ') % {'USER': request.user.account} else: f.title = _(u'Обновлено %(USER)s ') % {'USER': request.user.account} f.save() files = [] if request.FILES: import mimetypes, os for file in request.FILES.getlist('attachment'): filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) if title != ticket.title: c = TicketChange( followup=f, field=_('Title'), old_value=ticket.title, new_value=title, ) c.save() ticket.title = title if HAS_TAG_SUPPORT: if tags != ticket.tags: c = TicketChange( followup=f, field=_('Tags'), old_value=ticket.tags, new_value=tags, ) c.save() ticket.tags = tags if f.new_status == Ticket.RESOLVED_STATUS: ticket.resolution = comment messages_sent_to = [] context.update( resolution=ticket.resolution, comment=f.comment, ) if ticket.submitter_email and public and (f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))): if f.new_status == Ticket.RESOLVED_STATUS: template = 'resolved_owner' elif f.new_status == Ticket.CLOSED_STATUS: template = 'closed_owner' else: template = 'updated_owner' send_templated_mail( template, context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.submitter_email) for cc in ticket.ticketcc_set.all(): if cc.email_address not in messages_sent_to: send_templated_mail( template, context, recipients=cc.email_address, sender=ticket.queue.from_address, fail_silently=True, ) messages_sent_to.append(cc.email_address) if ticket.assigned_to and request.user != ticket.assigned_to and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to: # We only send e-mails to staff members if the ticket is updated by # another user. The actual template varies, depending on what has been # changed. if reassigned: template_staff = 'assigned_to' elif f.new_status == Ticket.RESOLVED_STATUS: template_staff = 'resolved_assigned_to' elif f.new_status == Ticket.CLOSED_STATUS: template_staff = 'closed_assigned_to' else: template_staff = 'updated_assigned_to' if (not reassigned or ( reassigned and ticket.assigned_to.usersettings.settings.get('email_on_ticket_assign', False))) or (not reassigned and ticket.assigned_to.usersettings.settings.get('email_on_ticket_change', False)): send_templated_mail( template_staff, context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.assigned_to.email) if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to: if reassigned: template_cc = 'assigned_cc' elif f.new_status == Ticket.RESOLVED_STATUS: template_cc = 'resolved_cc' elif f.new_status == Ticket.CLOSED_STATUS: template_cc = 'closed_cc' else: template_cc = 'updated_cc' send_templated_mail( template_cc, context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True, files=files, ) ticket.save() return HttpResponseRedirect(ticket.ticket_url)
def create_object_from_email_message(message, ticket_id, payload, files, quiet): ticket, previous_followup, new = None, None, False now = timezone.now() queue = payload['queue'] sender_email = payload['sender_email'] to_list = getaddresses(message.get_all('To', [])) cc_list = getaddresses(message.get_all('Cc', [])) message_id = message.get('Message-Id') in_reply_to = message.get('In-Reply-To') if in_reply_to is not None: try: queryset = FollowUp.objects.filter(message_id=in_reply_to).order_by('-date') if queryset.count() > 0: previous_followup = queryset.first() ticket = previous_followup.ticket except FollowUp.DoesNotExist: pass #play along. The header may be wrong if previous_followup is None and ticket_id is not None: try: ticket = Ticket.objects.get(id=ticket_id) new = False except Ticket.DoesNotExist: ticket = None # New issue, create a new <Ticket> instance if ticket is None: ticket = Ticket.objects.create( title = payload['subject'], queue = queue, submitter_email = sender_email, created = now, description = payload['body'], priority = payload['priority'], ) ticket.save() new = True update = '' # Old issue being re-openned elif ticket.status == Ticket.CLOSED_STATUS: ticket.status = Ticket.REOPENED_STATUS ticket.save() f = FollowUp( ticket = ticket, title = _('E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}), date = now, public = True, comment = payload['body'], message_id = message_id, ) if ticket.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" % (ticket.queue.slug, ticket.id, ticket.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(ticket) new_ticket_ccs = [] new_ticket_ccs.append(create_ticket_cc(ticket, to_list)) new_ticket_ccs.append(create_ticket_cc(ticket, cc_list)) notification_template = None notifications_to_be_sent = [sender_email,] if queue.enable_notifications_on_email_events and len(notifications_to_be_sent): ticket_cc_list = TicketCC.objects.filter(ticket=ticket).all().values_list('email', flat=True) for email in ticket_cc_list : notifications_to_be_sent.append(email) if new: notification_template = 'newticket_cc' if sender_email: send_templated_mail( 'newticket_submitter', context, recipients=notifications_to_be_sent, 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: notification_template = 'updated_cc' context.update(comment=f.comment) if ticket.status == Ticket.REOPENED_STATUS: update = _(' (Reopened)') else: update = _(' (Updated)') if ticket.assigned_to: send_templated_mail( 'updated_owner', context, recipients=ticket.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, ) if queue.enable_notifications_on_email_events: if queue.updated_ticket_cc: send_templated_mail( 'updated_cc', context, recipients=notifications_to_be_sent, sender=queue.from_address, fail_silently=True, ) return ticket
def form_valid(self, form): self.object = form.save(True) t = self.object q = t.queue for field, value in form.cleaned_data.items(): if field.startswith('custom_'): field_name = field.replace('custom_', '', 1) customfields = CustomField.objects.filter(customfieldset__queue_id=form.cleaned_data['queue']) for customfield in customfields: if customfield.name == field_name: cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() cfs = CustomFieldSet(queue_id=q.pk, field=customfield) cfs.save() f = FollowUp( ticket_id = t.pk, title = _('Ticket Opened'), date = timezone.now(), public = True, comment = form.cleaned_data['body'], user_id = t.assigned_to_id ) if form.cleaned_data['assigned_to']: f.title = _('Ticket Opened & Assigned to %(name)s') % { 'name': t.get_assigned_to } f.save() files = [] if form.cleaned_data['attachment']: import mimetypes file = form.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup_id=f.pk, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. try: files.append([a.filename, a.file]) except NotImplementedError: pass context = safe_template_context(t) context['comment'] = f.comment messages_sent_to = [] if t.submitter_email: send_templated_mail( 'newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if t.assigned_to and t.assigned_to != self.request.user and t.assigned_to.usersettings.settings.get('email_on_ticket_assign', False) and t.assigned_to.email and t.assigned_to.email not in messages_sent_to: send_templated_mail( 'assigned_owner', context, recipients=t.assigned_to.email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.assigned_to.email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return HttpResponseRedirect(self.get_success_url())
def ticket_from_message(message, queue, quiet): is_cc = False update = None # 'message' must be an RFC822 formatted message. msg = message message = email.message_from_string(msg) subject = message.get('subject', _('Created from e-mail')) subject = decode_mail_headers(decodeUnknown(message.get_charset(), subject)) subject = subject.replace("Re: ", "").replace("Fw: ", "").replace("RE: ", "").replace("FW: ", "").strip() sender = message.get('from', _('Unknown Sender')) sender = decode_mail_headers(decodeUnknown(message.get_charset(), sender)) sender_email = parseaddr(sender)[1] body_plain, body_html = '', '' for ignore in IgnoreEmail.objects.filter(Q(queues=queue) | Q(queues__isnull=True)): if ignore.test(sender_email): if ignore.keep_in_mailbox: # By returning 'False' the message will be kept in the mailbox, # and the 'True' will cause the message to be deleted. return False return True # Check if we're being CC'ed, in which case we might not want to send emails or filter dest = decode_mail_headers(decodeUnknown(message.get_charset(), message.get('to', _('Unknown Sender')))) dest_email = parseaddr(dest) if (not helpdesk_settings.HELPDESK_EMAIL_CONFIRM_CC or helpdesk_settings.HELPDESK_FILTER_CC_ALTERNATE) \ and dest_email[1] != queue.email_address: is_cc = True # If we want to filter CC'd messages to a seperate queue, do so # Try to filter to a queue based on gmail labels reset_queue = False if helpdesk_settings.HELPDESK_FILTER_LABEL_TO_QUEUE: match_info = re.match(r"^(.*?)\++(?P<label>.*?)@.*", dest_email[1]) if match_info: try: new_queue = Queue.objects.get(slug=match_info.group('label').lower()) if new_queue: logger.info(" ++ Matched label '%s' to queue '%s'" % (match_info.group('label').lower(), new_queue)) queue = new_queue reset_queue = True except: logger.error(" !! Failed to match label '%s' to a queue, not moving message" % match_info.group('label').lower()) # Check we want to filter CCs, but only if we have a queue and # a queue was not already modified because we matched a label if helpdesk_settings.HELPDESK_FILTER_CC_ALTERNATE and is_cc and queue.alternate_queue is not None \ and not reset_queue: logger.info(" ++ We think this is CC'd") queue = queue.alternate_queue matchobj = re.match(r"^\[(?P<queue>[-A-Za-z0-9]+)-(?P<id>\d+)\]", subject) if matchobj: # This is a reply or forward. ticket = matchobj.group('id') else: ticket = None counter = 0 files = [] for part in message.walk(): if part.get_content_maintype() == 'multipart': continue name = part.get_param("name") if name: name = collapse_rfc2231_value(name) if part.get_content_maintype() == 'text' and name == None: if part.get_content_subtype() == 'plain': try: body_plain = decodeUnknown(part.get_content_charset(), part.get_payload(decode=True)) except: # We could get a unicode exception here, in which case, we really don't know anymore body_plain = None else: body_html = part.get_payload(decode=True) else: if not name: ext = mimetypes.guess_extension(part.get_content_type()) name = "part-%i%s" % (counter, ext) files.append({ 'filename': name, 'content': part.get_payload(decode=True), 'type': part.get_content_type()}, ) counter += 1 plain = html = False if body_plain: body = body_plain plain = True else: body = _('No plain-text email body available. Please see attachment email_html_body.html.') if body_html: html = True files.append({ 'filename': _("email_html_body.html"), 'content': body_html, 'type': 'text/html', }) now = datetime.now() if ticket: try: t = Ticket.objects.get(id=ticket) new = False except Ticket.DoesNotExist: logger.debug("Didn't find a ticket with ID %s" % ticket) ticket = None priority = 3 smtp_priority = message.get('priority', '') smtp_importance = message.get('importance', '') high_priority_types = ('high', 'important', '1', 'urgent') if smtp_priority in high_priority_types or smtp_importance in high_priority_types: priority = 2 if ticket == None: logger.debug("Creating new ticket for email") t = Ticket( title=subject, queue=queue, submitter_email=sender_email, created=now, description=body, priority=priority, ) t.save() new = True update = '' elif t.status == Ticket.CLOSED_STATUS: logger.debug("Reopening ticket") t.status = Ticket.REOPENED_STATUS t.save() f = FollowUp( ticket = t, title = _('E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}), date = datetime.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: logger.info(" [%s-%s] %s%s" % (t.queue.slug, t.id, t.title, update)).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: logger.info(" - %s" % filename) context = safe_template_context(t) if new: if helpdesk_settings.HELPDESK_SEND_SUBMITTER_EMAIL and sender_email and not is_cc: send_templated_mail( 'newticket_submitter', context, recipients=sender_email, sender=queue.from_address, fail_silently=True, ) if queue.new_ticket_cc and not is_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 and not is_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 and not is_cc: send_templated_mail( 'updated_owner', context, recipients=t.assigned_to.email, sender=queue.from_address, fail_silently=True, ) if queue.updated_ticket_cc and not is_cc: send_templated_mail( 'updated_cc', context, recipients=queue.updated_ticket_cc, sender=queue.from_address, fail_silently=True, ) return t
def save(self, owner=None): """ Writes and returns a Ticket() object """ q = Queue.objects.get(id=int(self.cleaned_data["queue"])) t = Ticket( title=self.cleaned_data["title"], owner=owner, submitter_email=self.cleaned_data["submitter_email"], created=datetime.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data["body"], priority=self.cleaned_data["priority"], account=owner.account, ) t.save() f = FollowUp( ticket=t, title=_("Ticket Opened Via Web"), date=datetime.now(), public=True, comment=self.cleaned_data["body"], account=owner.account, ) f.save() files = [] if self.cleaned_data["attachment"]: import mimetypes file = self.cleaned_data["attachment"] filename = file.name.replace(" ", "_") a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or "application/octet-stream", size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, "MAX_EMAIL_ATTACHMENT_SIZE", 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = {"ticket": t, "queue": q} messages_sent_to = [] send_templated_mail( "newticket_owner", context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( "newticket_cc", context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if ( q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to ): send_templated_mail( "newticket_cc", context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def form_valid(self, form): form.instance.created = timezone.now() form.instance.status = Ticket.OPEN_STATUS self.object = form.save() t = self.object f = FollowUp( ticket_id = t.id, title = _('Ticket Opened'), date = timezone.now(), public = True, comment = '', user_id = t.assigned_to_id ) if t.assigned_to_id: f.title = _('Ticket Opened & Assigned to %(name)s') % { 'name': t.get_assigned_to.get_full_name() } f.save() files = [] if form.cleaned_data.get('attachment'): import mimetypes file = form.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. try: files.append([a.filename, a.file]) except NotImplementedError: pass context = safe_template_context(t) context['comment'] = f.comment messages_sent_to = [] if t.submitter_email: send_templated_mail( 'newticket_submitter', context, recipients=t.submitter_email, sender=t.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) #if t.assigned_to and t.assigned_to != user and t.assigned_to.usersettings.settings.get('email_on_ticket_assign', False) and t.assigned_to.email and t.assigned_to.email not in messages_sent_to: if t.assigned_to and t.assigned_to.usersettings.settings.get('email_on_ticket_assign', False) \ and t.assigned_to.email and t.assigned_to.email not in messages_sent_to: send_templated_mail( 'assigned_owner', context, recipients=t.assigned_to.email, sender=t.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.assigned_to.email) if t.queue.new_ticket_cc and t.queue.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=t.queue.new_ticket_cc, sender=t.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.queue.new_ticket_cc) if t.queue.updated_ticket_cc and t.queue.updated_ticket_cc != t.queue.new_ticket_cc \ and t.queue.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=t.queue.updated_ticket_cc, sender=t.queue.from_address, fail_silently=True, files=files, ) return HttpResponseRedirect(self.get_success_url())
def update_ticket(request, ticket_id, public=False): if not (public or (request.user.is_authenticated() and request.user.is_active and (request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE))): return HttpResponseForbidden(_('Sorry, you need to login to do that.')) ticket = get_object_or_404(Ticket, id=ticket_id) comment = request.POST.get('comment', '') new_status = int(request.POST.get('new_status', ticket.status)) title = request.POST.get('title', '') public = request.POST.get('public', False) owner = int(request.POST.get('owner', None)) priority = int(request.POST.get('priority', ticket.priority)) due_year = int(request.POST.get('due_date_year')) due_month = int(request.POST.get('due_date_month')) due_day = int(request.POST.get('due_date_day')) due_date = datetime( due_year, due_month, due_day) if due_year and due_month and due_day else ticket.due_date tags = request.POST.get('tags', '') # We need to allow the 'ticket' and 'queue' contexts to be applied to the # comment. from django.template import loader, Context context = safe_template_context(ticket) # this line sometimes creates problems if code is sent as a comment. # if comment contains some django code, like "why does {% if bla %} crash", # then the following line will give us a crash, since django expects {% if %} # to be closed with an {% endif %} tag. comment = loader.get_template_from_string(comment).render(Context(context)) if owner is None and ticket.assigned_to: owner = ticket.assigned_to.id f = FollowUp(ticket=ticket, date=datetime.now(), comment=comment) if request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE: f.user = request.user f.public = public reassigned = False if owner is not None: if owner != 0 and ( (ticket.assigned_to and owner != ticket.assigned_to.id) or not ticket.assigned_to): new_user = User.objects.get(id=owner) f.title = _('Assigned to %(username)s') % { 'username': new_user.username, } ticket.assigned_to = new_user reassigned = True # user changed owner to 'unassign' elif owner == 0 and ticket.assigned_to is not None: f.title = _('Unassigned') ticket.assigned_to = None if new_status != ticket.status: ticket.status = new_status ticket.save() f.new_status = new_status if f.title: f.title += ' and %s' % ticket.get_status_display() else: f.title = '%s' % ticket.get_status_display() if not f.title: if f.comment: f.title = _('Comment') else: f.title = _('Updated') f.save() files = [] if request.FILES: import mimetypes, os for file in request.FILES.getlist('attachment'): filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) if title != ticket.title: c = TicketChange( followup=f, field=_('Title'), old_value=ticket.title, new_value=title, ) c.save() ticket.title = title if priority != ticket.priority: c = TicketChange( followup=f, field=_('Priority'), old_value=ticket.priority, new_value=priority, ) c.save() ticket.priority = priority if due_date != ticket.due_date: c = TicketChange( followup=f, field=_('Due on'), old_value=ticket.due_date, new_value=due_date, ) if helpdesk_settings.HELPDESK_UPDATE_CALENDAR: from helpdesk import calendars calendars.update_calendar(request, search_date=ticket.due_date) c.save() ticket.due_date = due_date if HAS_TAGGING_SUPPORT: if tags != ticket.tags: c = TicketChange( followup=f, field=_('Tags'), old_value=ticket.tags, new_value=tags, ) c.save() ticket.tags = tags if HAS_TAGGIT_SUPPORT: old_tags = [tag.name for tag in ticket.tags.all()] old_tags.sort() new_tags = tags.replace(' ', '').strip(',').split(',') new_tags.sort() if new_tags != old_tags: c = TicketChange( followup=f, field=_('Tags'), old_value=', '.join(old_tags), new_value=', '.join(new_tags), ) c.save() ticket.tags.set(*new_tags) if new_status in [Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS]: ticket.resolution = comment messages_sent_to = [] # ticket might have changed above, so we re-instantiate context with the # (possibly) updated ticket. context = safe_template_context(ticket) context.update( resolution=ticket.resolution, comment=f.comment, ) if ticket.submitter_email and public and ( f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))): if f.new_status == Ticket.RESOLVED_STATUS: template = 'resolved_submitter' elif f.new_status == Ticket.CLOSED_STATUS: template = 'closed_submitter' else: template = 'updated_submitter' send_templated_mail( template, context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.submitter_email) for cc in ticket.ticketcc_set.all(): if cc.email_address not in messages_sent_to: send_templated_mail( template, context, recipients=cc.email_address, sender=ticket.queue.from_address, fail_silently=True, ) messages_sent_to.append(cc.email_address) if ticket.assigned_to and request.user != ticket.assigned_to and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to: # We only send e-mails to staff members if the ticket is updated by # another user. The actual template varies, depending on what has been # changed. if reassigned: template_staff = 'assigned_owner' elif f.new_status == Ticket.RESOLVED_STATUS: template_staff = 'resolved_owner' elif f.new_status == Ticket.CLOSED_STATUS: template_staff = 'closed_owner' else: template_staff = 'updated_owner' if (not reassigned or (reassigned and ticket.assigned_to.usersettings.settings.get( 'email_on_ticket_assign', False))) or ( not reassigned and ticket.assigned_to.usersettings.settings.get( 'email_on_ticket_change', False)): send_templated_mail( template_staff, context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.assigned_to.email) if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to: if reassigned: template_cc = 'assigned_cc' elif f.new_status == Ticket.RESOLVED_STATUS: template_cc = 'resolved_cc' elif f.new_status == Ticket.CLOSED_STATUS: template_cc = 'closed_cc' else: template_cc = 'updated_cc' send_templated_mail( template_cc, context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True, files=files, ) ticket.save() if request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE: return HttpResponseRedirect(ticket.get_absolute_url()) else: return HttpResponseRedirect(ticket.ticket_url)
def save(self): """ Writes and returns a Ticket() object """ q = self.cleaned_data["queue"] t = Ticket( title=self.cleaned_data["title"], submitter_email=self.cleaned_data["submitter_email"], created=timezone.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data["body"], priority=self.cleaned_data["priority"], due_date=self.cleaned_data["due_date"], ) t.save() for field, value in self.cleaned_data.items(): if field.startswith("custom_"): field_name = field.replace("custom_", "", 1) customfield = CustomField.objects.get(name=field_name) cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() f = FollowUp( ticket=t, title=_("Ticket Opened Via Web"), date=timezone.now(), public=True, comment=self.cleaned_data["body"], ) f.save() files = [] if self.cleaned_data["attachment"]: import mimetypes file = self.cleaned_data["attachment"] filename = file.name.replace(" ", "_") a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or "application/octet-stream", size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, "MAX_EMAIL_ATTACHMENT_SIZE", 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append([a.filename, a.file]) context = safe_template_context(t) messages_sent_to = [] send_templated_mail( "newticket_submitter", context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( "newticket_cc", context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if ( q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to ): send_templated_mail( "newticket_cc", context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def update_ticket(request, ticket_id, public=False): if not ( public or ( request.user.is_authenticated() and request.user.is_active and (request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE) ) ): return HttpResponseForbidden(_("Sorry, you need to login to do that.")) ticket = get_object_or_404(Ticket, id=ticket_id) comment = request.POST.get("comment", "") new_status = int(request.POST.get("new_status", ticket.status)) title = request.POST.get("title", "") public = request.POST.get("public", False) owner = int(request.POST.get("owner", None)) priority = int(request.POST.get("priority", ticket.priority)) due_year = int(request.POST.get("due_date_year")) due_month = int(request.POST.get("due_date_month")) due_day = int(request.POST.get("due_date_day")) due_date = datetime(due_year, due_month, due_day) if due_year and due_month and due_day else ticket.due_date tags = request.POST.get("tags", "") # We need to allow the 'ticket' and 'queue' contexts to be applied to the # comment. from django.template import loader, Context context = safe_template_context(ticket) # this line sometimes creates problems if code is sent as a comment. # if comment contains some django code, like "why does {% if bla %} crash", # then the following line will give us a crash, since django expects {% if %} # to be closed with an {% endif %} tag. comment = loader.get_template_from_string(comment).render(Context(context)) if owner is None and ticket.assigned_to: owner = ticket.assigned_to.id f = FollowUp(ticket=ticket, date=datetime.now(), comment=comment) if request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE: f.user = request.user f.public = public reassigned = False if owner is not None: if owner != 0 and ((ticket.assigned_to and owner != ticket.assigned_to.id) or not ticket.assigned_to): new_user = User.objects.get(id=owner) f.title = _("Assigned to %(username)s") % {"username": new_user.username} ticket.assigned_to = new_user reassigned = True # user changed owner to 'unassign' elif owner == 0 and ticket.assigned_to is not None: f.title = _("Unassigned") ticket.assigned_to = None if new_status != ticket.status: ticket.status = new_status ticket.save() f.new_status = new_status if f.title: f.title += " and %s" % ticket.get_status_display() else: f.title = "%s" % ticket.get_status_display() if not f.title: if f.comment: f.title = _("Comment") else: f.title = _("Updated") f.save() files = [] if request.FILES: import mimetypes, os for file in request.FILES.getlist("attachment"): filename = file.name.replace(" ", "_") a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or "application/octet-stream", size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, "MAX_EMAIL_ATTACHMENT_SIZE", 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) if title != ticket.title: c = TicketChange(followup=f, field=_("Title"), old_value=ticket.title, new_value=title) c.save() ticket.title = title if priority != ticket.priority: c = TicketChange(followup=f, field=_("Priority"), old_value=ticket.priority, new_value=priority) c.save() ticket.priority = priority if due_date != ticket.due_date: c = TicketChange(followup=f, field=_("Due on"), old_value=ticket.due_date, new_value=due_date) if helpdesk_settings.HELPDESK_UPDATE_CALENDAR: from helpdesk import calendars calendars.update_calendar(request, search_date=ticket.due_date) c.save() ticket.due_date = due_date if HAS_TAGGING_SUPPORT: if tags != ticket.tags: c = TicketChange(followup=f, field=_("Tags"), old_value=ticket.tags, new_value=tags) c.save() ticket.tags = tags if HAS_TAGGIT_SUPPORT: old_tags = [tag.name for tag in ticket.tags.all()] old_tags.sort() new_tags = tags.replace(" ", "").strip(",").split(",") new_tags.sort() if new_tags != old_tags: c = TicketChange(followup=f, field=_("Tags"), old_value=", ".join(old_tags), new_value=", ".join(new_tags)) c.save() ticket.tags.set(*new_tags) if new_status in [Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS]: ticket.resolution = comment messages_sent_to = [] # ticket might have changed above, so we re-instantiate context with the # (possibly) updated ticket. context = safe_template_context(ticket) context.update(resolution=ticket.resolution, comment=f.comment) if ( ticket.submitter_email and public and (f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))) ): if f.new_status == Ticket.RESOLVED_STATUS: template = "resolved_submitter" elif f.new_status == Ticket.CLOSED_STATUS: template = "closed_submitter" else: template = "updated_submitter" send_templated_mail( template, context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.submitter_email) for cc in ticket.ticketcc_set.all(): if cc.email_address not in messages_sent_to: send_templated_mail( template, context, recipients=cc.email_address, sender=ticket.queue.from_address, fail_silently=True ) messages_sent_to.append(cc.email_address) if ( ticket.assigned_to and request.user != ticket.assigned_to and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to ): # We only send e-mails to staff members if the ticket is updated by # another user. The actual template varies, depending on what has been # changed. if reassigned: template_staff = "assigned_owner" elif f.new_status == Ticket.RESOLVED_STATUS: template_staff = "resolved_owner" elif f.new_status == Ticket.CLOSED_STATUS: template_staff = "closed_owner" else: template_staff = "updated_owner" if ( not reassigned or (reassigned and ticket.assigned_to.usersettings.settings.get("email_on_ticket_assign", False)) ) or (not reassigned and ticket.assigned_to.usersettings.settings.get("email_on_ticket_change", False)): send_templated_mail( template_staff, context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.assigned_to.email) if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to: if reassigned: template_cc = "assigned_cc" elif f.new_status == Ticket.RESOLVED_STATUS: template_cc = "resolved_cc" elif f.new_status == Ticket.CLOSED_STATUS: template_cc = "closed_cc" else: template_cc = "updated_cc" send_templated_mail( template_cc, context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True, files=files, ) ticket.save() if request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE: return HttpResponseRedirect(ticket.get_absolute_url()) else: return HttpResponseRedirect(ticket.ticket_url)
def ticket_from_message(message, queue, logger): # 'message' must be an RFC822 formatted message. msg = message message = email.message_from_string(msg) subject = message.get('subject', _('Created from e-mail')) subject = decode_mail_headers(decodeUnknown(message.get_charset(), subject)) for affix in STRIPPED_SUBJECT_STRINGS: subject = subject.replace(affix, "") subject = subject.strip() sender = message.get('from', _('Unknown Sender')) sender = decode_mail_headers(decodeUnknown(message.get_charset(), sender)) sender_email = parseaddr(sender)[1] body_plain, body_html = '', '' for ignore in IgnoreEmail.objects.filter(Q(queues=queue) | Q(queues__isnull=True)): if ignore.test(sender_email): if ignore.keep_in_mailbox: # By returning 'False' the message will be kept in the mailbox, # and the 'True' will cause the message to be deleted. return False return True matchobj = re.match(r".*\[" + queue.slug + "-(?P<id>\d+)\]", subject) if matchobj: # This is a reply or forward. ticket = matchobj.group('id') logger.info("Matched tracking ID %s-%s" % (queue.slug, ticket)) else: logger.info("No tracking ID matched.") ticket = None counter = 0 files = [] for part in message.walk(): if part.get_content_maintype() == 'multipart': continue name = part.get_param("name") if name: name = collapse_rfc2231_value(name) if part.get_content_maintype() == 'text' and name is None: if part.get_content_subtype() == 'plain': body_plain = EmailReplyParser.parse_reply( decodeUnknown(part.get_content_charset(), part.get_payload(decode=True))) logger.debug("Discovered plain text MIME part") else: body_html = part.get_payload(decode=True) logger.debug("Discovered HTML MIME part") else: if not name: ext = mimetypes.guess_extension(part.get_content_type()) name = "part-%i%s" % (counter, ext) files.append({ 'filename': name, 'content': part.get_payload(decode=True), 'type': part.get_content_type()}, ) logger.debug("Found MIME attachment %s" % name) counter += 1 if body_plain: body = body_plain else: body = _('No plain-text email body available. Please see attachment "email_html_body.html".') if body_html: files.append({ 'filename': _("email_html_body.html"), 'content': body_html, 'type': 'text/html', }) now = timezone.now() if ticket: try: t = Ticket.objects.get(id=ticket) new = False logger.info("Found existing ticket with Tracking ID %s-%s" % (t.queue.slug, t.id)) except Ticket.DoesNotExist: logger.info("Tracking ID %s-%s not associated with existing ticket. Creating new ticket." % (queue.slug, ticket)) ticket = None priority = 3 smtp_priority = message.get('priority', '') smtp_importance = message.get('importance', '') high_priority_types = ('high', 'important', '1', 'urgent') 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, created=now, description=body, priority=priority, ) t.save() new = True logger.debug("Created new ticket %s-%s" % (t.queue.slug, t.id)) 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() logger.debug("Created new FollowUp for Ticket") if six.PY2: logger.info(("[%s-%s] %s" % (t.queue.slug, t.id, t.title,)).encode('ascii', 'replace')) elif six.PY3: logger.info("[%s-%s] %s" % (t.queue.slug, t.id, t.title,)) for file in files: if file['content']: if six.PY2: filename = file['filename'].encode('ascii', 'replace').replace(' ', '_') elif six.PY3: filename = file['filename'].replace(' ', '_') filename = re.sub('[^a-zA-Z0-9._-]+', '', filename) logger.info("Found attachment '%s'" % 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() logger.info("Attachment '%s' successfully added to ticket." % 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, ) 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
def save(self): """ Writes and returns a Ticket() object """ q = Queue.objects.get(id=int(self.cleaned_data['queue'])) t = Ticket( title=self.cleaned_data['title'], submitter_email=self.cleaned_data['submitter_email'], created=timezone.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data['body'], priority=self.cleaned_data['priority'], due_date=self.cleaned_data['due_date'], ) if q.default_owner and not t.assigned_to: t.assigned_to = q.default_owner t.save() for field, value in self.cleaned_data.items(): if field.startswith('custom_'): field_name = field.replace('custom_', '', 1) customfield = CustomField.objects.get(name=field_name) cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() f = FollowUp( ticket=t, title=_('Ticket Opened Via Web'), date=timezone.now(), public=True, comment=self.cleaned_data['body'], ) f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append([a.filename, a.file]) context = safe_template_context(t) messages_sent_to = [] send_templated_mail( 'newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if t.assigned_to and \ t.assigned_to.usersettings.settings.get('email_on_ticket_assign', False) and \ t.assigned_to.email and \ t.assigned_to.email not in messages_sent_to: send_templated_mail( 'assigned_owner', context, recipients=t.assigned_to.email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.assigned_to.email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and \ q.updated_ticket_cc != q.new_ticket_cc and \ q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def save(self, user): """ Writes and returns a Ticket() object """ q = self.cleaned_data['queue'] t = Ticket( title=self.cleaned_data['title'], submitter_email=self.cleaned_data['submitter_email'], created=datetime.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data['description'], priority=self.cleaned_data['priority'], due_date=self.cleaned_data['due_date'], ) if HAS_TAGGING_SUPPORT: t.tags = self.cleaned_data['tags'] if self.cleaned_data['assigned_to']: try: u = self.cleaned_data['assigned_to'] t.assigned_to = u except User.DoesNotExist: t.assigned_to = None t.save() if HAS_TAGGIT_SUPPORT: t.tags.set(*self.cleaned_data['tags']) for field, value in self.cleaned_data.items(): if field.startswith('custom_'): field_name = field.replace('custom_', '') customfield = CustomField.objects.get(name=field_name) cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() f = FollowUp( ticket=t, title=_('Ticket Opened'), date=datetime.now(), public=True, comment=self.cleaned_data['description'] if helpdesk_settings.HELPDESK_INCLUDE_DESCRIPTION_IN_FOLLOWUP else None, user=user, ) if self.cleaned_data['assigned_to']: f.title = _('Ticket Opened & Assigned to %(name)s') % { 'name': t.get_assigned_to } f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = safe_template_context(t) context['comment'] = f.comment messages_sent_to = [] if t.submitter_email: send_templated_mail( 'newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if t.assigned_to and t.assigned_to != user and getattr( t.assigned_to.usersettings.settings, 'email_on_ticket_assign', False ) and t.assigned_to.email and t.assigned_to.email not in messages_sent_to: send_templated_mail( 'assigned_owner', context, recipients=t.assigned_to.email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.assigned_to.email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def save(self, user): """ Writes and returns a Ticket() object """ q = self.cleaned_data['queue'] t = Ticket( title = self.cleaned_data['title'], submitter_email = self.cleaned_data['submitter_email'], account = self.cleaned_data['account'], created = datetime.now(), status = Ticket.OPEN_STATUS, queue = q, description = self.cleaned_data['body'], priority = self.cleaned_data['priority'], owner = self.cleaned_data['owner'] ) if HAS_TAG_SUPPORT: t.tags = self.cleaned_data['tags'] if self.cleaned_data['assigned_to']: try: t.assigned_to = self.cleaned_data['assigned_to'] except User.DoesNotExist: t.assigned_to = None t.save() f = FollowUp( ticket = t, title = _('Ticket Opened'), date = datetime.now(), public = False, comment = self.cleaned_data['body'], systemuser = user.account, ) if self.cleaned_data['assigned_to']: f.title = _('Ticket Opened & Assigned to %(name)s') % { 'name': t.get_assigned_to } f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = { 'ticket': t, 'queue': q, 'comment': f.comment, } messages_sent_to = [] if t.submitter_email: send_templated_mail( 'newticket_owner', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) #FIX USERSETTINGS #======================================================================= # if t.assigned_to and t.assigned_to != user and getattr(t.assigned_to.usersettings.settings, 'email_on_ticket_assign', False) and t.assigned_to.email and t.assigned_to.email not in messages_sent_to: # send_templated_mail( # 'assigned_to', # context, # recipients=t.assigned_to.email, # sender=q.from_address, # fail_silently=True, # files=files, # ) # messages_sent_to.append(t.assigned_to.email) #======================================================================= if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def save(self, user): """ Writes and returns a Ticket() object """ q = self.cleaned_data['queue'] t = Ticket(title=self.cleaned_data['title'], submitter_email=self.cleaned_data['submitter_email'], account=self.cleaned_data['account'], created=datetime.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data['body'], priority=self.cleaned_data['priority'], owner=self.cleaned_data['owner']) if HAS_TAG_SUPPORT: t.tags = self.cleaned_data['tags'] if self.cleaned_data['assigned_to']: try: t.assigned_to = self.cleaned_data['assigned_to'] except User.DoesNotExist: t.assigned_to = None t.save() f = FollowUp( ticket=t, title=_('Ticket Opened'), date=datetime.now(), public=False, comment=self.cleaned_data['body'], systemuser=user.account, ) if self.cleaned_data['assigned_to']: f.title = _('Ticket Opened & Assigned to %(name)s') % { 'name': t.get_assigned_to } f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = { 'ticket': t, 'queue': q, 'comment': f.comment, } messages_sent_to = [] if t.submitter_email: send_templated_mail( 'newticket_owner', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) #FIX USERSETTINGS #======================================================================= # if t.assigned_to and t.assigned_to != user and getattr(t.assigned_to.usersettings.settings, 'email_on_ticket_assign', False) and t.assigned_to.email and t.assigned_to.email not in messages_sent_to: # send_templated_mail( # 'assigned_to', # context, # recipients=t.assigned_to.email, # sender=q.from_address, # fail_silently=True, # files=files, # ) # messages_sent_to.append(t.assigned_to.email) #======================================================================= if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def save(self, user): """ Writes and returns a Ticket() object """ q = Queue.objects.get(id=int(self.cleaned_data['queue'])) t = Ticket( title = self.cleaned_data['title'], submitter_email = self.cleaned_data['submitter_email'], created = timezone.now(), status = Ticket.OPEN_STATUS, queue = q, description = self.cleaned_data['body'], priority = self.cleaned_data['priority'], due_date = self.cleaned_data['due_date'], ) if HAS_TAG_SUPPORT: t.tags = self.cleaned_data['tags'] if self.cleaned_data['assigned_to']: try: u = User.objects.get(id=self.cleaned_data['assigned_to']) t.assigned_to = u except User.DoesNotExist: t.assigned_to = None t.save() for field, value in self.cleaned_data.items(): if field.startswith('custom_'): field_name = field.replace('custom_', '') customfield = CustomField.objects.get(name=field_name) cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() f = FollowUp( ticket = t, title = _('Ticket Opened'), date = timezone.now(), public = True, comment = self.cleaned_data['body'], user = user, ) if self.cleaned_data['assigned_to']: f.title = _('Ticket Opened & Assigned to %(name)s') % { 'name': t.get_assigned_to } f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = safe_template_context(t) context['comment'] = f.comment messages_sent_to = [] if t.submitter_email: send_templated_mail( 'newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.submitter_email) if t.assigned_to and t.assigned_to != user and t.assigned_to.usersettings.settings.get('email_on_ticket_assign', False) and t.assigned_to.email and t.assigned_to.email not in messages_sent_to: send_templated_mail( 'assigned_owner', context, recipients=t.assigned_to.email, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(t.assigned_to.email) if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) messages_sent_to.append(q.new_ticket_cc) if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc and q.updated_ticket_cc not in messages_sent_to: send_templated_mail( 'newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True, files=files, ) return t
def followup_edit(request): id = request.POST.get("id") item = None if request.method == 'POST': if id: model = FollowUp.objects.get(id=id) form = FollowUpForm(request.POST, instance=model) if not (request.user.account.has_perm('helpdesk.change_followup')): messages.error(request, _(u'У вас нет прав на редактирование комментариев к заявке'), extra_tags='alert-danger') return HttpResponseRedirect(request.path) else: form = FollowUpForm(request.POST, request.FILES) if not (request.user.account.has_perm('helpdesk.add_followup')): messages.error(request, _(u'У вас нет прав на добавление комментариев к заявке'), extra_tags='alert-danger') return HttpResponseRedirect(request.path) if form.is_valid(): model = form.save(commit=False) model.save() followup_type = form.cleaned_data.get('followup_type') if followup_type=='comment': if not id: model.title = _(u'Добавлен комментарий от %(USER)s ') % {'USER': request.user.account} elif followup_type=='files': if not id: model.title = _(u'Добавлен файл от %(USER)s ') % {'USER': request.user.account} files = [] if request.FILES: import mimetypes, os for file in request.FILES.getlist('file'): filename = file.name.replace(' ', '_') a = Attachment( followup=model, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) elif followup_type=='new_status': model.title = _(u'Статус заявки изменён %(USER)s ') % {'USER': request.user.account} if model.new_status!=model.ticket: model.ticket.status = model.new_status if model.new_status in [3,4]: model.ticket.resolution = model.comment model.ticket.save() log('EDIT', request.user, model.ticket) model.systemuser = request.user.account model.save() from django.template import loader, Context log('EDIT', request.user, model) if id else log('CREATE', request.user, model) messages.success(request, _(u'Комментарий успешно сохранён.'), extra_tags='alert-success') return {'form':form, 'status': True} else: messages.error(request, _(u'При сохранении комментария возникли ошибки.'), extra_tags='alert-danger') if form._errors: for k, v in form._errors.items(): messages.error(request, '%s=>%s' % (k, ','.join(v)), extra_tags='alert-danger') return {'form':form, 'status': False} else: id = request.GET.get("id") ticket_id = request.GET.get("ticket_id") followup_type = request.GET.get("followup_type") or 'comment' new_status = request.GET.get("new_status") if not (request.user.account.has_perm('helpdesk.add_followup')): messages.error(request, _(u'У вас нет прав на создание комментариев.'), extra_tags='alert-danger') return {} if id: item = FollowUp.objects.get(id=id) form = FollowUpForm(instance=item) else: if new_status: form = FollowUpForm(initial={'ticket': Ticket.objects.get(id=ticket_id), 'followup_type': followup_type, 'new_status':2}) else: form = FollowUpForm(initial={'ticket': Ticket.objects.get(id=ticket_id), 'followup_type': followup_type}) return { 'form':form, 'status': False}
def update_ticket(request, ticket_id, public=False): if not (public or (request.user.is_authenticated() and request.user.is_active and request.user.is_staff)): return HttpResponseForbidden(_('Sorry, you need to login to do that.')) ticket = get_object_or_404(Ticket, id=ticket_id) comment = request.POST.get('comment', '') new_status = int(request.POST.get('new_status', ticket.status)) title = request.POST.get('title', '') public = request.POST.get('public', False) owner = int(request.POST.get('owner', None)) priority = int(request.POST.get('priority', ticket.priority)) tags = request.POST.get('tags', '') # We need to allow the 'ticket' and 'queue' contexts to be applied to the # comment. from django.template import loader, Context context = safe_template_context(ticket) comment = loader.get_template_from_string(comment).render(Context(context)) if owner is None and ticket.assigned_to: owner = ticket.assigned_to.id f = FollowUp(ticket=ticket, date=datetime.now(), comment=comment) if request.user.is_staff: f.user = request.user f.public = public reassigned = False if owner is not None: if owner != 0 and ((ticket.assigned_to and owner != ticket.assigned_to.id) or not ticket.assigned_to): new_user = User.objects.get(id=owner) f.title = _('Assigned to %(username)s') % { 'username': new_user.username, } ticket.assigned_to = new_user reassigned = True elif owner == 0 and ticket.assigned_to is not None: f.title = _('Unassigned') ticket.assigned_to = None if new_status != ticket.status: ticket.status = new_status ticket.save() f.new_status = new_status if f.title: f.title += ' and %s' % ticket.get_status_display() else: f.title = '%s' % ticket.get_status_display() if not f.title: if f.comment: f.title = _('Comment') else: f.title = _('Updated') f.save() files = [] if request.FILES: import mimetypes, os for file in request.FILES.getlist('attachment'): filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) if title != ticket.title: c = TicketChange( followup=f, field=_('Title'), old_value=ticket.title, new_value=title, ) c.save() ticket.title = title if priority != ticket.priority: c = TicketChange( followup=f, field=_('Priority'), old_value=ticket.priority, new_value=priority, ) c.save() ticket.priority = priority if HAS_TAG_SUPPORT: if tags != ticket.tags: c = TicketChange( followup=f, field=_('Tags'), old_value=ticket.tags, new_value=tags, ) c.save() ticket.tags = tags if f.new_status == Ticket.RESOLVED_STATUS: ticket.resolution = comment messages_sent_to = [] # ticket might have changed above, so we re-instantiate context with the # (possibly) updated ticket. context = safe_template_context(ticket) context.update( resolution=ticket.resolution, comment=f.comment, ) if ticket.submitter_email and public and (f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))): if f.new_status == Ticket.RESOLVED_STATUS: template = 'resolved_submitter' elif f.new_status == Ticket.CLOSED_STATUS: template = 'closed_submitter' else: template = 'updated_submitter' send_templated_mail( template, context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.submitter_email) for cc in ticket.ticketcc_set.all(): if cc.email_address not in messages_sent_to: send_templated_mail( template, context, recipients=cc.email_address, sender=ticket.queue.from_address, fail_silently=True, ) messages_sent_to.append(cc.email_address) if ticket.assigned_to and request.user != ticket.assigned_to and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to: # We only send e-mails to staff members if the ticket is updated by # another user. The actual template varies, depending on what has been # changed. if reassigned: template_staff = 'assigned_owner' elif f.new_status == Ticket.RESOLVED_STATUS: template_staff = 'resolved_owner' elif f.new_status == Ticket.CLOSED_STATUS: template_staff = 'closed_owner' else: template_staff = 'updated_owner' if (not reassigned or ( reassigned and ticket.assigned_to.usersettings.settings.get('email_on_ticket_assign', False))) or (not reassigned and ticket.assigned_to.usersettings.settings.get('email_on_ticket_change', False)): send_templated_mail( template_staff, context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True, files=files, ) messages_sent_to.append(ticket.assigned_to.email) if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to: if reassigned: template_cc = 'assigned_cc' elif f.new_status == Ticket.RESOLVED_STATUS: template_cc = 'resolved_cc' elif f.new_status == Ticket.CLOSED_STATUS: template_cc = 'closed_cc' else: template_cc = 'updated_cc' send_templated_mail( template_cc, context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True, files=files, ) ticket.save() if request.user.is_staff: return HttpResponseRedirect(ticket.get_absolute_url()) else: return HttpResponseRedirect(ticket.ticket_url)
def followup_edit(request): id = request.POST.get("id") item = None if request.method == 'POST': if id: model = FollowUp.objects.get(id=id) form = FollowUpForm(request.POST, instance=model) if not (request.user.account.has_perm('helpdesk.change_followup')): messages.error( request, _(u'У вас нет прав на редактирование комментариев к заявке' ), extra_tags='alert-danger') return HttpResponseRedirect(request.path) else: form = FollowUpForm(request.POST, request.FILES) if not (request.user.account.has_perm('helpdesk.add_followup')): messages.error( request, _(u'У вас нет прав на добавление комментариев к заявке'), extra_tags='alert-danger') return HttpResponseRedirect(request.path) if form.is_valid(): model = form.save(commit=False) model.save() followup_type = form.cleaned_data.get('followup_type') if followup_type == 'comment': if not id: model.title = _(u'Добавлен комментарий от %(USER)s ') % { 'USER': request.user.account } elif followup_type == 'files': if not id: model.title = _(u'Добавлен файл от %(USER)s ') % { 'USER': request.user.account } files = [] if request.FILES: import mimetypes, os for file in request.FILES.getlist('file'): filename = file.name.replace(' ', '_') a = Attachment( followup=model, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr( settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) elif followup_type == 'new_status': model.title = _(u'Статус заявки изменён %(USER)s ') % { 'USER': request.user.account } if model.new_status != model.ticket: model.ticket.status = model.new_status if model.new_status in [3, 4]: model.ticket.resolution = model.comment model.ticket.save() log('EDIT', request.user, model.ticket) model.systemuser = request.user.account model.save() from django.template import loader, Context log('EDIT', request.user, model) if id else log( 'CREATE', request.user, model) messages.success(request, _(u'Комментарий успешно сохранён.'), extra_tags='alert-success') return {'form': form, 'status': True} else: messages.error(request, _(u'При сохранении комментария возникли ошибки.'), extra_tags='alert-danger') if form._errors: for k, v in form._errors.items(): messages.error(request, '%s=>%s' % (k, ','.join(v)), extra_tags='alert-danger') return {'form': form, 'status': False} else: id = request.GET.get("id") ticket_id = request.GET.get("ticket_id") followup_type = request.GET.get("followup_type") or 'comment' new_status = request.GET.get("new_status") if not (request.user.account.has_perm('helpdesk.add_followup')): messages.error(request, _(u'У вас нет прав на создание комментариев.'), extra_tags='alert-danger') return {} if id: item = FollowUp.objects.get(id=id) form = FollowUpForm(instance=item) else: if new_status: form = FollowUpForm( initial={ 'ticket': Ticket.objects.get(id=ticket_id), 'followup_type': followup_type, 'new_status': 2 }) else: form = FollowUpForm( initial={ 'ticket': Ticket.objects.get(id=ticket_id), 'followup_type': followup_type }) return {'form': form, 'status': False}
def ticket_from_message(message, queue, quiet): # 'message' must be an RFC822 formatted message. msg = message message = email.message_from_string(msg) subject = message.get('subject', _('Created from e-mail')) subject = decode_mail_headers(decodeUnknown(message.get_charset(), subject)) subject = subject.replace("Re: ", "").replace("Fw: ", "").replace( "RE: ", "").replace("FW: ", "").replace("Automatic reply: ", "").strip() sender = message.get('from', _('Unknown Sender')) sender = decode_mail_headers(decodeUnknown(message.get_charset(), sender)) sender_email = parseaddr(sender)[1] body_plain, body_html = '', '' for ignore in IgnoreEmail.objects.filter( Q(queues=queue) | Q(queues__isnull=True)): if ignore.test(sender_email): if ignore.keep_in_mailbox: # By returning 'False' the message will be kept in the mailbox, # and the 'True' will cause the message to be deleted. return False return True matchobj = re.match(r".*\[" + queue.slug + "-(?P<id>\d+)\]", subject) if matchobj: # This is a reply or forward. ticket = matchobj.group('id') else: ticket = None counter = 0 files = [] for part in message.walk(): if part.get_content_maintype() == 'multipart': continue name = part.get_param("name") if name: name = collapse_rfc2231_value(name) if part.get_content_maintype() == 'text' and name == None: if part.get_content_subtype() == 'plain': body_plain = EmailReplyParser.parse_reply( decodeUnknown(part.get_content_charset(), part.get_payload(decode=True))) else: body_html = part.get_payload(decode=True) else: if not name: ext = mimetypes.guess_extension(part.get_content_type()) name = "part-%i%s" % (counter, ext) files.append( { 'filename': name, 'content': part.get_payload(decode=True), 'type': part.get_content_type() }, ) counter += 1 if body_plain: body = body_plain else: body = _( 'No plain-text email body available. Please see attachment email_html_body.html.' ) if body_html: files.append({ 'filename': _("email_html_body.html"), 'content': body_html, 'type': 'text/html', }) now = timezone.now() if ticket: try: t = Ticket.objects.get(id=ticket) new = False except Ticket.DoesNotExist: ticket = None priority = 3 smtp_priority = message.get('priority', '') smtp_importance = message.get('importance', '') high_priority_types = ('high', 'important', '1', 'urgent') if smtp_priority in high_priority_types or smtp_importance in high_priority_types: priority = 2 if ticket == None: t = Ticket( title=subject, queue=queue, submitter_email=sender_email, 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') print files for file in files: print file if file['content']: filename = file['filename'].encode('ascii', 'replace').replace(' ', '_') print filename filename = re.sub('[^a-zA-Z0-9._-]+', '', filename) print 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, ) 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
def save(self, request=None): """ Writes and returns a Ticket() object """ q = Queue.objects.get(id=int(self.cleaned_data['queue'])) t = Ticket( title=self.cleaned_data['title'], submitter_email=self.cleaned_data['submitter_email'], created=datetime.now(), status=Ticket.OPEN_STATUS, queue=q, description=self.cleaned_data['body'], priority=self.cleaned_data['priority'], ) t.save() for field, value in self.cleaned_data.items(): if field.startswith('custom_'): field_name = field.replace('custom_', '') customfield = CustomField.objects.get(name=field_name) cfv = TicketCustomFieldValue(ticket=t, field=customfield, value=value) cfv.save() f = FollowUp( ticket=t, title=_('Ticket Opened Via Web'), date=datetime.now(), public=True, comment=self.cleaned_data['body'], ) f.save() files = [] if self.cleaned_data['attachment']: import mimetypes file = self.cleaned_data['attachment'] filename = file.name.replace(' ', '_') a = Attachment( followup=f, filename=filename, mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', size=file.size, ) a.file.save(file.name, file, save=False) a.save() if file.size < getattr(settings, 'MAX_EMAIL_ATTACHMENT_SIZE', 512000): # Only files smaller than 512kb (or as defined in # settings.MAX_EMAIL_ATTACHMENT_SIZE) are sent via email. files.append(a.file.path) context = { 'ticket': t, 'queue': q, 'site': Site.objects.get_current(), 'request': request } send_templated_mail( 'newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True, files=files, ) who_to_notify = [] emails = "%s,%s" % (q.new_ticket_cc, q.updated_ticket_cc) for e in emails.split(','): email = e.strip(' ') if email and email != t.submitter_email and email not in who_to_notify: who_to_notify.append(email) if who_to_notify: send_templated_mail( 'newticket_cc', context, recipients=who_to_notify, sender=q.from_address, fail_silently=True, files=files, ) return t