Esempio n. 1
0
def followup_edit(request, ticket_id, followup_id, ):
    "Edit followup options with an ability to change the ticket."
    followup = get_object_or_404(FollowUp, id=followup_id)
    ticket = get_object_or_404(Ticket, id=ticket_id)
    if request.method == 'GET':
        form = EditFollowUpForm(initial=
                                     {'title': escape(followup.title),
                                      'ticket': followup.ticket,
                                      'comment': escape(followup.comment),
                                      'public': followup.public,
                                      'new_status': followup.new_status,
                                      })
        
        return render_to_response('helpdesk/followup_edit.html',
            RequestContext(request, {
                'followup': followup,
                'ticket': ticket,
                'form': form,
        }))
    elif request.method == 'POST':
        form = EditFollowUpForm(request.POST)
        if form.is_valid():
            title = form.cleaned_data['title']
            _ticket = form.cleaned_data['ticket']
            comment = form.cleaned_data['comment']
            public = form.cleaned_data['public']
            new_status = form.cleaned_data['new_status']
            #will save previous date
            old_date = followup.date
            followup.delete()
            new_followup = FollowUp(title=title, date=old_date, ticket=_ticket, comment=comment, public=public, new_status=new_status, )
            new_followup.save()
        return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id]))
Esempio n. 2
0
def get_issue_status(repo, ticket):

    repo = repo + "/issues/" + ticket.github_issue_number

    token = settings.GITHUB_AUTH_TOKEN
    header = {'Authorization': 'token %s' % token}

    r = requests.get(repo, headers=header)
    try:
        if int(r.status_code) == 200:
            data = json.loads(r.content)

            update_ticket = Ticket.objects.get(id=ticket.id)

            title = data['title']
            updated_date = data['updated_at']
            state = data['state']
            description = ticket.description
            state_txt = ''
            if state == 'closed':
                status = 4  # If 'Closed' in github, save as 'Closed' in TW
                state_txt = 'Closed'

            elif state == 'open' and update_ticket.status == 4:
                status = 2
                state_txt = 'Reopened'
            else:
                status = 1
                state_txt = 'Open'

            # add a comment/explanation for the change of state in TW
            comments = '[GitHub Sync] Ticket is ' + str(
                state_txt) + ' in GitHub'

            current_status = update_ticket.status

            print 'Ticket#' + str(ticket.id) + str(comments)
            try:
                if current_status != 7 and status != 1:
                    if not int(current_status) == int(status):
                        new_followup = FollowUp(
                            title=title,
                            date=updated_date,
                            ticket_id=ticket.id,
                            comment=comments,
                            public=1,
                            new_status=status,
                        )
                        new_followup.save()

                update_ticket.status = status
            except Exception, e:
                pass
            update_ticket.title = title
            update_ticket.description = description

            try:
                update_ticket.save()
            except Exception, e:
                pass
Esempio n. 3
0
 def _create_follow_up(self, ticket, title, user=None):
     followup = FollowUp(
         ticket=ticket, title=title, date=timezone.now(), public=True, comment=self.cleaned_data["body"]
     )
     if user:
         followup.user = user
     return followup
Esempio n. 4
0
def followup_edit(request, ticket_id, followup_id, ):
    "Edit followup options with an ability to change the ticket."
    followup = get_object_or_404(FollowUp, id=followup_id)
    ticket = get_object_or_404(Ticket, id=ticket_id)
    if request.method == 'GET':
        form = EditFollowUpForm(initial=
                                     {'title': escape(followup.title),
                                      'ticket': followup.ticket,
                                      'comment': escape(followup.comment),
                                      'public': followup.public,
                                      'new_status': followup.new_status,
                                      })
        
        return render_to_response('helpdesk/followup_edit.html',
            RequestContext(request, {
                'followup': followup,
                'ticket': ticket,
                'form': form,
        }))
    elif request.method == 'POST':
        form = EditFollowUpForm(request.POST)
        if form.is_valid():
            title = form.cleaned_data['title']
            _ticket = form.cleaned_data['ticket']
            comment = form.cleaned_data['comment']
            public = form.cleaned_data['public']
            new_status = form.cleaned_data['new_status']
            #will save previous date
            old_date = followup.date
            followup.delete()
            new_followup = FollowUp(title=title, date=old_date, ticket=_ticket, comment=comment, public=public, new_status=new_status, )
            new_followup.save()
        return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id]))
Esempio n. 5
0
 def _create_follow_up(self, ticket, title, user=None):
     followup = FollowUp(ticket=ticket,
                         title=title,
                         date=timezone.now(),
                         public=True,
                         comment=self.cleaned_data['body'],
                         )
     if user:
         followup.user = user
     return followup
Esempio n. 6
0
 def set_validated(self, validated, user):
     if validated == True:
         self.validate_date = datetime.now()
         # append follow up to ticket
         follow = FollowUp(ticket=self.ticket,
                           date=self.validate_date,
                           title="已進行審核",
                           user=user)
         follow.save()
     elif validated == False:
         self.validate_date = None
 def take(self, request, *args, **kwargs):
   f = FollowUp(
     ticket_id=self.object.pk,
     user_id = request.user.pk,
     date=timezone.now(),
     comment='',
     title=_('Assigned to %s') % request.user.username,
     public = 1
   )
   f.save()
   self.object.assigned_to_id = request.user.id
   self.object.save(update_fields=['assigned_to'])
   return HttpResponseRedirect(self.get_success_url())
Esempio n. 8
0
def get_label(repo,ticket):

    repo = repo + "/issues/" + ticket.github_issue_number + "/labels"
    r = requests.get(repo)

    if int(r.status_code) == 200:
        data = json.loads(r.content)
        label_txt2 = ""
        label_txt = ""
        label_int = '0'

        for item in range(len(data)):
            label = data[item]['name']

            if label == "Tola-Work Ticket":
                label_txt = 'Submitted from TolaWork '

            elif label == "accepted":
                label_txt2 = ', accepted by QA Lead and moved into the Ready Queue'
                label_int = '5'

            elif label == "1 - Ready":
                label_txt2 = ', accepted by Developers and moved into the Ready Queue'
                label_int = '1'

            elif label == "2 - Working":
                label_txt2 = ' and Developers have started working on the Ticket'
                label_int = '2'

            elif label == "3 - In Dev":
                label_txt2 = ' and moved to Dev'
                label_int = '3'

            elif label == "4 - Done":
                label_txt2 = ' and its Done'
                label_int = '4'

        comments = '[Progress Update] Ticket ' + str(label_txt) + str(label_txt2)

        update_ticket = Ticket.objects.get(id=ticket.id)
        db_label = update_ticket.git_label

        if not int(db_label) == int(label_int):
            new_followup = FollowUp(title=ticket.title, ticket_id=ticket.id, comment=comments, public=1, )
            new_followup.save()

            update_ticket.git_label = label_int
            update_ticket.save()

    return r.status_code
Esempio n. 9
0
def hold_ticket(request, ticket_id, unhold=False):
    ticket = get_object_or_404(Ticket, id=ticket_id)

    if unhold:
        ticket.on_hold = False
        title = _("Ticket taken off hold")
    else:
        ticket.on_hold = True
        title = _("Ticket placed on hold")

    f = FollowUp(ticket=ticket, user=request.user, title=title, date=datetime.now(), public=True)
    f.save()

    ticket.save()

    return HttpResponseRedirect(ticket.get_absolute_url())
Esempio n. 10
0
def ticket_mark_complete(request, ticket_id):
  resolution = "Marked complete by " + request.user.username
  action = Ticket.objects.get(pk=ticket_id)
  follow_up = FollowUp (
                        ticket=action,
                        date=datetime.now(),
                        comment=resolution,
                        title="Reply Sent",
                        public=True)
  follow_up.save()
  
  action = get_object_or_404(Ticket, pk=ticket_id)
  action.status = Ticket.CLOSED_STATUS
  action.resolution = follow_up.comment
  action.save()
  
  return redirect("list_email_tickets")
Esempio n. 11
0
  def post(self, request, *args, **kwargs):
    if self.kwargs['unhold']:
        self.object.on_hold = False
        title = _('Ticket taken off hold')
    else:
        self.object.on_hold = True
        title = _('Ticket placed on hold')
    self.object.save(update_fields=['on_hold'])

    f = FollowUp(
        ticket = ticket,
        user = request.user,
        title = title,
        date = timezone.now(),
        public = True,
    )
    f.save()
    return HttpResponseRedirect(self.get_success_url())
Esempio n. 12
0
def followup_edit(request, ticket_id, followup_id):
    "Edit followup options with an ability to change the ticket."
    followup = get_object_or_404(FollowUp, id=followup_id)
    ticket = get_object_or_404(Ticket, id=ticket_id)
    if request.method == "GET":
        form = EditFollowUpForm(
            initial={
                "title": escape(followup.title),
                "ticket": followup.ticket,
                "comment": escape(followup.comment),
                "public": followup.public,
                "new_status": followup.new_status,
            }
        )

        return render_to_response(
            "helpdesk/followup_edit.html",
            RequestContext(request, {"followup": followup, "ticket": ticket, "form": form}),
        )
    elif request.method == "POST":
        form = EditFollowUpForm(request.POST)
        if form.is_valid():
            title = form.cleaned_data["title"]
            _ticket = form.cleaned_data["ticket"]
            comment = form.cleaned_data["comment"]
            public = form.cleaned_data["public"]
            new_status = form.cleaned_data["new_status"]
            # will save previous date
            old_date = followup.date
            new_followup = FollowUp(
                title=title, date=old_date, ticket=_ticket, comment=comment, public=public, new_status=new_status
            )
            # keep old user if one did exist before.
            if followup.user:
                new_followup.user = followup.user
            new_followup.save()
            # get list of old attachments & link them to new_followup
            attachments = Attachment.objects.filter(followup=followup)
            for attachment in attachments:
                attachment.followup = new_followup
                attachment.save()
            # delete old followup
            followup.delete()
        return HttpResponseRedirect(reverse("helpdesk_view", args=[ticket.id]))
Esempio n. 13
0
    def close(self, request, *args, **kwargs):
      if not self.object.assigned_to:
        owner = 0
      else:
        owner = self.object.assigned_to.id

      self.object.assigned_to_id = owner
      self.object.status = Ticket.CLOSED_STATUS
      self.object.save(update_fields=['status', 'assigned_to'])
      f = FollowUp(
        ticket_id=self.object.pk, 
        user_id = request.user.pk,
        date=timezone.now(), 
        new_status = self.object.status,
        comment = _('Accepted resolution and closed ticket'),
        title=_('Assigned to %s') % request.user.username,
        public = 1
      )
      f.save()
      return HttpResponseRedirect(self.get_success_url())
Esempio n. 14
0
 def record_reply_received(self, email):
     """
     Record a reply to this mail as a FollowUp to the Reply
     action.
     """
     queue = Queue.objects.get(pk=1)
     actions = self.action.filter(queue=queue)
     resolution = 'Reply received from %s on %s' % (email.fromParticipant, email.date)
     for action in actions:
         follow_up = FollowUp (
                               ticket=action,
                               date=datetime.now(),
                               comment=resolution,
                               title="Reply received",
                               public=True)
         follow_up.save()
         
         action.status = Ticket.CLOSED_STATUS
         action.resolution = follow_up.comment
         action.save()
Esempio n. 15
0
def hold_ticket(request, ticket_id, unhold=False):
    ticket = get_object_or_404(Ticket, id=ticket_id)

    if unhold:
        ticket.on_hold = False
        title = _('Ticket taken off hold')
    else:
        ticket.on_hold = True
        title = _('Ticket placed on hold')

    f = FollowUp(
        ticket=ticket,
        user=request.user,
        title=title,
        date=datetime.now(),
        public=True,
    )
    f.save()

    ticket.save()

    return HttpResponseRedirect(ticket.get_absolute_url())
Esempio n. 16
0
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,
    })
Esempio n. 17
0
def email_send(request):
  """
  Send an email. The post request should contain the necessary data for
  sending the mail as follows:
  subject: the subject of the email
  body: the body of the email
  to: the to address
  """
  body = request.POST['body']
  to = request.POST['to']
  subject = request.POST['subject']
  reply_to_id = request.POST['reply_to_id']
  message_id = email.utils.make_msgid()
  
  mail = EmailMessage(subject, body, '*****@*****.**',
                      [to],
                      headers = {'Message-ID': message_id, 'In-Reply-To': reply_to_id})
  mail.send()

  queue = Queue.objects.get(pk=1)
  if reply_to_id:
      replyTo = Message.objects.get(id = reply_to_id)
      actions = replyTo.action.filter(queue=queue)
      resolution = 'Reply sent on %s' % (datetime.now())
      for action in actions:
          follow_up = FollowUp (
                                ticket=action,
                                date=datetime.now(),
                                comment=resolution,
                                title="Reply sent",
                                public=False)
          follow_up.save()
            
          action.status = Ticket.RESOLVED_STATUS
          action.resolution = follow_up.comment
          action.save()
  
  return redirect("list_email_tickets")
Esempio n. 18
0
def get_issue_status(repo,ticket):

    repo = repo + "/issues/" + ticket.github_issue_number
    r = requests.get(repo)

    if int(r.status_code) == 200:
        data = json.loads(r.content)

        title = data['title']
        updated_date = data['updated_at']
        state = data['state']
        description = data['body']

        if state == 'closed':
            status = 4 # If 'Closed' in github, save as 'Closed' in TW
            state_txt = 'Closed'
        else:
            status = 1 #open
            state_txt = 'Open'

        # add a comment/explanation for the change of state in TW
        comments = '[GitHub Sync] Ticket is ' + str(state_txt) + ' in GitHub'

        update_ticket = Ticket.objects.get(id=ticket.id)
        current_status = update_ticket.status
        print 'Ticket#' + str(ticket.id) + str(comments)
        if not int(current_status) == int(status):
            new_followup = FollowUp(title=title, date=updated_date, ticket_id=ticket.id, comment=comments, public=1, new_status=status, )
            new_followup.save()

        update_ticket.status = status
        update_ticket.title =title
        update_ticket.description = description
        update_ticket.save()

    return r.status_code
    def get(self, request, *args, **kwargs):
        ticket = get_object_or_404(Ticket, id=self.kwargs['pk'])
        if not _has_access_to_queue(request.user, ticket.queue):
            raise PermissionDenied()

        if 'unhold' in self.kwargs.keys():
            ticket.on_hold = False
            title = _('Ticket taken off hold')
        else:
            ticket.on_hold = True
            title = _('Ticket placed on hold')

        f = FollowUp(
            ticket = ticket,
            user = request.user,
            title = title,
            date = timezone.now(),
            public = True,
        )
        f.save()

        ticket.save()

        return HttpResponseRedirect(ticket.get_staff_url())
Esempio n. 20
0
class TicketForm(forms.Form):

    queue = forms.ChoiceField(label=_('Queue'), required=True, choices=())

    title = forms.CharField(
        max_length=100,
        required=True,
        widget=forms.TextInput(attrs={'size': '60'}),
        label=_('Summary of the problem'),
    )

    submitter_email = forms.EmailField(
        required=False,
        label=_('Submitter E-Mail Address'),
        widget=forms.TextInput(attrs={'size': '60'}),
        help_text=_('This e-mail address will receive copies of all public '
                    'updates to this ticket.'),
    )

    error_msg = forms.CharField(
        widget=forms.Textarea(attrs={
            'cols': 47,
            'rows': 4
        }),
        label=_('Error Message'),
        required=False,
        help_text=
        _('Was an error message displaced? Please copy and paste this error message here. '
          ),
    )
    body = forms.CharField(
        widget=forms.Textarea(attrs={
            'cols': 47,
            'rows': 7
        }),
        label=_('Description of Issue'),
        required=True,
    )

    assigned_to = forms.ChoiceField(
        choices=(),
        required=False,
        label=_('Case owner'),
        help_text=_('If you select an owner other than yourself, they\'ll be '
                    'e-mailed details of this ticket immediately.'),
    )

    priority = forms.ChoiceField(
        choices=Ticket.PRIORITY_CHOICES,
        required=False,
        initial='3',
        label=_('Priority'),
        help_text=_('Please select a priority carefully. If unsure, leave it '
                    'as \'3\'.'),
    )

    type = forms.ChoiceField(
        choices=Ticket.TICKET_TYPE,
        required=True,
        initial='3',
        label=_('Type of Ticket'),
        help_text=_(
            'Enhancements requests or Bugs/Problems with Tola software.'),
    )

    due_date = forms.DateTimeField(
        widget=extras.SelectDateWidget,
        required=False,
        label=_('Due on'),
    )
    tags = forms.ModelMultipleChoiceField(
        queryset=Tag.objects.all(),
        widget=M2MSelect,
        required=False,
    )

    def clean_due_date(self):
        data = self.cleaned_data['due_date']
        #TODO: add Google calendar update hook
        #if not hasattr(self, 'instance') or self.instance.due_date != new_data:
        #    print "you changed!"
        return data

    def __init__(self, *args, **kwargs):
        """
        Add any custom fields that are defined to the form
        """
        super(TicketForm, self).__init__(*args, **kwargs)

        for field in CustomField.objects.all():
            instanceargs = {
                'label': field.label,
                'help_text': field.help_text,
                'required': field.required,
            }

            self.customfield_to_field(field, instanceargs)

    #Crispy Form Helper to add Bootstrap and layout
    helper = FormHelper()
    helper.form_method = 'post'
    helper.form_class = 'form-horizontal'
    helper.label_class = 'col-sm-3'
    helper.field_class = 'col-sm-8'
    helper.form_error_title = 'Form Errors'
    helper.error_text_inline = True
    helper.help_text_inline = True
    helper.html5_required = True
    helper.form_tag = False

    def save(self, user):
        """
        Writes and returns a Ticket() object
        """

        q = Queue.objects.get(id=int(self.cleaned_data['queue']))
        q = Queue.objects.get(id=int(self.cleaned_data['queue']))
        org = Organization.objects.get(id=1)

        t = Ticket(title=self.cleaned_data['title'],
                   submitter_email=self.cleaned_data['submitter_email'],
                   created=timezone.now(),
                   status=Ticket.OPEN_STATUS,
                   queue=q,
                   organization=org,
                   description=self.cleaned_data['body'],
                   error_msg=self.cleaned_data['error_msg'],
                   priority=self.cleaned_data['priority'],
                   type=self.cleaned_data['type'],
                   due_date=self.cleaned_data['due_date'])

        t.assigned_to = None

        if self.cleaned_data['assigned_to']:
            try:
                u = User.objects.get(id=self.cleaned_data['assigned_to'])
                t.assigned_to = u
            except User.DoesNotExist:
                pass
        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()

        ticket = t
        user = None
        try:
            user = t.assigned_to
        except Exception, e:
            pass

        f = FollowUp(
            ticket=ticket,
            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()

        context = safe_template_context(t)
        context['comment'] = f.comment

        #send email notifications for new ticket
        messages_sent_to = []

        if t.submitter_email:
            email(t, t.description, "NEW", t.submitter_email)
            messages_sent_to.append(t.submitter_email)

        try:
            if t.assigned_to and t.assigned_to != user and t.assigned_to.email and t.assigned_to.email not in messages_sent_to:
                email(t, t.description, "NEW", t.assigned_to.email)
                messages_sent_to.append(t.assigned_to.email)

        except Exception, e:
            pass
Esempio n. 21
0
    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
Esempio n. 22
0
def mass_update(request):
    tickets = request.POST.getlist("ticket_id")
    action = request.POST.get("action", None)
    if not (tickets and action):
        return HttpResponseRedirect(reverse("helpdesk_list"))

    if action.startswith("assign_"):
        parts = action.split("_")
        user = User.objects.get(id=parts[1])
        action = "assign"
    elif action == "take":
        user = request.user
        action = "assign"

    for t in Ticket.objects.filter(id__in=tickets):
        if action == "assign" and t.assigned_to != user:
            t.assigned_to = user
            t.save()
            f = FollowUp(
                ticket=t,
                date=datetime.now(),
                title=_("Assigned to %(username)s in bulk update" % {"username": user.username}),
                public=True,
                user=request.user,
            )
            f.save()
        elif action == "unassign" and t.assigned_to is not None:
            t.assigned_to = None
            t.save()
            f = FollowUp(
                ticket=t, date=datetime.now(), title=_("Unassigned in bulk update"), public=True, user=request.user
            )
            f.save()
        elif action == "close" and t.status != Ticket.CLOSED_STATUS:
            t.status = Ticket.CLOSED_STATUS
            t.save()
            f = FollowUp(
                ticket=t,
                date=datetime.now(),
                title=_("Closed in bulk update"),
                public=False,
                user=request.user,
                new_status=Ticket.CLOSED_STATUS,
            )
            f.save()
        elif action == "close_public" and t.status != Ticket.CLOSED_STATUS:
            t.status = Ticket.CLOSED_STATUS
            t.save()
            f = FollowUp(
                ticket=t,
                date=datetime.now(),
                title=_("Closed in bulk update"),
                public=True,
                user=request.user,
                new_status=Ticket.CLOSED_STATUS,
            )
            f.save()
            # Send email to Submitter, Owner, Queue CC
            context = safe_template_context(t)
            context.update(resolution=t.resolution, queue=t.queue)

            messages_sent_to = []

            if t.submitter_email:
                send_templated_mail(
                    "closed_submitter",
                    context,
                    recipients=t.submitter_email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )
                messages_sent_to.append(t.submitter_email)

            for cc in t.ticketcc_set.all():
                if cc.email_address not in messages_sent_to:
                    send_templated_mail(
                        "closed_submitter",
                        context,
                        recipients=cc.email_address,
                        sender=t.queue.from_address,
                        fail_silently=True,
                    )
                    messages_sent_to.append(cc.email_address)

            if (
                t.assigned_to
                and request.user != t.assigned_to
                and t.assigned_to.email
                and t.assigned_to.email not in messages_sent_to
            ):
                send_templated_mail(
                    "closed_owner",
                    context,
                    recipients=t.assigned_to.email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )
                messages_sent_to.append(t.assigned_to.email)

            if t.queue.updated_ticket_cc and t.queue.updated_ticket_cc not in messages_sent_to:
                send_templated_mail(
                    "closed_cc",
                    context,
                    recipients=t.queue.updated_ticket_cc,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )

        elif action == "delete":
            t.delete()

    return HttpResponseRedirect(reverse("helpdesk_list"))
Esempio n. 23
0
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)
Esempio n. 24
0
def get_label(repo, ticket):

    repo = repo + "/issues/" + ticket.github_issue_number + "/labels"
    token = settings.GITHUB_AUTH_TOKEN
    header = {'Authorization': 'token %s' % token}

    r = requests.get(repo, headers=header)

    try:

        if int(r.status_code) == 200:
            data = json.loads(r.content)
            label_txt2 = ""
            label_txt = ""
            label_int = '0'
            labels = []
            label = ''

            for item in range(len(data)):
                labels.append(data[item]['name'])

            for l in labels:

                if "Tola-Work Ticket" in l:
                    pass

                elif "accepted" in l:
                    label_txt2 = ', accepted by QA Lead and moved into the Ready Queue'
                    label_int = '5'
                    label = l

                elif "Ready" in l:
                    label_txt2 = ', accepted by Developers and moved into the Ready Queue'
                    label_int = '1'
                    label = l

                elif "Working" in l:
                    label_txt2 = ' and Developers have started working on the Ticket'
                    label_int = '2'
                    label = l

                elif "In Dev" in l:
                    label_txt2 = ' and moved to Dev'
                    label_int = '3'
                    label = l

                elif "Done" in l:
                    label_txt2 = ' and its Done'
                    label_int = '4'
                    label = l

            print labels

            comments = '[Progress Update] Ticket ' + str(label_txt) + str(
                label_txt2)

            update_ticket = Ticket.objects.get(id=ticket.id)
            db_label = update_ticket.git_label

            if not int(db_label) == int(label_int):
                new_followup = FollowUp(
                    title=ticket.title,
                    ticket_id=ticket.id,
                    comment=comments,
                    public=1,
                )
                new_followup.save()

                update_ticket.git_label = label_int
                update_ticket.save()
    except Exception, e:
        pass
Esempio n. 25
0
    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
Esempio n. 26
0
def escalate_tickets(queues, verbose):
    """ Only include queues with escalation configured """
    queryset = Queue.objects.filter(escalate_days__isnull=False).exclude(
        escalate_days=0)
    if queues:
        queryset = queryset.filter(slug__in=queues)

    for q in queryset:
        last = date.today() - timedelta(days=q.escalate_days)
        today = date.today()
        workdate = last

        days = 0

        while workdate < today:
            if EscalationExclusion.objects.filter(date=workdate).count() == 0:
                days += 1
            workdate = workdate + timedelta(days=1)

        req_last_escl_date = date.today() - timedelta(days=days)

        if verbose:
            print("Processing: %s" % q)

        for t in q.ticket_set.filter(
                Q(status=Ticket.OPEN_STATUS)
                | Q(status=Ticket.REOPENED_STATUS)).exclude(priority=1).filter(
                    Q(on_hold__isnull=True) | Q(on_hold=False)).filter(
                        Q(last_escalation__lte=req_last_escl_date)
                        | Q(last_escalation__isnull=True,
                            created__lte=req_last_escl_date)):

            t.last_escalation = timezone.now()
            t.priority -= 1
            t.save()

            context = safe_template_context(t)

            if t.submitter_email:
                send_templated_mail(
                    'escalated_submitter',
                    context,
                    recipients=t.submitter_email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )

            if t.queue.updated_ticket_cc:
                send_templated_mail(
                    'escalated_cc',
                    context,
                    recipients=t.queue.updated_ticket_cc,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )

            if t.assigned_to:
                send_templated_mail(
                    'escalated_owner',
                    context,
                    recipients=t.assigned_to.email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )

            if verbose:
                print("  - Esclating %s from %s>%s" %
                      (t.ticket, t.priority + 1, t.priority))

            f = FollowUp(
                ticket=t,
                title='Ticket Escalated',
                date=timezone.now(),
                public=True,
                comment=_('Ticket escalated after %s days' % q.escalate_days),
            )
            f.save()

            tc = TicketChange(
                followup=f,
                field=_('Priority'),
                old_value=t.priority + 1,
                new_value=t.priority,
            )
            tc.save()
Esempio n. 27
0
    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
Esempio n. 28
0
    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
Esempio n. 29
0
def mass_update(request):
    tickets = request.POST.getlist('ticket_id')
    action = request.POST.get('action', None)
    if not (tickets and action):
        return HttpResponseRedirect(reverse('helpdesk_list'))

    if action.startswith('assign_'):
        parts = action.split('_')
        user = User.objects.get(id=parts[1])
        action = 'assign'
    elif action == 'take':
        user = request.user
        action = 'assign'

    for t in Ticket.objects.filter(id__in=tickets):
        if action == 'assign' and t.assigned_to != user:
            t.assigned_to = user
            t.save()
            f = FollowUp(ticket=t, date=datetime.now(), title=_('Assigned to %(username)s in bulk update' % {'username': user.username}), public=True, user=request.user)
            f.save()
        elif action == 'unassign' and t.assigned_to is not None:
            t.assigned_to = None
            t.save()
            f = FollowUp(ticket=t, date=datetime.now(), title=_('Unassigned in bulk update'), public=True, user=request.user)
            f.save()
        elif action == 'close' and t.status != Ticket.CLOSED_STATUS:
            t.status = Ticket.CLOSED_STATUS
            t.save()
            f = FollowUp(ticket=t, date=datetime.now(), title=_('Closed in bulk update'), public=False, user=request.user, new_status=Ticket.CLOSED_STATUS)
            f.save()
        elif action == 'close_public' and t.status != Ticket.CLOSED_STATUS:
            t.status = Ticket.CLOSED_STATUS
            t.save()
            f = FollowUp(ticket=t, date=datetime.now(), title=_('Closed in bulk update'), public=True, user=request.user, new_status=Ticket.CLOSED_STATUS)
            f.save()
            # Send email to Submitter, Owner, Queue CC
            context = {
                'ticket': t,
                'queue': t.queue,
                'resolution': t.resolution,
            }

            messages_sent_to = []

            if t.submitter_email:
                send_templated_mail(
                    'closed_submitter',
                    context,
                    recipients=t.submitter_email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                    )
                messages_sent_to.append(t.submitter_email)

            for cc in t.ticketcc_set.all():
                if cc.email_address not in messages_sent_to:
                    send_templated_mail(
                        'closed_submitter',
                        context,
                        recipients=cc.email_address,
                        sender=t.queue.from_address,
                        fail_silently=True,
                        )
                    messages_sent_to.append(cc.email_address)

            if t.assigned_to and request.user != t.assigned_to and t.assigned_to.email and t.assigned_to.email not in messages_sent_to:
                send_templated_mail(
                    'closed_owner',
                    context,
                    recipients=t.assigned_to.email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                    )
                messages_sent_to.append(t.assigned_to.email)

            if t.queue.updated_ticket_cc and t.queue.updated_ticket_cc not in messages_sent_to:
                send_templated_mail(
                    'closed_cc',
                    context,
                    recipients=t.queue.updated_ticket_cc,
                    sender=t.queue.from_address,
                    fail_silently=True,
                    )

        elif action == 'delete':
            t.delete()

    return HttpResponseRedirect(reverse('helpdesk_list'))
Esempio n. 30
0
    def api_public_add_followup(self):
        try:
            ticket = Ticket.objects.get(
                id=self.request.POST.get('ticket', False))
        except Ticket.DoesNotExist:
            return api_return(STATUS_ERROR, "Invalid ticket ID")

        message = self.request.POST.get('message', None)
        public = self.request.POST.get('public', 'n')

        if public not in ['y', 'n']:
            return api_return(STATUS_ERROR, "Invalid 'public' flag")

        if not message:
            return api_return(STATUS_ERROR, "Blank message")

        f = FollowUp(
            ticket=ticket,
            date=timezone.now(),
            comment=message,
            user=self.request.user,
            title='Comment Added',
        )

        if public:
            f.public = True

        f.save()

        context = safe_template_context(ticket)
        context['comment'] = f.comment

        messages_sent_to = []

        if public and ticket.submitter_email:
            send_templated_mail(
                'updated_submitter',
                context,
                recipients=ticket.submitter_email,
                sender=ticket.queue.from_address,
                fail_silently=True,
            )
            messages_sent_to.append(ticket.submitter_email)

        if public:
            for cc in ticket.ticketcc_set.all():
                if cc.email_address not in messages_sent_to:
                    send_templated_mail(
                        'updated_submitter',
                        context,
                        recipients=cc.email_address,
                        sender=ticket.queue.from_address,
                        fail_silently=True,
                    )
                    messages_sent_to.append(cc.email_address)

        if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
            send_templated_mail(
                'updated_cc',
                context,
                recipients=ticket.queue.updated_ticket_cc,
                sender=ticket.queue.from_address,
                fail_silently=True,
            )
            messages_sent_to.append(ticket.queue.updated_ticket_cc)

        if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(
                ticket.assigned_to.usersettings.settings,
                'email_on_ticket_apichange', False
        ) and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
            send_templated_mail(
                'updated_owner',
                context,
                recipients=ticket.assigned_to.email,
                sender=ticket.queue.from_address,
                fail_silently=True,
            )

        ticket.save()

        return api_return(STATUS_OK)
Esempio n. 31
0
    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):
        """
        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
Esempio n. 33
0
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
Esempio n. 34
0
    def api_public_resolve(self):
        try:
            ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
        except Ticket.DoesNotExist:
            return api_return(STATUS_ERROR, "Invalid ticket ID")

        resolution = self.request.POST.get('resolution', None)

        if not resolution:
            return api_return(STATUS_ERROR, "Blank resolution")

        f = FollowUp(
            ticket=ticket,
            date=datetime.now(),
            comment=resolution,
            user=self.request.user,
            title='Resolved',
            public=True,
            )
        f.save()

        context = {
            'ticket': ticket,
            'queue': ticket.queue,
            'resolution': f.comment,
        }

        subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
        
        messages_sent_to = []

        if ticket.submitter_email:
            send_templated_mail(
                'resolved_submitter',
                context,
                recipients=ticket.submitter_email,
                sender=ticket.queue.from_address,
                fail_silently=True,
                )
            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(
                        'resolved_submitter',
                        context,
                        recipients=cc.email_address,
                        sender=ticket.queue.from_address,
                        fail_silently=True,
                        )
                    messages_sent_to.append(cc.email_address)

        if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
            send_templated_mail(
                'resolved_cc',
                context,
                recipients=ticket.queue.updated_ticket_cc,
                sender=ticket.queue.from_address,
                fail_silently=True,
                )
            messages_sent_to.append(ticket.queue.updated_ticket_cc)

        if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(ticket.assigned_to.usersettings.settings, 'email_on_ticket_apichange', False) and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
            send_templated_mail(
                'resolved_resolved',
                context,
                recipients=ticket.assigned_to.email,
                sender=ticket.queue.from_address,
                fail_silently=True,
                )

        ticket.resoltuion = f.comment
        ticket.status = Ticket.RESOLVED_STATUS

        ticket.save()

        return api_return(STATUS_OK)
Esempio n. 35
0
    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
Esempio n. 36
0
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)

    
Esempio n. 37
0
    def api_public_add_followup(self):
        try:
            ticket = Ticket.objects.get(id=self.request.POST.get('ticket', False))
        except Ticket.DoesNotExist:
            return api_return(STATUS_ERROR, "Invalid ticket ID")

        message = self.request.POST.get('message', None)
        public = self.request.POST.get('public', 'n')

        if public not in ['y', 'n']:
            return api_return(STATUS_ERROR, "Invalid 'public' flag")

        if not message:
            return api_return(STATUS_ERROR, "Blank message")

        f = FollowUp(
            ticket=ticket,
            date=datetime.now(),
            comment=message,
            user=self.request.user,
            title='Comment Added',
            )

        if public:
            f.public = True

        f.save()

        context = {
            'ticket': ticket,
            'queue': ticket.queue,
            'comment': f.comment,
        }
        
        messages_sent_to = []

        if public and ticket.submitter_email:
            send_templated_mail(
                'updated_submitter',
                context,
                recipients=ticket.submitter_email,
                sender=ticket.queue.from_address,
                fail_silently=True,
                )
            messages_sent_to.append(ticket.submitter_email)

        if public:
            for cc in ticket.ticketcc_set.all():
                if cc.email_address not in messages_sent_to:
                    send_templated_mail(
                        'updated_submitter',
                        context,
                        recipients=cc.email_address,
                        sender=ticket.queue.from_address,
                        fail_silently=True,
                        )
                    messages_sent_to.append(cc.email_address)

        if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
            send_templated_mail(
                'updated_cc',
                context,
                recipients=ticket.queue.updated_ticket_cc,
                sender=ticket.queue.from_address,
                fail_silently=True,
                )
            messages_sent_to.append(ticket.queue.updated_ticket_cc)

        if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(ticket.assigned_to.usersettings.settings, 'email_on_ticket_apichange', False) and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
            send_templated_mail(
                'updated_owner',
                context,
                recipients=ticket.assigned_to.email,
                sender=ticket.queue.from_address,
                fail_silently=True,
                )

        ticket.save()

        return api_return(STATUS_OK)
Esempio n. 38
0
def mass_update(request):
    tickets = request.POST.getlist('ticket_id')
    action = request.POST.get('action', None)
    if not (tickets and action):
        return HttpResponseRedirect(reverse('helpdesk_list'))

    if action.startswith('assign_'):
        parts = action.split('_')
        user = User.objects.get(id=parts[1])
        action = 'assign'
    elif action == 'take':
        user = request.user
        action = 'assign'

    for t in Ticket.objects.filter(id__in=tickets):
        if action == 'assign' and t.assigned_to != user:
            t.assigned_to = user
            t.save()
            f = FollowUp(ticket=t,
                         date=datetime.now(),
                         title=_('Assigned to %(username)s in bulk update' %
                                 {'username': user.username}),
                         public=True,
                         user=request.user)
            f.save()
        elif action == 'unassign' and t.assigned_to is not None:
            t.assigned_to = None
            t.save()
            f = FollowUp(ticket=t,
                         date=datetime.now(),
                         title=_('Unassigned in bulk update'),
                         public=True,
                         user=request.user)
            f.save()
        elif action == 'close' and t.status != Ticket.CLOSED_STATUS:
            t.status = Ticket.CLOSED_STATUS
            t.save()
            f = FollowUp(ticket=t,
                         date=datetime.now(),
                         title=_('Closed in bulk update'),
                         public=False,
                         user=request.user,
                         new_status=Ticket.CLOSED_STATUS)
            f.save()
        elif action == 'close_public' and t.status != Ticket.CLOSED_STATUS:
            t.status = Ticket.CLOSED_STATUS
            t.save()
            f = FollowUp(ticket=t,
                         date=datetime.now(),
                         title=_('Closed in bulk update'),
                         public=True,
                         user=request.user,
                         new_status=Ticket.CLOSED_STATUS)
            f.save()
            # Send email to Submitter, Owner, Queue CC
            context = safe_template_context(t)
            context.update(
                resolution=t.resolution,
                queue=t.queue,
            )

            messages_sent_to = []

            if t.submitter_email:
                send_templated_mail(
                    'closed_submitter',
                    context,
                    recipients=t.submitter_email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )
                messages_sent_to.append(t.submitter_email)

            for cc in t.ticketcc_set.all():
                if cc.email_address not in messages_sent_to:
                    send_templated_mail(
                        'closed_submitter',
                        context,
                        recipients=cc.email_address,
                        sender=t.queue.from_address,
                        fail_silently=True,
                    )
                    messages_sent_to.append(cc.email_address)

            if t.assigned_to and request.user != t.assigned_to and t.assigned_to.email and t.assigned_to.email not in messages_sent_to:
                send_templated_mail(
                    'closed_owner',
                    context,
                    recipients=t.assigned_to.email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )
                messages_sent_to.append(t.assigned_to.email)

            if t.queue.updated_ticket_cc and t.queue.updated_ticket_cc not in messages_sent_to:
                send_templated_mail(
                    'closed_cc',
                    context,
                    recipients=t.queue.updated_ticket_cc,
                    sender=t.queue.from_address,
                    fail_silently=True,
                )

        elif action == 'delete':
            t.delete()

    return HttpResponseRedirect(reverse('helpdesk_list'))
Esempio n. 39
0
def create_object_from_email_message(message, ticket_id, payload, files,
                                     logger):

    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)
        except Ticket.DoesNotExist:
            ticket = None
        else:
            new = False
            # Check if the ticket has been merged to another ticket
            if ticket.merged_to:
                logger.info("Ticket has been merged to %s" %
                            ticket.merged_to.ticket)
                # Use the ticket in which it was merged to for next operations
                ticket = ticket.merged_to

    # New issue, create a new <Ticket> instance
    if ticket is None:
        if not settings.QUEUE_EMAIL_BOX_UPDATE_ONLY:
            ticket = Ticket.objects.create(
                title=payload['subject'],
                queue=queue,
                submitter_email=sender_email,
                created=now,
                description=payload['body'],
                priority=payload['priority'],
            )
            ticket.save()
            logger.debug("Created new ticket %s-%s" %
                         (ticket.queue.slug, ticket.id))

            new = True
            update = ''

    # Old issue being re-opened
    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()
    logger.debug("Created new FollowUp for Ticket")

    logger.info("[%s-%s] %s" % (
        ticket.queue.slug,
        ticket.id,
        ticket.title,
    ))

    attached = process_attachments(f, files)
    for att_file in attached:
        logger.info(
            "Attachment '%s' (with size %s) successfully added to ticket from email."
            % (att_file[0], att_file[1].size))

    context = safe_template_context(ticket)

    new_ticket_ccs = []
    new_ticket_ccs.append(create_ticket_cc(ticket, to_list + cc_list))

    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)

    # send mail to appropriate people now depending on what objects
    # were created and who was CC'd
    if new:
        ticket.send(
            {
                'submitter': ('newticket_submitter', context),
                'new_ticket_cc': ('newticket_cc', context),
                'ticket_cc': ('newticket_cc', context)
            },
            fail_silently=True,
            extra_headers={'In-Reply-To': message_id},
        )
    else:
        context.update(comment=f.comment)
        ticket.send(
            {
                'submitter': ('newticket_submitter', context),
                'assigned_to': ('updated_owner', context)
            },
            fail_silently=True,
            extra_headers={'In-Reply-To': message_id},
        )
        if queue.enable_notifications_on_email_events:
            ticket.send(
                {'ticket_cc': ('updated_cc', context)},
                fail_silently=True,
                extra_headers={'In-Reply-To': message_id},
            )

    return ticket
Esempio n. 40
0
def ticket_from_message(message, queue, logger):
    # 'message' must be an RFC822 formatted message.
    message = email.message_from_string(message) if six.PY3 else email.message_from_string(message.encode('utf-8'))
    subject = message.get('subject', _('Comment 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 = email.utils.parseaddr(sender)[1]

    cc = message.get_all('cc', None)
    if cc:
        # first, fixup the encoding if necessary
        cc = [decode_mail_headers(decodeUnknown(message.get_charset(), x)) for x in cc]
        # get_all checks if multiple CC headers, but individual emails may be comma separated too
        tempcc = []
        for hdr in cc:
            tempcc.extend(hdr.split(','))
        # use a set to ensure no duplicates
        cc = set([x.strip() for x in tempcc])

    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 + r"-(?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

    body = None
    counter = 0
    files = []

    for part in message.walk():
        if part.get_content_maintype() == 'multipart':
            continue

        name = part.get_param("name")
        if name:
            name = email.utils.collapse_rfc2231_value(name)

        if part.get_content_maintype() == 'text' and name is None:
            if part.get_content_subtype() == 'plain':
                body = EmailReplyParser.parse_reply(
                    decodeUnknown(part.get_content_charset(), part.get_payload(decode=True))
                )
                # workaround to get unicode text out rather than escaped text
                try:
                    body = body.encode('ascii').decode('unicode_escape')
                except UnicodeEncodeError:
                    body.encode('utf-8')
                logger.debug("Discovered plain text MIME part")
            else:
                files.append(
                    SimpleUploadedFile(_("email_html_body.html"), encoding.smart_bytes(part.get_payload()), 'text/html')
                )
                logger.debug("Discovered HTML MIME part")
        else:
            if not name:
                ext = mimetypes.guess_extension(part.get_content_type())
                name = "part-%i%s" % (counter, ext)
            payload = part.get_payload()
            if isinstance(payload, list):
                payload = payload.pop().as_string()
            payloadToWrite = payload
            # check version of python to ensure use of only the correct error type
            if six.PY2:
                non_b64_err = binascii.Error
            else:
                non_b64_err = TypeError
            try:
                logger.debug("Try to base64 decode the attachment payload")
                if six.PY2:
                    payloadToWrite = base64.decodestring(payload)
                else:
                    payloadToWrite = base64.decodebytes(payload)
            except non_b64_err:
                logger.debug("Payload was not base64 encoded, using raw bytes")
                payloadToWrite = payload
            files.append(SimpleUploadedFile(name, part.get_payload(decode=True), mimetypes.guess_type(name)[0]))
            logger.debug("Found MIME attachment %s" % name)

        counter += 1

    if not body:
        mail = BeautifulSoup(part.get_payload(), "lxml")
        if ">" in mail.text:
            body = mail.find('body')
            body = body.text
            body = body.encode('ascii', errors='ignore')
        else:
            body = mail.text

    if ticket:
        try:
            t = Ticket.objects.get(id=ticket)
        except Ticket.DoesNotExist:
            logger.info("Tracking ID %s-%s not associated with existing ticket. Creating new ticket." % (queue.slug, ticket))
            ticket = None
        else:
            logger.info("Found existing ticket with Tracking ID %s-%s" % (t.queue.slug, t.id))
            if t.status == Ticket.CLOSED_STATUS:
                t.status = Ticket.REOPENED_STATUS
                t.save()
            new = False

    smtp_priority = message.get('priority', '')
    smtp_importance = message.get('importance', '')
    high_priority_types = {'high', 'important', '1', 'urgent'}
    priority = 2 if high_priority_types & {smtp_priority, smtp_importance} else 3

    if ticket is None:
        if settings.QUEUE_EMAIL_BOX_UPDATE_ONLY:
            return None
        new = True
        t = Ticket.objects.create(
            title=subject,
            queue=queue,
            submitter_email=sender_email,
            created=timezone.now(),
            description=body,
            priority=priority,
        )
        logger.debug("Created new ticket %s-%s" % (t.queue.slug, t.id))

    if cc:
        # get list of currently CC'd emails
        current_cc = TicketCC.objects.filter(ticket=ticket)
        current_cc_emails = [x.email for x in current_cc if x.email]
        # get emails of any Users CC'd to email, if defined
        # (some Users may not have an associated email, e.g, when using LDAP)
        current_cc_users = [x.user.email for x in current_cc if x.user and x.user.email]
        # ensure submitter, assigned user, queue email not added
        other_emails = [queue.email_address]
        if t.submitter_email:
            other_emails.append(t.submitter_email)
        if t.assigned_to:
            other_emails.append(t.assigned_to.email)
        current_cc = set(current_cc_emails + current_cc_users + other_emails)
        # first, add any User not previously CC'd (as identified by User's email)
        all_users = User.objects.all()
        all_user_emails = set([x.email for x in all_users])
        users_not_currently_ccd = all_user_emails.difference(set(current_cc))
        users_to_cc = cc.intersection(users_not_currently_ccd)
        for user in users_to_cc:
            tcc = TicketCC.objects.create(
                ticket=t,
                user=User.objects.get(email=user),
                can_view=True,
                can_update=False
            )
            tcc.save()
        # then add remaining emails alphabetically, makes testing easy
        new_cc = cc.difference(current_cc).difference(all_user_emails)
        new_cc = sorted(list(new_cc))
        for ccemail in new_cc:
            tcc = TicketCC.objects.create(
                ticket=t,
                email=ccemail.replace('\n', ' ').replace('\r', ' '),
                can_view=True,
                can_update=False
            )
            tcc.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,))

    attached = process_attachments(f, files)
    for att_file in attached:
        logger.info("Attachment '%s' (with size %s) successfully added to ticket from email." % (att_file[0], att_file[1].size))

    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.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
Esempio n. 41
0
    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
Esempio n. 42
0
def ticket_from_message(message, queue, logger):
    # 'message' must be an RFC822 formatted message.
    message = email.message_from_string(
        message) if six.PY3 else email.message_from_string(
            message.encode('utf-8'))
    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 = email.utils.parseaddr(sender)[1]

    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

    body = None
    counter = 0
    files = []

    for part in message.walk():
        if part.get_content_maintype() == 'multipart':
            continue

        name = part.get_param("name")
        if name:
            name = email.utils.collapse_rfc2231_value(name)

        if part.get_content_maintype() == 'text' and name is None:
            if part.get_content_subtype() == 'plain':
                body = EmailReplyParser.parse_reply(
                    decodeUnknown(part.get_content_charset(),
                                  part.get_payload(decode=True)))
                # workaround to get unicode text out rather than escaped text
                body = body.encode('ascii').decode(
                    'unicode_escape') if six.PY3 else body.encode('utf-8')
                logger.debug("Discovered plain text MIME part")
            else:
                files.append(
                    SimpleUploadedFile(
                        _("email_html_body.html"),
                        encoding.smart_bytes(part.get_payload()), 'text/html'))
                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(
                SimpleUploadedFile(name,
                                   encoding.smart_bytes(part.get_payload()),
                                   part.get_content_type()))
            logger.debug("Found MIME attachment %s" % name)

        counter += 1

    if not body:
        body = _(
            'No plain-text email body available. Please see attachment "email_html_body.html".'
        )

    if ticket:
        try:
            t = Ticket.objects.get(id=ticket)
        except Ticket.DoesNotExist:
            logger.info(
                "Tracking ID %s-%s not associated with existing ticket. Creating new ticket."
                % (queue.slug, ticket))
            ticket = None
        else:
            logger.info("Found existing ticket with Tracking ID %s-%s" %
                        (t.queue.slug, t.id))
            if t.status == Ticket.CLOSED_STATUS:
                t.status = Ticket.REOPENED_STATUS
                t.save()
            new = False

    smtp_priority = message.get('priority', '')
    smtp_importance = message.get('importance', '')
    high_priority_types = {'high', 'important', '1', 'urgent'}
    priority = 2 if high_priority_types & {smtp_priority, smtp_importance
                                           } else 3

    if ticket is None:
        new = True
        t = Ticket.objects.create(
            title=subject,
            queue=queue,
            submitter_email=sender_email,
            created=timezone.now(),
            description=body,
            priority=priority,
        )
        logger.debug("Created new ticket %s-%s" % (t.queue.slug, t.id))

    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,
        ))

    attached = process_attachments(f, files)
    for att_file in attached:
        logger.info(
            "Attachment '%s' successfully added to ticket from email." %
            att_file[0])

    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.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
Esempio n. 43
0
def ticket_from_message(message, queue, logger):
    # 'message' must be an RFC822 formatted message.
    message = email.message_from_string(message)
    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 = email.utils.parseaddr(sender)[1]

    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

    body = None
    counter = 0
    files = []

    for part in message.walk():
        if part.get_content_maintype() == 'multipart':
            continue

        name = part.get_param("name")
        if name:
            name = email.utils.collapse_rfc2231_value(name)

        if part.get_content_maintype() == 'text' and name is None:
            if part.get_content_subtype() == 'plain':
                body = EmailReplyParser.parse_reply(
                    decodeUnknown(part.get_content_charset(), part.get_payload(decode=True))
                )
                logger.debug("Discovered plain text MIME part")
            else:
                files.append(
                    SimpleUploadedFile(_("email_html_body.html"), encoding.smart_bytes(part.get_payload()), 'text/html')
                )
                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(SimpleUploadedFile(name, encoding.smart_bytes(part.get_payload()), part.get_content_type()))
            logger.debug("Found MIME attachment %s" % name)

        counter += 1

    if not body:
        body = _('No plain-text email body available. Please see attachment "email_html_body.html".')

    if ticket:
        try:
            t = Ticket.objects.get(id=ticket)
        except Ticket.DoesNotExist:
            logger.info("Tracking ID %s-%s not associated with existing ticket. Creating new ticket." % (queue.slug, ticket))
            ticket = None
        else:
            logger.info("Found existing ticket with Tracking ID %s-%s" % (t.queue.slug, t.id))
            if t.status == Ticket.CLOSED_STATUS:
                t.status = Ticket.REOPENED_STATUS
                t.save()
            new = False

    smtp_priority = message.get('priority', '')
    smtp_importance = message.get('importance', '')
    high_priority_types = {'high', 'important', '1', 'urgent'}
    priority = 2 if high_priority_types & {smtp_priority, smtp_importance} else 3

    if ticket is None:
        new = True
        t = Ticket.objects.create(
            title=subject,
            queue=queue,
            submitter_email=sender_email,
            created=timezone.now(),
            description=body,
            priority=priority,
        )
        logger.debug("Created new ticket %s-%s" % (t.queue.slug, t.id))

    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,))

    attached = process_attachments(f, files)
    for att_file in attached:
        logger.info("Attachment '%s' successfully added to ticket from email." % att_file[0])

    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.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
Esempio n. 44
0
    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
Esempio n. 45
0
    def api_public_resolve(self):
        try:
            ticket = Ticket.objects.get(
                id=self.request.POST.get('ticket', False))
        except Ticket.DoesNotExist:
            return api_return(STATUS_ERROR, "Invalid ticket ID")

        resolution = self.request.POST.get('resolution', None)

        if not resolution:
            return api_return(STATUS_ERROR, "Blank resolution")

        f = FollowUp(
            ticket=ticket,
            date=timezone.now(),
            comment=resolution,
            user=self.request.user,
            title='Resolved',
            public=True,
        )
        f.save()

        context = safe_template_context(ticket)
        context['resolution'] = f.comment

        subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)

        messages_sent_to = []

        if ticket.submitter_email:
            send_templated_mail(
                'resolved_submitter',
                context,
                recipients=ticket.submitter_email,
                sender=ticket.queue.from_address,
                fail_silently=True,
            )
            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(
                        'resolved_submitter',
                        context,
                        recipients=cc.email_address,
                        sender=ticket.queue.from_address,
                        fail_silently=True,
                    )
                    messages_sent_to.append(cc.email_address)

        if ticket.queue.updated_ticket_cc and ticket.queue.updated_ticket_cc not in messages_sent_to:
            send_templated_mail(
                'resolved_cc',
                context,
                recipients=ticket.queue.updated_ticket_cc,
                sender=ticket.queue.from_address,
                fail_silently=True,
            )
            messages_sent_to.append(ticket.queue.updated_ticket_cc)

        if ticket.assigned_to and self.request.user != ticket.assigned_to and getattr(
                ticket.assigned_to.usersettings.settings,
                'email_on_ticket_apichange', False
        ) and ticket.assigned_to.email and ticket.assigned_to.email not in messages_sent_to:
            send_templated_mail(
                'resolved_resolved',
                context,
                recipients=ticket.assigned_to.email,
                sender=ticket.queue.from_address,
                fail_silently=True,
            )

        ticket.resoltuion = f.comment
        ticket.status = Ticket.RESOLVED_STATUS

        ticket.save()

        return api_return(STATUS_OK)
Esempio n. 46
0
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)
Esempio n. 47
0
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)
Esempio n. 48
0
    def save(self):
        """
        Writes and returns a Ticket() object
        """

        q = Queue.objects.get(title = 'public')

        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 = 3,
            due_date = 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 Via Web'),
            date = timezone.now(),
            public = True,
            comment = self.cleaned_data['body'],
            )

        f.save()
        files = []

        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
Esempio n. 49
0
    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
Esempio n. 50
0
def escalate_tickets(queues, verbose):
    """ Only include queues with escalation configured """
    queryset = Queue.objects.filter(escalate_days__isnull=False).exclude(escalate_days=0)
    if queues:
        queryset = queryset.filter(slug__in=queues)

    for q in queryset:
        last = date.today() - timedelta(days=q.escalate_days)
        today = date.today()
        workdate = last

        days = 0

        while workdate < today:
            if EscalationExclusion.objects.filter(date=workdate).count() == 0:
                days += 1
            workdate = workdate + timedelta(days=1)


        req_last_escl_date = date.today() - timedelta(days=days)

        if verbose:
            print "Processing: %s" % q

        for t in q.ticket_set.filter(
                  Q(status=Ticket.OPEN_STATUS)
                | Q(status=Ticket.REOPENED_STATUS)
            ).exclude(
                priority=1
            ).filter(
                  Q(on_hold__isnull=True)
                | Q(on_hold=False)
            ).filter(
                  Q(last_escalation__lte=req_last_escl_date)
                | Q(last_escalation__isnull=True, created__lte=req_last_escl_date)
            ):

            t.last_escalation = timezone.now()
            t.priority -= 1
            t.save()

            context = safe_template_context(t)

            if t.submitter_email:
                send_templated_mail(
                    'escalated_submitter',
                    context,
                    recipients=t.submitter_email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                    )

            if t.queue.updated_ticket_cc:
                send_templated_mail(
                    'escalated_cc',
                    context,
                    recipients=t.queue.updated_ticket_cc,
                    sender=t.queue.from_address,
                    fail_silently=True,
                    )

            if t.assigned_to:
                send_templated_mail(
                    'escalated_owner',
                    context,
                    recipients=t.assigned_to.email,
                    sender=t.queue.from_address,
                    fail_silently=True,
                    )

            if verbose:
                print "  - Esclating %s from %s>%s" % (
                    t.ticket,
                    t.priority+1,
                    t.priority
                    )

            f = FollowUp(
                ticket = t,
                title = 'Ticket Escalated',
                date=timezone.now(),
                public=True,
                comment=_('Ticket escalated after %s days' % q.escalate_days),
            )
            f.save()

            tc = TicketChange(
                followup = f,
                field = _('Priority'),
                old_value = t.priority + 1,
                new_value = t.priority,
            )
            tc.save()
Esempio n. 51
0
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
Esempio n. 52
0
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)