Ejemplo n.º 1
0
def reports(request):
    if 'report' in request.GET:
        rep = tickets_reports.objects.get(pk=request.GET['report'])
        add_breadcrumbs(request,
                        request.GET['report'],
                        '@',
                        caption=rep.name[:20])
        request.session['last_search'] = json.loads(rep.search)
        return HttpResponseRedirect('/tickets/search/?report=%s' %
                                    request.GET['report'])

    if 'delReport' in request.GET:
        tickets_reports.objects.get(
            c_user=request.user,
            pk=request.GET['delReport']).delete(user=request.user)
        return HttpResponseRedirect('/reports/')

    reps = tickets_reports.objects.filter(active_record=True,
                                          c_user=request.user).order_by('name')

    paginator = Paginator(reps, 10)
    page = request.GET.get('page')
    try:
        rep_lines = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        rep_lines = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        rep_lines = paginator.page(paginator.num_pages)

    return render(request, 'tickets/reports.html', {'lines': rep_lines})
Ejemplo n.º 2
0
def reports(request):
    if 'report' in request.GET:
        rep = tickets_reports.objects.get(pk=request.GET['report'])
        add_breadcrumbs(request, request.GET['report'], '@', caption=rep.name[:20])
        request.session['last_search'] = json.loads(rep.search)
        return HttpResponseRedirect('/tickets/search/?report=%s' % request.GET['report'])

    if 'delReport' in request.GET:
        tickets_reports.objects.get(c_user=request.user, pk=request.GET['delReport']).delete(user=request.user)
        return HttpResponseRedirect('/reports/')

    reps = tickets_reports.objects.filter(active_record=True, c_user=request.user).order_by('name')

    paginator = Paginator(reps, 10)
    page = request.GET.get('page')
    try:
        rep_lines = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        rep_lines = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        rep_lines = paginator.page(paginator.num_pages)

    return render(request, 'tickets/reports.html', {'lines': rep_lines})
Ejemplo n.º 3
0
def kanban(request):
    flows = ticket_flow.objects.all().order_by('type')
    columns = []
    finish_state = -1
    days = UserProfile.objects.get(user=request.user).day_since_closed_tickets

    query = get_ticket_model().objects.select_related('type', 'state', 'assigned', 'priority', 'customer').all()

    for flow in flows:
        search_params, flow.data = build_ticket_search_ext(request, query, convert_sarch({'state': flow.pk}))
        flow.data = flow.data.filter(Q(show_start=None) | Q(show_start__lte=timezone.now()))

        if flow.type == 2:
            flow.data = flow.data.filter(Q(assigned=None) | Q(assigned=request.user)).order_by('-close_date')
        else:
            flow.data = flow.data.filter(Q(assigned=None) | Q(assigned=request.user)).extra(select={'prio': 'COALESCE(caldav, 10)'}, order_by=['prio', '-c_date'])

        if flow.type == 1:
            columns.insert(0, flow)
        else:
            columns.append(flow)
            if flow.type == 2:
                finish_state = flow.pk
                flow.data = flow.data.filter(close_date__gte=datetime.date.today() - datetime.timedelta(days=days))

        seen_elements = {}
        seen = tickets_participants.objects.filter(user=request.user, ticket__in=flow.data.values_list('id', flat=True)).values_list('ticket_id', 'seen')
        for see in seen:
            seen_elements[see[0]] = see[1]

        seen = tickets_ignorants.objects.filter(user=request.user, ticket__in=flow.data.values_list('id', flat=True)).values_list('ticket_id')
        for see in seen:
            seen_elements[see[0]] = True

        flow.seen = seen_elements

    close = TicketCloseForm()
    reassign = TicketReassignForm()
    edges = ticket_flow_edges.objects.all().order_by('now')
    add_breadcrumbs(request, 0, 'k')
    cur_language = translation.get_language()
    return render(request, 'board/kanban.html', {'layout': 'horizontal', 'columns': columns, 'edges': edges, 'finish_state': finish_state, 'close': close, 'reassign': reassign, 'cur_language': cur_language})
Ejemplo n.º 4
0
def docs_action(request, mode, docid):
    doc = docs.objects.get(pk=docid)
    if mode == 'view':
        form = DocsForm(user=request.user, instance=doc, view_only=True)
        add_breadcrumbs(request, docid, '*', caption=doc.caption[:20])
        return render(request, 'docs/view.html', {'layout': 'horizontal', 'form': form, 'doc': doc})

    elif mode == 'edit':
        if request.method == 'POST':
            form = DocsForm(request.POST, user=request.user, instance=doc)
            if form.is_valid():
                doc = form.save()
                return HttpResponseRedirect('/docs/view/%s/' % doc.pk)

        form = DocsForm(user=request.user, instance=doc)
        return render(request, 'docs/edit.html', {'layout': 'horizontal', 'form': form, 'doc': doc})

    elif mode == 'delete':
        doc.delete(user=request.user)
        return HttpResponseRedirect('/search/?q=%s&models=yats.docs&models=web.test' % request.session.get('last_fulltextsearch', '*'))
Ejemplo n.º 5
0
def action(request, mode, ticket):
    mod_path, cls_name = settings.TICKET_CLASS.rsplit('.', 1)
    mod_path = mod_path.split('.').pop(0)
    tic = apps.get_model(mod_path, cls_name).objects.get(pk=ticket)

    if hasattr(settings, 'KEEP_IT_SIMPLE') and settings.KEEP_IT_SIMPLE:
        keep_it_simple = True
    else:
        keep_it_simple = False

    if mode == 'view':
        if request.method == 'POST':
            form = CommentForm(request.POST)
            if form.is_valid():
                com = tickets_comments()
                com.comment = form.cleaned_data['comment']
                com.ticket_id = ticket
                com.action = 6
                com.save(user=request.user)

                check_references(request, com)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 6, com.comment)

                mail_comment(request, com.pk)
                jabber_comment(request, com.pk)

            else:
                if 'resolution' in request.POST:
                    if request.POST['resolution'] and int(
                            request.POST['resolution']) > 0:
                        tic.resolution_id = request.POST['resolution']
                        tic.closed = True
                        tic.close_date = timezone.now()
                        tic.state = get_flow_end()
                        tic.save(user=request.user)

                        com = tickets_comments()
                        com.comment = _(
                            'ticket closed - resolution: %(resolution)s\n\n%(comment)s'
                        ) % {
                            'resolution':
                            ticket_resolution.objects.get(
                                pk=request.POST['resolution']).name,
                            'comment':
                            request.POST.get('close_comment', '')
                        }
                        com.ticket_id = ticket
                        com.action = 1
                        com.save(user=request.user)

                        check_references(request, com)

                        touch_ticket(request.user, ticket)

                        add_history(request, tic, 1,
                                    request.POST.get('close_comment', ''))

                        mail_comment(request, com.pk)
                        jabber_comment(request, com.pk)

                    else:
                        messages.add_message(request, messages.ERROR,
                                             _('no resolution selected'))

                else:
                    messages.add_message(request, messages.ERROR,
                                         _('comment invalid'))

            # reload ticket => last_action date has changed
            tic = apps.get_model(mod_path, cls_name).objects.get(pk=ticket)

        excludes = []
        form = TicketsForm(exclude_list=excludes,
                           is_stuff=request.user.is_staff,
                           user=request.user,
                           instance=tic,
                           customer=request.organisation.id,
                           view_only=True)
        close = TicketCloseForm()
        reassign = TicketReassignForm(initial={
            'assigned': tic.assigned_id,
            'state': tic.state
        })
        flows = list(
            ticket_flow_edges.objects.select_related('next').filter(
                now=tic.state).exclude(next__type=2).values_list('next',
                                                                 flat=True))
        flows.append(tic.state_id)
        reassign.fields['state'].queryset = reassign.fields[
            'state'].queryset.filter(id__in=flows)

        participants = tickets_participants.objects.select_related(
            'user').filter(ticket=ticket)
        comments = tickets_comments.objects.select_related('c_user').filter(
            ticket=ticket).order_by('c_date')

        close_allowed = ticket_flow_edges.objects.select_related(
            'next').filter(now=tic.state, next__type=2).count() > 0

        files = tickets_files.objects.filter(ticket=ticket, active_record=True)
        paginator = Paginator(files, 10)
        page = request.GET.get('page')
        try:
            files_lines = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            files_lines = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            files_lines = paginator.page(paginator.num_pages)

        add_breadcrumbs(request, ticket, '#', caption=tic.caption[:20])
        if 'YATSE' in request.GET and 'isUsingYATSE' not in request.session:
            request.session['isUsingYATSE'] = True

        return render(
            request, 'tickets/view.html', {
                'layout':
                'horizontal',
                'ticket':
                tic,
                'form':
                form,
                'close':
                close,
                'reassign':
                reassign,
                'files':
                files_lines,
                'comments':
                comments,
                'participants':
                participants,
                'close_allowed':
                close_allowed,
                'keep_it_simple':
                keep_it_simple,
                'last_action_date':
                http_date(time.mktime(tic.last_action_date.timetuple()))
            })

    elif mode == 'gallery':
        images = tickets_files.objects.filter(ticket=ticket,
                                              active_record=True)
        return render(request, 'tickets/gallery.html', {
            'layout': 'horizontal',
            'ticket': tic,
            'images': images
        })

    elif mode == 'history':
        history = tickets_history.objects.filter(ticket=ticket)
        return render(
            request, 'tickets/history.html', {
                'layout': 'horizontal',
                'ticket': tic,
                'history': history,
                'keep_it_simple': keep_it_simple
            })

    elif mode == 'reopen':
        if tic.closed:
            tic.closed = False
            tic.state = get_flow_start()
            tic.resolution = None
            tic.close_date = None
            tic.save(user=request.user)

            com = tickets_comments()
            com.comment = _('ticket reopend - resolution deleted')
            com.ticket_id = ticket
            com.action = 2
            com.save(user=request.user)

            check_references(request, com)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 2, None)

            mail_comment(request, com.pk)
            jabber_comment(request, com.pk)

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'move':
        if not tic.closed:
            old_state = tic.state

            tic.state = ticket_flow.objects.get(pk=request.POST['state'])
            tic.save(user=request.user)

            touch_ticket(request.user, ticket)

            oldUser = str(User.objects.get(
                pk=tic.assigned_id)) if tic.assigned_id else None

            history_data = {
                'old': {
                    'comment': '',
                    'assigned': oldUser,
                    'state': str(old_state)
                },
                'new': {
                    'comment': _('ticket moved'),
                    'assigned': oldUser,
                    'state': str(tic.state)
                }
            }
            add_history(request, tic, 7, history_data)

        return HttpResponse('OK')

    elif mode == 'reassign':
        if not tic.closed:
            if 'assigned' in request.POST:
                if request.POST['assigned'] and int(
                        request.POST['assigned']) > 0:
                    old_assigned_user = tic.assigned
                    old_state = tic.state

                    tic.assigned_id = request.POST['assigned']
                    tic.state = ticket_flow.objects.get(
                        pk=request.POST['state'])
                    tic.save(user=request.user)

                    newUser = User.objects.get(pk=request.POST['assigned'])

                    com = tickets_comments()
                    com.comment = _(
                        'ticket reassigned to %(user)s\nstate now: %(state)s\n\n%(comment)s'
                    ) % {
                        'user': newUser,
                        'comment': request.POST.get('reassign_comment', ''),
                        'state': tic.state
                    }
                    com.ticket_id = ticket
                    com.action = 7
                    com.save(user=request.user)

                    check_references(request, com)

                    touch_ticket(request.user, ticket)
                    if request.POST['assigned']:
                        touch_ticket(newUser, ticket)

                    mail_comment(request, com.pk)
                    jabber_comment(request, com.pk)

                    history_data = {
                        'old': {
                            'comment': '',
                            'assigned': str(old_assigned_user),
                            'state': str(old_state)
                        },
                        'new': {
                            'comment':
                            request.POST.get('reassign_comment', ''),
                            'assigned':
                            str(User.objects.get(pk=request.POST['assigned'])),
                            'state':
                            str(tic.state)
                        }
                    }
                    add_history(request, tic, 7, history_data)

                else:
                    messages.add_message(request, messages.ERROR,
                                         _('missing assigned user'))

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'edit' or (mode == 'simple' and
                            (not tic.keep_it_simple or tic.closed)
                            and keep_it_simple):
        excludes = ['resolution']
        if request.method == 'POST':
            form = TicketsForm(request.POST,
                               exclude_list=excludes,
                               is_stuff=request.user.is_staff,
                               user=request.user,
                               instance=tic,
                               customer=request.organisation.id)
            if form.is_valid():
                tic = form.save()

                if tic.keep_it_simple:
                    tic.keep_it_simple = False
                    tic.save(user=request.user)

                assigned = form.cleaned_data.get('assigned')
                if assigned:
                    touch_ticket(assigned, tic.pk)

                mail_ticket(request, tic.pk, form)
                jabber_ticket(request, tic.pk, form)

                remember_changes(request, form, tic)

                touch_ticket(request.user, tic.pk)

                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        else:
            form = TicketsForm(exclude_list=excludes,
                               is_stuff=request.user.is_staff,
                               user=request.user,
                               instance=tic,
                               customer=request.organisation.id)
        if 'state' in form.fields:
            form.fields['state'].queryset = form.fields[
                'state'].queryset.exclude(type=2)
        return render(request, 'tickets/edit.html', {
            'ticket': tic,
            'layout': 'horizontal',
            'form': form
        })

    elif mode == 'simple':
        if request.method == 'POST':
            form = SimpleTickets(request.POST,
                                 initial={
                                     'caption': tic.caption,
                                     'description': tic.description,
                                     'priority': tic.priority,
                                     'assigned': tic.assigned
                                 })
            if form.is_valid():
                cd = form.cleaned_data
                tic.caption = cd['caption']
                tic.description = cd['description'].replace(u"\u00A0", " ")
                tic.priority = cd['priority']
                tic.assigned = cd['assigned']
                tic.deadline = cd['deadline']
                tic.show_start = cd['show_start']
                tic.component = cd['component']
                tic.save(user=request.user)

                if cd['assigned']:
                    touch_ticket(cd['assigned'], tic.pk)

                remember_changes(request, form, tic)

                touch_ticket(request.user, tic.pk)

                mail_ticket(request, tic.pk, form)
                jabber_ticket(request, tic.pk, form)

                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        else:
            form = SimpleTickets(
                initial={
                    'caption': tic.caption,
                    'description': tic.description,
                    'priority': tic.priority,
                    'assigned': tic.assigned,
                    'deadline': tic.deadline,
                    'show_start': tic.show_start,
                    'component': tic.component,
                })
        return render(request, 'tickets/edit.html', {
            'ticket': tic,
            'layout': 'horizontal',
            'form': form,
            'mode': mode
        })

    elif mode == 'download':
        fileid = request.GET.get('file', -1)
        file_data = tickets_files.objects.get(id=fileid, ticket=ticket)
        src = '%s%s.dat' % (settings.FILE_UPLOAD_PATH, fileid)
        content_type = file_data.content_type
        if request.GET.get('preview') == 'yes' and os.path.isfile(
                '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)):
            src = '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)
            content_type = 'imgae/png'

        if request.GET.get(
                'resize',
                'no') == 'yes' and ('image' in file_data.content_type
                                    or 'pdf' in file_data.content_type):
            img = resize_image('%s' % (src), (200, 150), 75)
            output = io.BytesIO()
            img.save(output, 'PNG')
            output.seek(0)
            response = StreamingHttpResponse(output, content_type='image/png')

        else:
            response = StreamingHttpResponse(open('%s' % (src), "rb"),
                                             content_type=content_type)

        if 'noDisposition' not in request.GET:
            if request.GET.get('preview') == 'yes' and os.path.isfile(
                    '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)):
                response[
                    'Content-Disposition'] = 'attachment;filename="%s"' % content_type
            else:
                response[
                    'Content-Disposition'] = 'attachment;filename="%s"' % smart_str(
                        file_data.name)
        return response

    elif mode == 'upload':
        if request.method == 'POST':
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                if tickets_files.objects.filter(
                        active_record=True,
                        ticket=ticket,
                        checksum=request.FILES['file'].hash).count() > 0:
                    messages.add_message(
                        request, messages.ERROR,
                        _('File already exists: %s') %
                        request.FILES['file'].name)
                    if request.GET.get('Ajax') == '1':
                        return HttpResponse('OK')
                    return HttpResponseRedirect('/tickets/view/%s/' % ticket)
                f = tickets_files()
                f.name = request.FILES['file'].name
                f.size = request.FILES['file'].size
                f.checksum = request.FILES['file'].hash
                f.content_type = request.FILES['file'].content_type
                f.ticket_id = ticket
                f.public = True
                f.save(user=request.user)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 5, request.FILES['file'].name)

                mail_file(request, f.pk)
                jabber_file(request, f.pk)

                dest = settings.FILE_UPLOAD_PATH
                if not os.path.exists(dest):
                    os.makedirs(dest)

                with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                    for chunk in request.FILES['file'].chunks():
                        destination.write(chunk)

                if 'pdf' in f.content_type:
                    convertPDFtoImg('%s/%s.dat' % (dest, f.id),
                                    '%s/%s.preview' % (dest, f.id))
                else:
                    if 'image' not in f.content_type and isPreviewable(
                            f.content_type):
                        tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id))
                        convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id))
                        if os.path.isfile(tmp):
                            os.unlink(tmp)

                return HttpResponseRedirect('/tickets/view/%s/' % tic.pk)

            else:
                msg = unicode(form.errors['file'])
                msg = re.sub('<[^<]+?>', '', msg)
                messages.add_message(request, messages.ERROR, msg)
                if request.GET.get('Ajax') == '1':
                    return HttpResponse('OK')
                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        elif request.method == 'PUT':
            # /tickets/upload/XXX/?filename=test1.txt
            upload_handlers = request.upload_handlers
            content_type = str(request.META.get('CONTENT_TYPE', ""))
            content_length = int(request.META.get('CONTENT_LENGTH', 0))

            if content_type == "":
                return HttpResponse('missing ContentType', status=400)
            if content_length == 0:
                # both returned 0
                return HttpResponse('missing ContentLength', status=400)

            content_type = content_type.split(";")[0].strip()
            try:
                charset = content_type.split(";")[1].strip()
            except IndexError:
                charset = ""

            # we can get the file name via the path, we don't actually
            file_name = request.GET['filename']
            field_name = file_name

            counters = [0] * len(upload_handlers)

            for handler in upload_handlers:
                result = handler.handle_raw_input("", request.META,
                                                  content_length, "", "")

            from django.core.files.uploadhandler import StopFutureHandlers
            for handler in upload_handlers:
                try:
                    handler.new_file(field_name, file_name, content_type,
                                     content_length, charset)
                except StopFutureHandlers:
                    break

            for i, handler in enumerate(upload_handlers):
                while True:
                    chunk = request.read(handler.chunk_size)
                    if chunk:

                        handler.receive_data_chunk(chunk, counters[i])
                        counters[i] += len(chunk)
                    else:
                        # no chunk
                        break

            for i, handler in enumerate(upload_handlers):
                file_obj = handler.file_complete(counters[i])
                if file_obj:
                    if settings.FILE_UPLOAD_VIRUS_SCAN and pyclamd:
                        # virus scan
                        try:
                            if not hasattr(pyclamd, 'scan_stream'):
                                cd = pyclamd.ClamdUnixSocket()
                            else:
                                pyclamd.init_network_socket('localhost', 3310)
                                cd = pyclamd

                            # We need to get a file object for clamav. We might have a path or we might
                            # have to read the data into memory.
                            if hasattr(file_obj, 'temporary_file_path'):
                                os.chmod(file_obj.temporary_file_path(), 0664)
                                result = cd.scan_file(
                                    file_obj.temporary_file_path())
                            else:
                                if hasattr(file_obj, 'read'):
                                    result = cd.scan_stream(file_obj.read())
                                else:
                                    result = cd.scan_stream(
                                        file_obj['content'])
                        except:
                            from socket import gethostname
                            raise Exception(
                                _(u'unable to initialize scan engine on host %s'
                                  ) % gethostname())

                        if result:
                            msg = ' '.join(result[result.keys()[0]]).replace(
                                'FOUND ', '')
                            raise Exception(
                                _(u"file is infected by virus: %s") % msg)

                    hasher = hashlib.md5()
                    # We need to get a file object for clamav. We might have a path or we might
                    # have to read the data into memory.
                    if hasattr(file_obj, 'temporary_file_path'):
                        with open(file_obj.temporary_file_path(),
                                  'rb') as afile:
                            buf = afile.read()
                            hasher.update(buf)
                        hash = hasher.hexdigest()
                    else:
                        if hasattr(file_obj, 'read'):
                            file_obj.seek(0)
                            buf = file_obj.read()
                            hasher.update(buf)
                        else:
                            hasher.update(file_obj['content'].read())
                    hash = hasher.hexdigest()

                    if tickets_files.objects.filter(active_record=True,
                                                    ticket=ticket,
                                                    checksum=hash).count() > 0:
                        raise Exception(
                            'duplicate hash value - file already exists in this ticket %s'
                            % ticket)

                    # todo: virusscan
                    f = tickets_files()
                    f.name = file_obj.name
                    f.size = file_obj.size
                    f.checksum = hash
                    f.content_type = content_type
                    f.ticket_id = ticket
                    f.public = True
                    f.save(user=request.user)

                    touch_ticket(request.user, ticket)

                    add_history(request, tic, 5, file_obj.name)

                    mail_file(request, f.pk)
                    jabber_file(request, f.pk)

                    dest = settings.FILE_UPLOAD_PATH
                    if not os.path.exists(dest):
                        os.makedirs(dest)

                    with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                        for chunk in file_obj.chunks():
                            destination.write(chunk)

                    if 'pdf' in f.content_type:
                        convertPDFtoImg('%s/%s.dat' % (dest, f.id),
                                        '%s/%s.preview' % (dest, f.id))
                    else:
                        if 'image' not in f.content_type and isPreviewable(
                                f.content_type):
                            try:
                                tmp = convertOfficeTpPDF('%s/%s.dat' %
                                                         (dest, f.id))
                                convertPDFtoImg(tmp,
                                                '%s/%s.preview' % (dest, f.id))
                                if os.path.isfile(tmp):
                                    os.unlink(tmp)
                            except:
                                pass

                        if 'audio' in f.content_type:
                            try:
                                # https://realpython.com/python-speech-recognition/
                                import speech_recognition as sr
                                AUDIO_FILE = '%s%s.dat' % (dest, f.id)
                                r = sr.Recognizer()
                                with sr.AudioFile(AUDIO_FILE) as source:
                                    audio = r.record(
                                        source)  # read the entire audio file

                                text = r.recognize_google(audio,
                                                          language='de-DE')
                                if text:
                                    com = tickets_comments()
                                    com.comment = text
                                    com.ticket_id = ticket
                                    com.action = 6
                                    com.save(user=request.user)
                            except:
                                pass

                    return HttpResponse(status=201)

                else:
                    # some indication this didn't work?
                    return HttpResponse(status=500)

        else:
            form = UploadFileForm()

        return render(request, 'tickets/file.html', {
            'ticketid': ticket,
            'layout': 'horizontal',
            'form': form
        })

    elif mode == 'delfile':
        file = tickets_files.objects.get(pk=request.GET['fileid'],
                                         ticket=ticket)
        file.delete(user=request.user)

        touch_ticket(request.user, ticket)

        add_history(request, tic, 8, file.name)

        return HttpResponseRedirect('/tickets/view/%s/#files' % tic.pk)

    elif mode == 'notify':
        tickets_participants.objects.filter(
            ticket=tic, user=request.user).update(seen=True)
        return HttpResponse('OK')

    elif mode == 'sleep':
        interval = request.GET.get('interval')
        if interval in ['1', '2', '3', '4', '5', '6', '7', '14', '21', '30']:
            old = tic.show_start
            tic.show_start = timezone.now() + datetime.timedelta(
                days=int(interval))
            tic.save(user=request.user)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 10, (tic.show_start, old))

            return HttpResponse('OK')

        else:
            raise Exception('no interval given')

    elif mode == 'ignore':
        ig = tickets_ignorants()
        ig.ticket = tic
        ig.user = request.user
        ig.save()
        return HttpResponse('OK')

    elif mode == 'todo':

        class local:
            counter = 0

        def ToDoDone(match):
            local.counter += 1
            group = match.groups()
            if local.counter == pos:
                return u'[X]'
            else:
                return u'[%s]' % group[0]

        def ToDoUnDone(match):
            local.counter += 1
            group = match.groups()
            if local.counter == pos:
                return u'[ ]'
            else:
                return u'[%s]' % group[0]

        form = ToDo(request.POST)
        if form.is_valid():
            desc = tic.description

            cd = form.cleaned_data
            text = cd['text']
            pos = cd['item']
            set = cd['set']
            if set:
                tic.description = re.sub(r'\[([ Xx])\]', ToDoDone, desc)
                old = _('undone: %s') % text
                new = _('done: %s') % text
            else:
                tic.description = re.sub(r'\[([ Xx])\]', ToDoUnDone, desc)
                new = _('undone: %s') % text
                old = _('done: %s') % text

            tic.save(user=request.user)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 9, (new, old))

            data = {
                'set': set,
                'item': pos,
                'text': text,
            }
            return JsonResponse(data, safe=False)

    elif mode == 'update_comment':

        if request.method == 'POST':
            comment_id = request.GET.get("comment_id")
            comment = tickets_comments.objects.get(pk=comment_id)

            if comment.c_user == request.user:
                comment.comment = request.POST.get("comment_body", "")
                comment.edited = True
                comment.save(user=request.user)

        return HttpResponseRedirect("/tickets/view/%s/#comment_id-%s" %
                                    (ticket, comment_id))

    elif mode == 'last_modified':
        if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE')
        if if_modified_since:
            if_modified_since = parse_http_date_safe(if_modified_since)
            if time.mktime(
                    tic.last_action_date.timetuple()) > if_modified_since:
                return HttpResponse('outdated', status=200)
            else:
                return HttpResponse('not modified', status=304)

        else:
            return HttpResponse('unknown', status=412)
Ejemplo n.º 6
0
def show_board(request, name):
    # http://bootsnipp.com/snippets/featured/kanban-board
    """
        board structure

        [
            {
                'column': 'closed',
                'query': {'closed': False},
                'limit': 10,
                'extra_filter': 1, # 1 = days since closed, 2 = days since created, 3 = days since last changed, 4 days since last action
                'days': 1, # days
                'order_by': 'id',
                'order_dir': ''
            }
        ]
    """

    name = unquote_plus(name)

    if request.method == 'POST':
        if 'method' in request.POST:
            board = boards.objects.get(active_record=True,
                                       pk=request.POST['board'],
                                       c_user=request.user)
            try:
                columns = json.loads(board.columns)
            except:
                columns = []

            if request.POST['method'] == 'add':
                form = AddToBordForm(request.POST)
                if form.is_valid():
                    cd = form.cleaned_data
                    col = {
                        'column': cd['column'],
                        'query': request.session['last_search'],
                        'limit': cd['limit'],
                        'order_by': cd['order_by'],
                        'order_dir': cd['order_dir']
                    }
                    if cd.get('extra_filter') and cd.get('days'):
                        col['extra_filter'] = cd['extra_filter']
                        col['days'] = cd['days']
                    columns.append(col)
                    board.columns = json.dumps(columns, cls=DjangoJSONEncoder)
                    board.save(user=request.user)

                else:
                    err_list = []
                    for field in form:
                        for err in field.errors:
                            err_list.append('%s: %s' % (field.name, err))
                    messages.add_message(
                        request, messages.ERROR,
                        _('data invalid: %s') % '\n'.join(err_list))

                return HttpResponseRedirect('/board/%s/' %
                                            urlquote_plus(board.name))

        else:
            if request.POST['boardname'].strip() != '':
                if boards.objects.filter(active_record=True,
                                         c_user=request.user,
                                         name=request.POST['boardname']).count(
                                         ) == 0 and request.POST['boardname']:
                    board = boards()
                    board.name = request.POST['boardname'].strip()
                    board.save(user=request.user)

                    return HttpResponseRedirect(
                        '/board/%s/' %
                        urlquote_plus(request.POST['boardname']))

                else:
                    messages.add_message(
                        request, messages.ERROR,
                        _(u'A board with the name "%s" already exists' %
                          request.POST['boardname']))
                    return HttpResponseRedirect('/')
            else:
                messages.add_message(request, messages.ERROR,
                                     _(u'No name for a board given'))
                return HttpResponseRedirect('/')

    else:
        board = boards.objects.get(active_record=True,
                                   name=name,
                                   c_user=request.user)
        try:
            columns = json.loads(board.columns)
        except:
            columns = []

        if 'method' in request.GET and request.GET['method'] == 'del':
            new_columns = []
            for col in columns:
                if col['column'] != request.GET['column']:
                    new_columns.append(col)
            board.columns = json.dumps(new_columns, cls=DjangoJSONEncoder)
            board.save(user=request.user)

            return HttpResponseRedirect('/board/%s/' % urlquote_plus(name))

        elif 'method' in request.GET and request.GET['method'] == 'delete':
            board.delete(user=request.user)
            return HttpResponseRedirect('/')

    for column in columns:
        query = get_ticket_model().objects.select_related(
            'type', 'state', 'assigned', 'priority', 'customer').all()
        search_params, query = build_ticket_search_ext(request, query,
                                                       column['query'])
        column['query'] = query.order_by(
            '%s%s' %
            (column.get('order_dir', ''), column.get('order_by', 'id')))
        if 'extra_filter' in column and 'days' in column and column[
                'extra_filter'] and column['days']:
            if column['extra_filter'] == '1':  # days since closed
                column['query'] = column['query'].filter(
                    close_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days'])).exclude(
                        close_date=None)
            if column['extra_filter'] == '2':  # days since created
                column['query'] = column['query'].filter(
                    c_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '3':  # days since last changed
                column['query'] = column['query'].filter(
                    u_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '4':  # days since last action
                column['query'] = column['query'].filter(
                    last_action_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days']))
        if not request.user.is_staff:
            column['query'] = column['query'].filter(
                customer=request.organisation)

        seen_elements = {}
        seen = tickets_participants.objects.filter(
            user=request.user,
            ticket__in=column['query'].values_list('id',
                                                   flat=True)).values_list(
                                                       'ticket_id', 'seen')
        for see in seen:
            seen_elements[see[0]] = see[1]

        seen = tickets_ignorants.objects.filter(
            user=request.user,
            ticket__in=column['query'].values_list(
                'id', flat=True)).values_list('ticket_id')
        for see in seen:
            seen_elements[see[0]] = True

        if column['limit']:
            column['query'] = column['query'][:column['limit']]
        column['seen'] = seen_elements

    add_breadcrumbs(request, board.pk, '$')
    return render(request, 'board/view.html', {
        'columns': columns,
        'board': board
    })
Ejemplo n.º 7
0
def kanban(request):
    flows = ticket_flow.objects.all().order_by('type')
    columns = []
    finish_state = -1
    days = UserProfile.objects.get(user=request.user).day_since_closed_tickets

    query = get_ticket_model().objects.select_related('type', 'state',
                                                      'assigned', 'priority',
                                                      'customer').all()

    for flow in flows:
        search_params, flow.data = build_ticket_search_ext(
            request, query, convert_sarch({'state': flow.pk}))
        flow.data = flow.data.filter(
            Q(show_start=None) | Q(show_start__lte=timezone.now()))

        if flow.type == 2:
            flow.data = flow.data.filter(
                Q(assigned=None)
                | Q(assigned=request.user)).order_by('-close_date')
        else:
            flow.data = flow.data.filter(
                Q(assigned=None) | Q(assigned=request.user)).extra(
                    select={'prio': 'COALESCE(caldav, 10)'},
                    order_by=['prio', '-c_date'])

        if flow.type == 1:
            columns.insert(0, flow)
        else:
            columns.append(flow)
            if flow.type == 2:
                finish_state = flow.pk
                flow.data = flow.data.filter(
                    close_date__gte=datetime.date.today() -
                    datetime.timedelta(days=days))

        seen_elements = {}
        seen = tickets_participants.objects.filter(
            user=request.user,
            ticket__in=flow.data.values_list('id', flat=True)).values_list(
                'ticket_id', 'seen')
        for see in seen:
            seen_elements[see[0]] = see[1]

        seen = tickets_ignorants.objects.filter(
            user=request.user,
            ticket__in=flow.data.values_list(
                'id', flat=True)).values_list('ticket_id')
        for see in seen:
            seen_elements[see[0]] = True

        flow.seen = seen_elements

    close = TicketCloseForm()
    reassign = TicketReassignForm()
    edges = ticket_flow_edges.objects.all().order_by('now')
    add_breadcrumbs(request, 0, 'k')
    cur_language = translation.get_language()
    return render(
        request, 'board/kanban.html', {
            'layout': 'horizontal',
            'columns': columns,
            'edges': edges,
            'finish_state': finish_state,
            'close': close,
            'reassign': reassign,
            'cur_language': cur_language
        })
Ejemplo n.º 8
0
def action(request, mode, ticket):
    mod_path, cls_name = settings.TICKET_CLASS.rsplit('.', 1)
    mod_path = mod_path.split('.').pop(0)
    tic = apps.get_model(mod_path, cls_name).objects.get(pk=ticket)

    if hasattr(settings, 'KEEP_IT_SIMPLE') and settings.KEEP_IT_SIMPLE:
        keep_it_simple = True
    else:
        keep_it_simple = False

    if mode == 'view':
        if request.method == 'POST':
            form = CommentForm(request.POST)
            if form.is_valid():
                com = tickets_comments()
                com.comment = form.cleaned_data['comment']
                com.ticket_id = ticket
                com.action = 6
                com.save(user=request.user)

                check_references(request, com)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 6, com.comment)

                mail_comment(request, com.pk)
                jabber_comment(request, com.pk)

            else:
                if 'resolution' in request.POST:
                    if request.POST['resolution'] and int(request.POST['resolution']) > 0:
                        tic.resolution_id = request.POST['resolution']
                        tic.closed = True
                        tic.close_date = timezone.now()
                        tic.state = get_flow_end()
                        tic.save(user=request.user)

                        com = tickets_comments()
                        com.comment = _('ticket closed - resolution: %(resolution)s\n\n%(comment)s') % {'resolution': ticket_resolution.objects.get(pk=request.POST['resolution']).name, 'comment': request.POST.get('close_comment', '')}
                        com.ticket_id = ticket
                        com.action = 1
                        com.save(user=request.user)

                        check_references(request, com)

                        touch_ticket(request.user, ticket)

                        add_history(request, tic, 1, request.POST.get('close_comment', ''))

                        mail_comment(request, com.pk)
                        jabber_comment(request, com.pk)

                    else:
                        messages.add_message(request, messages.ERROR, _('no resolution selected'))

                else:
                    messages.add_message(request, messages.ERROR, _('comment invalid'))

        excludes = []
        form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id, view_only=True)
        close = TicketCloseForm()
        reassign = TicketReassignForm(initial={'assigned': tic.assigned_id, 'state': tic.state})
        flows = list(ticket_flow_edges.objects.select_related('next').filter(now=tic.state).exclude(next__type=2).values_list('next', flat=True))
        flows.append(tic.state_id)
        reassign.fields['state'].queryset = reassign.fields['state'].queryset.filter(id__in=flows)

        participants = tickets_participants.objects.select_related('user').filter(ticket=ticket)
        comments = tickets_comments.objects.select_related('c_user').filter(ticket=ticket).order_by('c_date')

        close_allowed = ticket_flow_edges.objects.select_related('next').filter(now=tic.state, next__type=2).count() > 0

        files = tickets_files.objects.filter(ticket=ticket, active_record=True)
        paginator = Paginator(files, 10)
        page = request.GET.get('page')
        try:
            files_lines = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            files_lines = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            files_lines = paginator.page(paginator.num_pages)

        add_breadcrumbs(request, ticket, '#', caption=tic.caption[:20])
        if 'YATSE' in request.GET and 'isUsingYATSE' not in request.session:
            request.session['isUsingYATSE'] = True

        return render(request, 'tickets/view.html', {'layout': 'horizontal', 'ticket': tic, 'form': form, 'close': close, 'reassign': reassign, 'files': files_lines, 'comments': comments, 'participants': participants, 'close_allowed': close_allowed, 'keep_it_simple': keep_it_simple, 'last_action_date': http_date(time.mktime(tic.last_action_date.timetuple()))})

    elif mode == 'gallery':
        images = tickets_files.objects.filter(ticket=ticket, active_record=True)
        return render(request, 'tickets/gallery.html', {'layout': 'horizontal', 'ticket': tic, 'images': images})

    elif mode == 'history':
        history = tickets_history.objects.filter(ticket=ticket)
        return render(request, 'tickets/history.html', {'layout': 'horizontal', 'ticket': tic, 'history': history, 'keep_it_simple': keep_it_simple})

    elif mode == 'reopen':
        if tic.closed:
            tic.closed = False
            tic.state = get_flow_start()
            tic.resolution = None
            tic.close_date = None
            tic.save(user=request.user)

            com = tickets_comments()
            com.comment = _('ticket reopend - resolution deleted')
            com.ticket_id = ticket
            com.action = 2
            com.save(user=request.user)

            check_references(request, com)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 2, None)

            mail_comment(request, com.pk)
            jabber_comment(request, com.pk)

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'move':
        if not tic.closed:
            old_state = tic.state

            tic.state = ticket_flow.objects.get(pk=request.POST['state'])
            tic.save(user=request.user)

            touch_ticket(request.user, ticket)

            oldUser = str(User.objects.get(pk=tic.assigned_id)) if tic.assigned_id else None

            history_data = {
                            'old': {'comment': '', 'assigned': oldUser, 'state': str(old_state)},
                            'new': {'comment': _('ticket moved'), 'assigned': oldUser, 'state': str(tic.state)}
                            }
            add_history(request, tic, 7, history_data)

        return HttpResponse('OK')

    elif mode == 'reassign':
        if not tic.closed:
            if 'assigned' in request.POST:
                if request.POST['assigned'] and int(request.POST['assigned']) > 0:
                    old_assigned_user = tic.assigned
                    old_state = tic.state

                    tic.assigned_id = request.POST['assigned']
                    tic.state = ticket_flow.objects.get(pk=request.POST['state'])
                    tic.save(user=request.user)

                    newUser = User.objects.get(pk=request.POST['assigned'])

                    com = tickets_comments()
                    com.comment = _('ticket reassigned to %(user)s\nstate now: %(state)s\n\n%(comment)s') % {'user': newUser, 'comment': request.POST.get('reassign_comment', ''), 'state': tic.state}
                    com.ticket_id = ticket
                    com.action = 7
                    com.save(user=request.user)

                    check_references(request, com)

                    touch_ticket(request.user, ticket)
                    if request.POST['assigned']:
                        touch_ticket(newUser, ticket)

                    mail_comment(request, com.pk)
                    jabber_comment(request, com.pk)

                    history_data = {
                                    'old': {'comment': '', 'assigned': str(old_assigned_user), 'state': str(old_state)},
                                    'new': {'comment': request.POST.get('reassign_comment', ''), 'assigned': str(User.objects.get(pk=request.POST['assigned'])), 'state': str(tic.state)}
                                    }
                    add_history(request, tic, 7, history_data)

                else:
                    messages.add_message(request, messages.ERROR, _('missing assigned user'))

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'edit' or (mode == 'simple' and (not tic.keep_it_simple or tic.closed) and keep_it_simple):
        excludes = ['resolution']
        if request.method == 'POST':
            form = TicketsForm(request.POST, exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id)
            if form.is_valid():
                tic = form.save()

                if tic.keep_it_simple:
                    tic.keep_it_simple = False
                    tic.save(user=request.user)

                assigned = form.cleaned_data.get('assigned')
                if assigned:
                    touch_ticket(assigned, tic.pk)

                mail_ticket(request, tic.pk, form)
                jabber_ticket(request, tic.pk, form)

                remember_changes(request, form, tic)

                touch_ticket(request.user, tic.pk)

                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        else:
            form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id)
        if 'state' in form.fields:
            form.fields['state'].queryset = form.fields['state'].queryset.exclude(type=2)
        return render(request, 'tickets/edit.html', {'ticket': tic, 'layout': 'horizontal', 'form': form})

    elif mode == 'simple':
        if request.method == 'POST':
            form = SimpleTickets(request.POST, initial={
                    'caption': tic.caption,
                    'description': tic.description,
                    'priority': tic.priority,
                    'assigned': tic.assigned
                })
            if form.is_valid():
                cd = form.cleaned_data
                tic.caption = cd['caption']
                tic.description = cd['description'].replace(u"\u00A0", " ")
                tic.priority = cd['priority']
                tic.assigned = cd['assigned']
                tic.deadline = cd['deadline']
                tic.show_start = cd['show_start']
                tic.component = cd['component']
                tic.save(user=request.user)

                if cd['assigned']:
                    touch_ticket(cd['assigned'], tic.pk)

                remember_changes(request, form, tic)

                touch_ticket(request.user, tic.pk)

                mail_ticket(request, tic.pk, form)
                jabber_ticket(request, tic.pk, form)

                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        else:
            form = SimpleTickets(initial={
                    'caption': tic.caption,
                    'description': tic.description,
                    'priority': tic.priority,
                    'assigned': tic.assigned,
                    'deadline': tic.deadline,
                    'show_start': tic.show_start,
                    'component': tic.component,
                })
        return render(request, 'tickets/edit.html', {'ticket': tic, 'layout': 'horizontal', 'form': form, 'mode': mode})

    elif mode == 'download':
        fileid = request.GET.get('file', -1)
        file_data = tickets_files.objects.get(id=fileid, ticket=ticket)
        src = '%s%s.dat' % (settings.FILE_UPLOAD_PATH, fileid)
        content_type = file_data.content_type
        if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)):
            src = '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)
            content_type = 'imgae/png'

        if request.GET.get('resize', 'no') == 'yes' and ('image' in file_data.content_type or 'pdf' in file_data.content_type):
            img = resize_image('%s' % (src), (200, 150), 75)
            output = io.BytesIO()
            img.save(output, 'PNG')
            output.seek(0)
            response = StreamingHttpResponse(output, content_type='image/png')

        else:
            response = StreamingHttpResponse(open('%s' % (src), "rb"), content_type=content_type)

        if 'noDisposition' not in request.GET:
            if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)):
                response['Content-Disposition'] = 'attachment;filename="%s"' % content_type
            else:
                response['Content-Disposition'] = 'attachment;filename="%s"' % smart_str(file_data.name)
        return response

    elif mode == 'upload':
        if request.method == 'POST':
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                if tickets_files.objects.filter(active_record=True, ticket=ticket, checksum=request.FILES['file'].hash).count() > 0:
                    messages.add_message(request, messages.ERROR, _('File already exists: %s') % request.FILES['file'].name)
                    if request.GET.get('Ajax') == '1':
                        return HttpResponse('OK')
                    return HttpResponseRedirect('/tickets/view/%s/' % ticket)
                f = tickets_files()
                f.name = request.FILES['file'].name
                f.size = request.FILES['file'].size
                f.checksum = request.FILES['file'].hash
                f.content_type = request.FILES['file'].content_type
                f.ticket_id = ticket
                f.public = True
                f.save(user=request.user)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 5, request.FILES['file'].name)

                mail_file(request, f.pk)
                jabber_file(request, f.pk)

                dest = settings.FILE_UPLOAD_PATH
                if not os.path.exists(dest):
                    os.makedirs(dest)

                with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                    for chunk in request.FILES['file'].chunks():
                        destination.write(chunk)

                if 'pdf' in f.content_type:
                    convertPDFtoImg('%s/%s.dat' % (dest, f.id), '%s/%s.preview' % (dest, f.id))
                else:
                    if 'image' not in f.content_type and isPreviewable(f.content_type):
                        tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id))
                        convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id))
                        if os.path.isfile(tmp):
                            os.unlink(tmp)

                return HttpResponseRedirect('/tickets/view/%s/' % tic.pk)

            else:
                msg = unicode(form.errors['file'])
                msg = re.sub('<[^<]+?>', '', msg)
                messages.add_message(request, messages.ERROR, msg)
                if request.GET.get('Ajax') == '1':
                    return HttpResponse('OK')
                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        elif request.method == 'PUT':
            # /tickets/upload/XXX/?filename=test1.txt
            upload_handlers = request.upload_handlers
            content_type = str(request.META.get('CONTENT_TYPE', ""))
            content_length = int(request.META.get('CONTENT_LENGTH', 0))

            if content_type == "":
                return HttpResponse('missing ContentType', status=400)
            if content_length == 0:
                # both returned 0
                return HttpResponse('missing ContentLength', status=400)

            content_type = content_type.split(";")[0].strip()
            try:
                charset = content_type.split(";")[1].strip()
            except IndexError:
                charset = ""

            # we can get the file name via the path, we don't actually
            file_name = request.GET['filename']
            field_name = file_name

            counters = [0]*len(upload_handlers)

            for handler in upload_handlers:
                result = handler.handle_raw_input("", request.META, content_length, "", "")

            from django.core.files.uploadhandler import StopFutureHandlers
            for handler in upload_handlers:
                try:
                    handler.new_file(field_name, file_name,
                                     content_type, content_length, charset)
                except StopFutureHandlers:
                    break

            for i, handler in enumerate(upload_handlers):
                while True:
                    chunk = request.read(handler.chunk_size)
                    if chunk:

                        handler.receive_data_chunk(chunk, counters[i])
                        counters[i] += len(chunk)
                    else:
                        # no chunk
                        break

            for i, handler in enumerate(upload_handlers):
                file_obj = handler.file_complete(counters[i])
                if file_obj:
                    if settings.FILE_UPLOAD_VIRUS_SCAN and pyclamd:
                        # virus scan
                        try:
                            if not hasattr(pyclamd, 'scan_stream'):
                                cd = pyclamd.ClamdUnixSocket()
                            else:
                                pyclamd.init_network_socket('localhost', 3310)
                                cd = pyclamd

                            # We need to get a file object for clamav. We might have a path or we might
                            # have to read the data into memory.
                            if hasattr(file_obj, 'temporary_file_path'):
                                os.chmod(file_obj.temporary_file_path(), 0664)
                                result = cd.scan_file(file_obj.temporary_file_path())
                            else:
                                if hasattr(file_obj, 'read'):
                                    result = cd.scan_stream(file_obj.read())
                                else:
                                    result = cd.scan_stream(file_obj['content'])
                        except:
                            from socket import gethostname
                            raise Exception(_(u'unable to initialize scan engine on host %s') % gethostname())

                        if result:
                            msg = ' '.join(result[result.keys()[0]]).replace('FOUND ', '')
                            raise Exception(_(u"file is infected by virus: %s") % msg)

                    hasher = hashlib.md5()
                    # We need to get a file object for clamav. We might have a path or we might
                    # have to read the data into memory.
                    if hasattr(file_obj, 'temporary_file_path'):
                        with open(file_obj.temporary_file_path(), 'rb') as afile:
                            buf = afile.read()
                            hasher.update(buf)
                        hash = hasher.hexdigest()
                    else:
                        if hasattr(file_obj, 'read'):
                            file_obj.seek(0)
                            buf = file_obj.read()
                            hasher.update(buf)
                        else:
                            hasher.update(file_obj['content'].read())
                    hash = hasher.hexdigest()

                    if tickets_files.objects.filter(active_record=True, ticket=ticket, checksum=hash).count() > 0:
                        raise Exception('duplicate hash value - file already exists in this ticket %s' % ticket)

                    # todo: virusscan
                    f = tickets_files()
                    f.name = file_obj.name
                    f.size = file_obj.size
                    f.checksum = hash
                    f.content_type = content_type
                    f.ticket_id = ticket
                    f.public = True
                    f.save(user=request.user)

                    touch_ticket(request.user, ticket)

                    add_history(request, tic, 5, file_obj.name)

                    mail_file(request, f.pk)
                    jabber_file(request, f.pk)

                    dest = settings.FILE_UPLOAD_PATH
                    if not os.path.exists(dest):
                        os.makedirs(dest)

                    with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                        for chunk in file_obj.chunks():
                            destination.write(chunk)

                    if 'pdf' in f.content_type:
                        convertPDFtoImg('%s/%s.dat' % (dest, f.id), '%s/%s.preview' % (dest, f.id))
                    else:
                        if 'image' not in f.content_type and isPreviewable(f.content_type):
                            try:
                                tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id))
                                convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id))
                                if os.path.isfile(tmp):
                                    os.unlink(tmp)
                            except:
                                pass

                        if 'audio' in f.content_type:
                            try:
                                # https://realpython.com/python-speech-recognition/
                                import speech_recognition as sr
                                AUDIO_FILE = '%s%s.dat' % (dest, f.id)
                                r = sr.Recognizer()
                                with sr.AudioFile(AUDIO_FILE) as source:
                                    audio = r.record(source)  # read the entire audio file

                                text = r.recognize_google(audio, language='de-DE')
                                if text:
                                    com = tickets_comments()
                                    com.comment = text
                                    com.ticket_id = ticket
                                    com.action = 6
                                    com.save(user=request.user)
                            except:
                                pass

                    return HttpResponse(status=201)

                else:
                    # some indication this didn't work?
                    return HttpResponse(status=500)

        else:
            form = UploadFileForm()

        return render(request, 'tickets/file.html', {'ticketid': ticket, 'layout': 'horizontal', 'form': form})

    elif mode == 'delfile':
        file = tickets_files.objects.get(pk=request.GET['fileid'], ticket=ticket)
        file.delete(user=request.user)

        touch_ticket(request.user, ticket)

        add_history(request, tic, 8, file.name)

        return HttpResponseRedirect('/tickets/view/%s/#files' % tic.pk)

    elif mode == 'notify':
        tickets_participants.objects.filter(ticket=tic, user=request.user).update(seen=True)
        return HttpResponse('OK')

    elif mode == 'sleep':
        interval = request.GET.get('interval')
        if interval in ['1', '7', '30']:
            old = tic.show_start
            tic.show_start = timezone.now() + datetime.timedelta(days=int(interval))
            tic.save(user=request.user)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 10, (tic.show_start, old))

            return HttpResponse('OK')

        else:
            raise Exception('no interval given')

    elif mode == 'ignore':
        ig = tickets_ignorants()
        ig.ticket = tic
        ig.user = request.user
        ig.save()
        return HttpResponse('OK')

    elif mode == 'todo':
        class local:
            counter = 0

        def ToDoDone(match):
            local.counter += 1
            group = match.groups()
            if local.counter == pos:
                return u'[X]'
            else:
                return u'[%s]' % group[0]

        def ToDoUnDone(match):
            local.counter += 1
            group = match.groups()
            if local.counter == pos:
                return u'[ ]'
            else:
                return u'[%s]' % group[0]

        form = ToDo(request.POST)
        if form.is_valid():
            desc = tic.description

            cd = form.cleaned_data
            text = cd['text']
            pos = cd['item']
            set = cd['set']
            if set:
                tic.description = re.sub(r'\[([ Xx])\]', ToDoDone, desc)
                old = _('undone: %s') % text
                new = _('done: %s') % text
            else:
                tic.description = re.sub(r'\[([ Xx])\]', ToDoUnDone, desc)
                new = _('undone: %s') % text
                old = _('done: %s') % text

            tic.save(user=request.user)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 9, (new, old))

            data = {
                'set': set,
                'item': pos,
                'text': text,
            }
            return JsonResponse(data, safe=False)

    elif mode == 'update_comment':

        if request.method == 'POST':
            comment_id = request.GET.get("comment_id")
            comment = tickets_comments.objects.get(pk=comment_id)

            if comment.c_user == request.user:
                comment.comment = request.POST.get("comment_body", "")
                comment.edited = True
                comment.save(user=request.user)

        return HttpResponseRedirect("/tickets/view/%s/#comment_id-%s" % (ticket, comment_id))

    elif mode == 'last_modified':
        if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE')
        if if_modified_since:
            if_modified_since = parse_http_date_safe(if_modified_since)
            if time.mktime(tic.last_action_date.timetuple()) > if_modified_since:
                return HttpResponse('outdated', status=200)
            else:
                return HttpResponse('not modified', status=304)

        else:
            return HttpResponse('unknown', status=412)
Ejemplo n.º 9
0
def docs_action(request, mode, docid):
    doc = docs.objects.get(pk=docid)
    if mode == 'view':
        form = DocsForm(user=request.user, instance=doc, view_only=True)
        add_breadcrumbs(request, docid, '*', caption=doc.caption[:20])

        files = docs_files.objects.filter(doc=doc, active_record=True)
        paginator = Paginator(files, 10)
        page = request.GET.get('page')
        try:
            files_lines = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            files_lines = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            files_lines = paginator.page(paginator.num_pages)

        return render(request, 'docs/view.html', {'layout': 'horizontal', 'form': form, 'doc': doc, 'files': files_lines})

    elif mode == 'edit':
        if request.method == 'POST':
            form = DocsForm(request.POST, user=request.user, instance=doc)
            if form.is_valid():
                doc = form.save()
                return HttpResponseRedirect('/docs/view/%s/' % doc.pk)

        form = DocsForm(user=request.user, instance=doc)
        return render(request, 'docs/edit.html', {'layout': 'horizontal', 'form': form, 'doc': doc})

    elif mode == 'delete':
        doc.delete(user=request.user)
        return HttpResponseRedirect('/search/?q=%s&models=yats.docs&models=web.test' % request.session.get('last_fulltextsearch', '*'))

    elif mode == 'ticket':
        ticket = get_ticket_model()
        tic = ticket()
        tic.caption = doc.caption
        tic.description = doc.text
        if hasattr(settings, 'KEEP_IT_SIMPLE_DEFAULT_CUSTOMER') and settings.KEEP_IT_SIMPLE_DEFAULT_CUSTOMER:
            if settings.KEEP_IT_SIMPLE_DEFAULT_CUSTOMER == -1:
                tic.customer = request.organisation
            else:
                tic.customer_id = settings.KEEP_IT_SIMPLE_DEFAULT_CUSTOME
        if not tic.component_id and hasattr(settings, 'KEEP_IT_SIMPLE_DEFAULT_COMPONENT') and settings.KEEP_IT_SIMPLE_DEFAULT_COMPONENT:
            tic.component_id = settings.KEEP_IT_SIMPLE_DEFAULT_COMPONENT
        tic.save(user=request.user)

        add_breadcrumbs(request, str(tic.pk), '#', caption=tic.caption[:20])

        if hasattr(settings, 'KEEP_IT_SIMPLE') and settings.KEEP_IT_SIMPLE:
            return HttpResponseRedirect('/tickets/simple/%s/' % tic.pk)
        else:
            return HttpResponseRedirect('/tickets/edit/%s/' % tic.pk)

    elif mode == 'download':
        fileid = request.GET.get('file', -1)
        file_data = docs_files.objects.get(id=fileid, doc=doc)
        src = '%s%s.dat' % (get_doc_files_folder(), fileid)
        content_type = file_data.content_type
        if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (get_doc_files_folder(), fileid)):
            src = '%s%s.preview' % (get_doc_files_folder(), fileid)
            content_type = 'imgae/png'

        if request.GET.get('resize', 'no') == 'yes' and ('image' in file_data.content_type or 'pdf' in file_data.content_type):
            img = resize_image('%s' % (src), (200, 150), 75)
            output = io.BytesIO()
            img.save(output, 'PNG')
            output.seek(0)
            response = StreamingHttpResponse(output, content_type='image/png')

        else:
            response = StreamingHttpResponse(open('%s' % (src), "rb"), content_type=content_type)

        if 'noDisposition' not in request.GET:
            if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (get_doc_files_folder(), fileid)):
                response['Content-Disposition'] = 'attachment;filename=%s' % content_type
            else:
                response['Content-Disposition'] = 'attachment;filename=%s' % smart_str(file_data.name)
        return response

    elif mode == 'upload':
        if request.method == 'POST':
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                if docs_files.objects.filter(active_record=True, doc=doc, checksum=request.FILES['file'].hash).count() > 0:
                    messages.add_message(request, messages.ERROR, _('File already exists: %s') % request.FILES['file'].name)
                    if request.GET.get('Ajax') == '1':
                        return HttpResponse('OK')
                    return HttpResponseRedirect('/docs/view/%s/' % doc.id)
                f = docs_files()
                f.name = request.FILES['file'].name
                f.size = request.FILES['file'].size
                f.checksum = request.FILES['file'].hash
                f.content_type = request.FILES['file'].content_type
                f.doc_id = doc.id
                f.public = True
                f.save(user=request.user)

                #add_history(request, tic, 5, request.FILES['file'].name)

                dest = get_doc_files_folder()
                if not os.path.exists(dest):
                    os.makedirs(dest)

                with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                    for chunk in request.FILES['file'].chunks():
                        destination.write(chunk)

                if 'pdf' in f.content_type:
                    convertPDFtoImg('%s/%s.dat' % (dest, f.id), '%s/%s.preview' % (dest, f.id))
                else:
                    if 'image' not in f.content_type and isPreviewable(f.content_type):
                        tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id))
                        convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id))
                        if os.path.isfile(tmp):
                            os.unlink(tmp)

                return HttpResponseRedirect('/docs/view/%s/' % doc.pk)

            else:
                msg = unicode(form.errors['file'])
                msg = re.sub('<[^<]+?>', '', msg)
                messages.add_message(request, messages.ERROR, msg)
                if request.GET.get('Ajax') == '1':
                    return HttpResponse('OK')
                return HttpResponseRedirect('/docs/view/%s/' % doc.pk)

        else:
            form = UploadFileForm()

        return render(request, 'docs/file.html', {'docid': doc, 'layout': 'horizontal', 'form': form})

    elif mode == 'delfile':
        file = docs_files.objects.get(pk=request.GET['fileid'], doc=doc)
        file.delete(user=request.user)

        #add_history(request, tic, 8, file.name)

        return HttpResponseRedirect('/docs/view/%s/#files' % doc.pk)
Ejemplo n.º 10
0
def action(request, mode, ticket):
    mod_path, cls_name = settings.TICKET_CLASS.rsplit('.', 1)
    mod_path = mod_path.split('.').pop(0)
    tic = get_model(mod_path, cls_name).objects.get(pk=ticket)

    if mode == 'view':
        if request.method == 'POST':
            form = CommentForm(request.POST)
            if form.is_valid():
                com = tickets_comments()
                com.comment = form.cleaned_data['comment']
                com.ticket_id = ticket
                com.action = 6
                com.save(user=request.user)

                check_references(request, com)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 6, com.comment)

                mail_comment(request, com.pk)

            else:
                if 'resolution' in request.POST:
                    if request.POST['resolution'] and int(request.POST['resolution']) > 0:
                        tic.resolution_id = request.POST['resolution']
                        tic.closed = True
                        tic.close_date = datetime.datetime.now()
                        tic.state = get_flow_end()
                        tic.save(user=request.user)

                        com = tickets_comments()
                        com.comment = _('ticket closed - resolution: %(resolution)s\n\n%(comment)s') % {'resolution': ticket_resolution.objects.get(pk=request.POST['resolution']).name, 'comment': request.POST.get('close_comment', '')}
                        com.ticket_id = ticket
                        com.action = 1
                        com.save(user=request.user)

                        check_references(request, com)

                        touch_ticket(request.user, ticket)

                        add_history(request, tic, 1, request.POST.get('close_comment', ''))

                        mail_comment(request, com.pk)

                    else:
                        messages.add_message(request, messages.ERROR, _('no resolution selected'))

                else:
                    messages.add_message(request, messages.ERROR, _('comment invalid'))

        excludes = []
        form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id, view_only=True)
        close = TicketCloseForm()
        reassign = TicketReassignForm(initial={'assigned': tic.assigned_id, 'state': tic.state})
        flows = list(ticket_flow_edges.objects.select_related('next').filter(now=tic.state).exclude(next__type=2).values_list('next', flat=True))
        flows.append(tic.state_id)
        reassign.fields['state'].queryset = reassign.fields['state'].queryset.filter(id__in=flows)

        participants = tickets_participants.objects.select_related('user').filter(ticket=ticket)
        comments = tickets_comments.objects.select_related('c_user').filter(ticket=ticket).order_by('c_date')

        close_allowed = ticket_flow_edges.objects.select_related('next').filter(now=tic.state, next__type=2).count() > 0

        files = tickets_files.objects.filter(ticket=ticket)
        paginator = Paginator(files, 10)
        page = request.GET.get('page')
        try:
            files_lines = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            files_lines = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            files_lines = paginator.page(paginator.num_pages)

        add_breadcrumbs(request, ticket, '#')

        return render_to_response('tickets/view.html', {'layout': 'horizontal', 'ticket': tic, 'form': form, 'close': close, 'reassign': reassign, 'files': files_lines, 'comments': comments, 'participants': participants, 'close_allowed': close_allowed}, RequestContext(request))

    elif mode == 'history':
        history = tickets_history.objects.filter(ticket=ticket)
        return render_to_response('tickets/history.html', {'layout': 'horizontal', 'ticket': tic, 'history': history}, RequestContext(request))

    elif mode == 'reopen':
        if tic.closed:
            tic.closed = False
            tic.state = get_flow_start()
            tic.resolution = None
            tic.close_date = None
            tic.save(user=request.user)

            com = tickets_comments()
            com.comment = _('ticket reopend - resolution deleted')
            com.ticket_id = ticket
            com.action = 2
            com.save(user=request.user)

            check_references(request, com)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 2, None)

            mail_comment(request, com.pk)

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'reassign':
        if not tic.closed:
            if 'assigned' in request.POST:
                if request.POST['assigned'] and int(request.POST['assigned']) > 0:
                    old_assigned_user = tic.assigned
                    old_state = tic.state

                    tic.assigned_id = request.POST['assigned']
                    tic.state = ticket_flow.objects.get(pk=request.POST['state'])
                    tic.save(user=request.user)

                    newUser = User.objects.get(pk=request.POST['assigned'])

                    com = tickets_comments()
                    com.comment = _('ticket reassigned to %(user)s\nstate now: %(state)s\n\n%(comment)s') % {'user': newUser, 'comment': request.POST.get('reassign_comment', ''), 'state': tic.state}
                    com.ticket_id = ticket
                    com.action = 7
                    com.save(user=request.user)

                    check_references(request, com)

                    touch_ticket(request.user, ticket)
                    if request.POST['assigned']:
                        touch_ticket(newUser, ticket)

                    history_data = {
                                    'old': {'comment': '', 'assigned': str(old_assigned_user), 'state': str(old_state)},
                                    'new': {'comment': request.POST.get('reassign_comment', ''), 'assigned': str(User.objects.get(pk=request.POST['assigned'])), 'state': str(tic.state)}
                                    }
                    add_history(request, tic, 7, history_data)

                    mail_comment(request, com.pk)
                else:
                    messages.add_message(request, messages.ERROR, _('missing assigned user'))

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'edit':
        excludes = ['resolution']
        if request.method == 'POST':
            form = TicketsForm(request.POST, exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id)
            if form.is_valid():
                tic = form.save()

                assigned = form.cleaned_data.get('assigned')
                if assigned:
                    touch_ticket(assigned, tic.pk)

                remember_changes(request, form, tic)

                touch_ticket(request.user, tic.pk)

                mail_ticket(request, tic.pk, form)

                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        else:
            form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id)
        if 'state' in form.fields:
            form.fields['state'].queryset = form.fields['state'].queryset.exclude(type=2)
        return render_to_response('tickets/edit.html', {'ticket': tic, 'layout': 'horizontal', 'form': form}, RequestContext(request))

    elif mode == 'download':
        fileid = request.GET.get('file', -1)
        file_data = tickets_files.objects.get(id=fileid, ticket=ticket)
        src = '%s%s.dat' % (settings.FILE_UPLOAD_PATH, fileid)

        if request.GET.get('resize', 'no') == 'yes' and 'image' in file_data.content_type:
            img = resize_image('%s' % (src), (200, 150), 75)
            output = io.BytesIO()
            img.save(output, 'PNG')
            output.seek(0)
            response = StreamingHttpResponse(output, mimetype=smart_str(file_data.content_type))

        else:
            response = StreamingHttpResponse(open('%s' % (src),"rb"), mimetype=smart_str(file_data.content_type))
        response['Content-Disposition'] = 'attachment;filename=%s' % smart_str(file_data.name)
        return response

    elif mode == 'upload':
        if request.method == 'POST':
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                f = tickets_files()
                f.name = request.FILES['file'].name
                f.size = request.FILES['file'].size
                f.content_type = request.FILES['file'].content_type
                f.ticket_id = ticket
                f.public = True
                f.save(user=request.user)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 5, request.FILES['file'].name)

                mail_file(request, f.pk)

                dest = settings.FILE_UPLOAD_PATH
                if not os.path.exists(dest):
                    os.makedirs(dest)

                with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                    for chunk in request.FILES['file'].chunks():
                        destination.write(chunk)

                return HttpResponseRedirect('/tickets/view/%s/' % tic.pk)
        else:
            form = UploadFileForm()

        return render_to_response('tickets/file.html', {'ticketid': ticket, 'layout': 'horizontal', 'form': form}, RequestContext(request))
Ejemplo n.º 11
0
def show_board(request, name):
    # http://bootsnipp.com/snippets/featured/kanban-board

    """
        board structure

        [
            {
                'column': 'closed',
                'query': {'closed': False},
                'limit': 10,
                'extra_filter': 1, # 1 = days since closed, 2 = days since created, 3 = days since last changed, 4 days since last action
                'days': 1, # days
                'order_by': 'id',
                'order_dir': ''
            }
        ]
    """

    if request.method == 'POST':
        if 'method' in request.POST:
            board = boards.objects.get(active_record=True, pk=request.POST['board'], c_user=request.user)
            try:
                columns = json.loads(board.columns)
            except:
                columns = []

            if request.POST['method'] == 'add':
                form = AddToBordForm(request.POST)
                if form.is_valid():
                    cd = form.cleaned_data
                    col = {
                           'column': cd['column'],
                           'query': request.session['last_search'],
                           'limit': cd['limit'],
                           'order_by': cd['order_by'],
                           'order_dir': cd['order_dir']
                           }
                    if cd.get('extra_filter') and cd.get('days'):
                        col['extra_filter'] = cd['extra_filter']
                        col['days'] = cd['days']
                    columns.append(col)
                    board.columns = json.dumps(columns, cls=DjangoJSONEncoder)
                    board.save(user=request.user)

                else:
                    err_list = []
                    for field in form:
                        for err in field.errors:
                            err_list.append('%s: %s' % (field.name, err))
                    messages.add_message(request, messages.ERROR, _('data invalid: %s') % '\n'.join(err_list))

                return HttpResponseRedirect('/board/%s/' % urlquote_plus(board.name))

        else:
            if request.POST['boardname'].strip() != '':
                if boards.objects.filter(active_record=True, c_user=request.user, name=request.POST['boardname']).count() == 0 and request.POST['boardname']:
                        board = boards()
                        board.name = request.POST['boardname'].strip()
                        board.save(user=request.user)

                        return HttpResponseRedirect('/board/%s/' % urlquote_plus(request.POST['boardname']))

                else:
                    messages.add_message(request, messages.ERROR, _(u'A board with the name "%s" already exists' % request.POST['boardname']))
                    return HttpResponseRedirect('/')
            else:
                messages.add_message(request, messages.ERROR, _(u'No name for a board given'))
                return HttpResponseRedirect('/')

    else:
        board = boards.objects.get(active_record=True, name=name, c_user=request.user)
        try:
            columns = json.loads(board.columns)
        except:
            columns = []

        if 'method' in request.GET and request.GET['method'] == 'del':
            new_columns = []
            for col in columns:
                if col['column'] != request.GET['column']:
                    new_columns.append(col)
            board.columns = json.dumps(new_columns, cls=DjangoJSONEncoder)
            board.save(user=request.user)

            return HttpResponseRedirect('/board/%s/' % urlquote_plus(name))

        elif 'method' in request.GET and request.GET['method'] == 'delete':
            board.delete(user=request.user)
            return HttpResponseRedirect('/')

    for column in columns:
        query = get_ticket_model().objects.select_related('type', 'state', 'assigned', 'priority', 'customer').all()
        search_params, query = build_ticket_search_ext(request, query, column['query'])
        column['query'] = query.order_by('%s%s' % (column.get('order_dir', ''), column.get('order_by', 'id')))
        if 'extra_filter' in column and 'days' in column and column['extra_filter'] and column['days']:
            if column['extra_filter'] == '1':  # days since closed
                column['query'] = column['query'].filter(close_date__gte=datetime.date.today() - datetime.timedelta(days=column['days'])).exclude(close_date=None)
            if column['extra_filter'] == '2':  # days since created
                column['query'] = column['query'].filter(c_date__gte=datetime.date.today() - datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '3':  # days since last changed
                column['query'] = column['query'].filter(u_date__gte=datetime.date.today() - datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '4':  # days since last action
                column['query'] = column['query'].filter(last_action_date__gte=datetime.date.today() - datetime.timedelta(days=column['days']))
        if not request.user.is_staff:
            column['query'] = column['query'].filter(customer=request.organisation)

        seen_elements = {}
        seen = tickets_participants.objects.filter(user=request.user, ticket__in=column['query'].values_list('id', flat=True)).values_list('ticket_id', 'seen')
        for see in seen:
            seen_elements[see[0]] = see[1]

        seen = tickets_ignorants.objects.filter(user=request.user, ticket__in=column['query'].values_list('id', flat=True)).values_list('ticket_id')
        for see in seen:
            seen_elements[see[0]] = True

        if column['limit']:
            column['query'] = column['query'][:column['limit']]
        column['seen'] = seen_elements

    add_breadcrumbs(request, board.pk, '$')
    return render(request, 'board/view.html', {'columns': columns, 'board': board})
Ejemplo n.º 12
0
def show_board(request, name):
    # http://bootsnipp.com/snippets/featured/kanban-board
    """
        board structure
        
        [
            {
                'column': 'closed',
                'query': {'closed': False},
                'limit': 10,
                'extra_filter': 1, # 1 = days since closed, 2 = days since created, 3 = days since last changed, 4 days since last action
                'days': 1, # days
                'order_by': 'id',
                'order_dir': ''
            }
        ]
    """

    if request.method == 'POST':
        if 'method' in request.POST:
            board = boards.objects.get(pk=request.POST['board'],
                                       c_user=request.user)
            try:
                columns = json.loads(board.columns)
            except:
                columns = []

            if request.POST['method'] == 'add':
                form = AddToBordForm(request.POST)
                if form.is_valid():
                    cd = form.cleaned_data
                    col = {
                        'column': cd['column'],
                        'query': request.session['last_search'],
                        'limit': cd['limit'],
                        'order_by': cd['order_by'],
                        'order_dir': cd['order_dir']
                    }
                    if cd.get('extra_filter') and cd.get('days'):
                        col['extra_filter'] = cd['extra_filter']
                        col['days'] = cd['days']
                    columns.append(col)
                    board.columns = json.dumps(columns, cls=DjangoJSONEncoder)
                    board.save(user=request.user)

                else:
                    err_list = []
                    for field in form:
                        for err in field.errors:
                            err_list.append('%s: %s' % (field.name, err))
                    messages.add_message(
                        request, messages.ERROR,
                        _('data invalid: %s') % '\n'.join(err_list))

                return HttpResponseRedirect('/board/%s/' %
                                            urlquote_plus(board.name))

        else:
            board = boards()
            board.name = request.POST['boardname']
            board.save(user=request.user)

            return HttpResponseRedirect(
                '/board/%s/' % urlquote_plus(request.POST['boardname']))

    else:
        board = boards.objects.get(name=name, c_user=request.user)
        try:
            columns = json.loads(board.columns)
        except:
            columns = []

        if 'method' in request.GET and request.GET['method'] == 'del':
            new_columns = []
            for col in columns:
                if col['column'] != request.GET['column']:
                    new_columns.append(col)
            board.columns = json.dumps(new_columns, cls=DjangoJSONEncoder)
            board.save(user=request.user)

            return HttpResponseRedirect('/board/%s/' % urlquote_plus(name))

    for column in columns:
        column['query'] = get_ticket_model().objects.select_related(
            'priority').filter(**column['query']).order_by(
                '%s%s' %
                (column.get('order_dir', ''), column.get('order_by', 'id')))
        if column['limit']:
            column['query'] = column['query'][:column['limit']]
        if 'extra_filter' in column and 'days' in column and column[
                'extra_filter'] and column['days']:
            print type(column['extra_filter'])
            if column['extra_filter'] == '1':  # days since closed
                column['query'] = column['query'].filter(
                    close_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days'])).exclude(
                        close_date=None)
            if column['extra_filter'] == '2':  # days since created
                column['query'] = column['query'].filter(
                    c_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '3':  # days since last changed
                column['query'] = column['query'].filter(
                    u_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '4':  # days since last action
                column['query'] = column['query'].filter(
                    last_action_date__gte=datetime.date.today() -
                    datetime.timedelta(days=column['days']))

    add_breadcrumbs(request, board.pk, '$')
    return render_to_response('board/view.html', {
        'columns': columns,
        'board': board
    }, RequestContext(request))
Ejemplo n.º 13
0
def action(request, mode, ticket):
    mod_path, cls_name = settings.TICKET_CLASS.rsplit('.', 1)
    mod_path = mod_path.split('.').pop(0)
    tic = apps.get_model(mod_path, cls_name).objects.get(pk=ticket)

    if hasattr(settings, 'KEEP_IT_SIMPLE') and settings.KEEP_IT_SIMPLE:
        keep_it_simple = True
    else:
        keep_it_simple = False

    if mode == 'view':
        if request.method == 'POST':
            form = CommentForm(request.POST)
            if form.is_valid():
                com = tickets_comments()
                com.comment = form.cleaned_data['comment']
                com.ticket_id = ticket
                com.action = 6
                com.save(user=request.user)

                check_references(request, com)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 6, com.comment)

                mail_comment(request, com.pk)

            else:
                if 'resolution' in request.POST:
                    if request.POST['resolution'] and int(request.POST['resolution']) > 0:
                        tic.resolution_id = request.POST['resolution']
                        tic.closed = True
                        tic.close_date = timezone.now()
                        tic.state = get_flow_end()
                        tic.save(user=request.user)

                        com = tickets_comments()
                        com.comment = _('ticket closed - resolution: %(resolution)s\n\n%(comment)s') % {'resolution': ticket_resolution.objects.get(pk=request.POST['resolution']).name, 'comment': request.POST.get('close_comment', '')}
                        com.ticket_id = ticket
                        com.action = 1
                        com.save(user=request.user)

                        check_references(request, com)

                        touch_ticket(request.user, ticket)

                        add_history(request, tic, 1, request.POST.get('close_comment', ''))

                        mail_comment(request, com.pk)

                    else:
                        messages.add_message(request, messages.ERROR, _('no resolution selected'))

                else:
                    messages.add_message(request, messages.ERROR, _('comment invalid'))

        excludes = []
        form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id, view_only=True)
        close = TicketCloseForm()
        reassign = TicketReassignForm(initial={'assigned': tic.assigned_id, 'state': tic.state})
        flows = list(ticket_flow_edges.objects.select_related('next').filter(now=tic.state).exclude(next__type=2).values_list('next', flat=True))
        flows.append(tic.state_id)
        reassign.fields['state'].queryset = reassign.fields['state'].queryset.filter(id__in=flows)

        participants = tickets_participants.objects.select_related('user').filter(ticket=ticket)
        comments = tickets_comments.objects.select_related('c_user').filter(ticket=ticket).order_by('c_date')

        close_allowed = ticket_flow_edges.objects.select_related('next').filter(now=tic.state, next__type=2).count() > 0

        files = tickets_files.objects.filter(ticket=ticket, active_record=True)
        paginator = Paginator(files, 10)
        page = request.GET.get('page')
        try:
            files_lines = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            files_lines = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            files_lines = paginator.page(paginator.num_pages)

        add_breadcrumbs(request, ticket, '#')
        if 'YATSE' in request.GET and 'isUsingYATSE' not in request.session:
            request.session['isUsingYATSE'] = True

        return render(request, 'tickets/view.html', {'layout': 'horizontal', 'ticket': tic, 'form': form, 'close': close, 'reassign': reassign, 'files': files_lines, 'comments': comments, 'participants': participants, 'close_allowed': close_allowed, 'keep_it_simple': keep_it_simple})

    elif mode == 'history':
        history = tickets_history.objects.filter(ticket=ticket)
        return render(request, 'tickets/history.html', {'layout': 'horizontal', 'ticket': tic, 'history': history, 'keep_it_simple': keep_it_simple})

    elif mode == 'reopen':
        if tic.closed:
            tic.closed = False
            tic.state = get_flow_start()
            tic.resolution = None
            tic.close_date = None
            tic.save(user=request.user)

            com = tickets_comments()
            com.comment = _('ticket reopend - resolution deleted')
            com.ticket_id = ticket
            com.action = 2
            com.save(user=request.user)

            check_references(request, com)

            touch_ticket(request.user, ticket)

            add_history(request, tic, 2, None)

            mail_comment(request, com.pk)

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'reassign':
        if not tic.closed:
            if 'assigned' in request.POST:
                if request.POST['assigned'] and int(request.POST['assigned']) > 0:
                    old_assigned_user = tic.assigned
                    old_state = tic.state

                    tic.assigned_id = request.POST['assigned']
                    tic.state = ticket_flow.objects.get(pk=request.POST['state'])
                    tic.save(user=request.user)

                    newUser = User.objects.get(pk=request.POST['assigned'])

                    com = tickets_comments()
                    com.comment = _('ticket reassigned to %(user)s\nstate now: %(state)s\n\n%(comment)s') % {'user': newUser, 'comment': request.POST.get('reassign_comment', ''), 'state': tic.state}
                    com.ticket_id = ticket
                    com.action = 7
                    com.save(user=request.user)

                    check_references(request, com)

                    touch_ticket(request.user, ticket)
                    if request.POST['assigned']:
                        touch_ticket(newUser, ticket)

                    history_data = {
                                    'old': {'comment': '', 'assigned': str(old_assigned_user), 'state': str(old_state)},
                                    'new': {'comment': request.POST.get('reassign_comment', ''), 'assigned': str(User.objects.get(pk=request.POST['assigned'])), 'state': str(tic.state)}
                                    }
                    add_history(request, tic, 7, history_data)

                    mail_comment(request, com.pk)
                else:
                    messages.add_message(request, messages.ERROR, _('missing assigned user'))

        return HttpResponseRedirect('/tickets/view/%s/' % ticket)

    elif mode == 'edit' or (mode == 'simple' and (not tic.keep_it_simple or tic.closed) and keep_it_simple):
        excludes = ['resolution']
        if request.method == 'POST':
            form = TicketsForm(request.POST, exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id)
            if form.is_valid():
                tic = form.save()

                if tic.keep_it_simple:
                    tic.keep_it_simple = False
                    tic.save(user=request.user)

                assigned = form.cleaned_data.get('assigned')
                if assigned:
                    touch_ticket(assigned, tic.pk)

                remember_changes(request, form, tic)

                touch_ticket(request.user, tic.pk)

                mail_ticket(request, tic.pk, form)

                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        else:
            form = TicketsForm(exclude_list=excludes, is_stuff=request.user.is_staff, user=request.user, instance=tic, customer=request.organisation.id)
        if 'state' in form.fields:
            form.fields['state'].queryset = form.fields['state'].queryset.exclude(type=2)
        return render(request, 'tickets/edit.html', {'ticket': tic, 'layout': 'horizontal', 'form': form})

    elif mode == 'simple':
        if request.method == 'POST':
            form = SimpleTickets(request.POST, initial={
                    'caption': tic.caption,
                    'description': tic.description,
                    'priority': tic.priority,
                    'assigned': tic.assigned
                })
            if form.is_valid():
                cd = form.cleaned_data
                tic.caption = cd['caption']
                tic.description = cd['description']
                tic.priority = cd['priority']
                tic.assigned = cd['assigned']
                tic.deadline = cd['deadline']
                tic.save(user=request.user)

                if cd['assigned']:
                    touch_ticket(cd['assigned'], tic.pk)

                remember_changes(request, form, tic)

                touch_ticket(request.user, tic.pk)

                mail_ticket(request, tic.pk, form)

                return HttpResponseRedirect('/tickets/view/%s/' % ticket)

        else:
            form = SimpleTickets(initial={
                    'caption': tic.caption,
                    'description': tic.description,
                    'priority': tic.priority,
                    'assigned': tic.assigned,
                    'deadline': tic.deadline,
                })
        return render(request, 'tickets/edit.html', {'ticket': tic, 'layout': 'horizontal', 'form': form, 'mode': mode})

    elif mode == 'download':
        fileid = request.GET.get('file', -1)
        file_data = tickets_files.objects.get(id=fileid, ticket=ticket)
        src = '%s%s.dat' % (settings.FILE_UPLOAD_PATH, fileid)
        content_type = file_data.content_type
        if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)):
            src = '%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)
            content_type = 'imgae/png'

        if request.GET.get('resize', 'no') == 'yes' and ('image' in file_data.content_type or 'pdf' in file_data.content_type):
            img = resize_image('%s' % (src), (200, 150), 75)
            output = io.BytesIO()
            img.save(output, 'PNG')
            output.seek(0)
            response = StreamingHttpResponse(output, content_type='image/png')

        else:
            response = StreamingHttpResponse(open('%s' % (src), "rb"), content_type=content_type)

        if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (settings.FILE_UPLOAD_PATH, fileid)):
            response['Content-Disposition'] = 'attachment;filename=%s' % content_type
        else:
            response['Content-Disposition'] = 'attachment;filename=%s' % smart_str(file_data.name)
        return response

    elif mode == 'upload':
        if request.method == 'POST':
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                if tickets_files.objects.filter(active_record=True, ticket=ticket, checksum=request.FILES['file'].hash).count() > 0:
                    messages.add_message(request, messages.ERROR, _('File already exists: %s') % request.FILES['file'].name)
                    if request.GET.get('Ajax') == '1':
                        return HttpResponse('OK')
                    return HttpResponseRedirect('/tickets/view/%s/' % ticket)
                f = tickets_files()
                f.name = request.FILES['file'].name
                f.size = request.FILES['file'].size
                f.checksum = request.FILES['file'].hash
                f.content_type = request.FILES['file'].content_type
                f.ticket_id = ticket
                f.public = True
                f.save(user=request.user)

                touch_ticket(request.user, ticket)

                add_history(request, tic, 5, request.FILES['file'].name)

                mail_file(request, f.pk)

                dest = settings.FILE_UPLOAD_PATH
                if not os.path.exists(dest):
                    os.makedirs(dest)

                with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                    for chunk in request.FILES['file'].chunks():
                        destination.write(chunk)

                if 'pdf' in f.content_type:
                    convertPDFtoImg('%s/%s.dat' % (dest, f.id), '%s/%s.preview' % (dest, f.id))
                else:
                    if 'image' not in f.content_type:
                        tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id))
                        convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id))
                        os.unlink(tmp)

                return HttpResponseRedirect('/tickets/view/%s/' % tic.pk)

            else:
                msg = unicode(form.errors['file'])
                msg = re.sub('<[^<]+?>', '', msg)
                messages.add_message(request, messages.ERROR, msg)
                if request.GET.get('Ajax') == '1':
                    return HttpResponse('OK')
                return HttpResponseRedirect('/tickets/view/%s/' % ticket)
        else:
            form = UploadFileForm()

        return render(request, 'tickets/file.html', {'ticketid': ticket, 'layout': 'horizontal', 'form': form})

    elif mode == 'delfile':
        file = tickets_files.objects.get(pk=request.GET['fileid'], ticket=ticket)
        file.delete(user=request.user)

        touch_ticket(request.user, ticket)

        add_history(request, tic, 8, file.name)

        return HttpResponseRedirect('/tickets/view/%s/#files' % tic.pk)

    elif mode == 'remove':
            del_breadcrumbs(request)

            return HttpResponse('OK')
Ejemplo n.º 14
0
def docs_action(request, mode, docid):
    doc = docs.objects.get(pk=docid)
    if mode == 'view':
        form = DocsForm(user=request.user, instance=doc, view_only=True)
        add_breadcrumbs(request, docid, '*', caption=doc.caption[:20])

        files = docs_files.objects.filter(doc=doc, active_record=True)
        paginator = Paginator(files, 10)
        page = request.GET.get('page')
        try:
            files_lines = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            files_lines = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            files_lines = paginator.page(paginator.num_pages)

        return render(request, 'docs/view.html', {'layout': 'horizontal', 'form': form, 'doc': doc, 'files': files_lines})

    elif mode == 'edit':
        if request.method == 'POST':
            form = DocsForm(request.POST, user=request.user, instance=doc)
            if form.is_valid():
                doc = form.save()
                return HttpResponseRedirect('/docs/view/%s/' % doc.pk)

        form = DocsForm(user=request.user, instance=doc)
        return render(request, 'docs/edit.html', {'layout': 'horizontal', 'form': form, 'doc': doc})

    elif mode == 'delete':
        doc.delete(user=request.user)
        return HttpResponseRedirect('/search/?q=%s&models=yats.docs&models=web.test' % request.session.get('last_fulltextsearch', '*'))

    elif mode == 'ticket':
        ticket = get_ticket_model()
        tic = ticket()
        tic.caption = doc.caption
        tic.description = doc.text
        if hasattr(settings, 'KEEP_IT_SIMPLE_DEFAULT_CUSTOMER') and settings.KEEP_IT_SIMPLE_DEFAULT_CUSTOMER:
            if settings.KEEP_IT_SIMPLE_DEFAULT_CUSTOMER == -1:
                tic.customer = request.organisation
            else:
                tic.customer_id = settings.KEEP_IT_SIMPLE_DEFAULT_CUSTOME
        if not tic.component_id and hasattr(settings, 'KEEP_IT_SIMPLE_DEFAULT_COMPONENT') and settings.KEEP_IT_SIMPLE_DEFAULT_COMPONENT:
            tic.component_id = settings.KEEP_IT_SIMPLE_DEFAULT_COMPONENT
        tic.save(user=request.user)

        # add ref to doc
        com = tickets_comments()
        com.comment = _('see §%s') % doc.pk
        com.ticket_id = tic
        com.action = 3
        com.save(user=request.user)

        add_breadcrumbs(request, str(tic.pk), '#', caption=tic.caption[:20])

        if hasattr(settings, 'KEEP_IT_SIMPLE') and settings.KEEP_IT_SIMPLE:
            return HttpResponseRedirect('/tickets/simple/%s/' % tic.pk)
        else:
            return HttpResponseRedirect('/tickets/edit/%s/' % tic.pk)

    elif mode == 'download':
        fileid = request.GET.get('file', -1)
        file_data = docs_files.objects.get(id=fileid, doc=doc)
        src = '%s%s.dat' % (get_doc_files_folder(), fileid)
        content_type = file_data.content_type
        if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (get_doc_files_folder(), fileid)):
            src = '%s%s.preview' % (get_doc_files_folder(), fileid)
            content_type = 'imgae/png'

        if request.GET.get('resize', 'no') == 'yes' and ('image' in file_data.content_type or 'pdf' in file_data.content_type):
            img = resize_image('%s' % (src), (200, 150), 75)
            output = io.BytesIO()
            img.save(output, 'PNG')
            output.seek(0)
            response = StreamingHttpResponse(output, content_type='image/png')

        else:
            response = StreamingHttpResponse(open('%s' % (src), "rb"), content_type=content_type)

        if 'noDisposition' not in request.GET:
            if request.GET.get('preview') == 'yes' and os.path.isfile('%s%s.preview' % (get_doc_files_folder(), fileid)):
                response['Content-Disposition'] = 'attachment;filename=%s' % content_type
            else:
                response['Content-Disposition'] = 'attachment;filename=%s' % smart_str(file_data.name)
        return response

    elif mode == 'upload':
        if request.method == 'POST':
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                if docs_files.objects.filter(active_record=True, doc=doc, checksum=request.FILES['file'].hash).count() > 0:
                    messages.add_message(request, messages.ERROR, _('File already exists: %s') % request.FILES['file'].name)
                    if request.GET.get('Ajax') == '1':
                        return HttpResponse('OK')
                    return HttpResponseRedirect('/docs/view/%s/' % doc.id)
                f = docs_files()
                f.name = request.FILES['file'].name
                f.size = request.FILES['file'].size
                f.checksum = request.FILES['file'].hash
                f.content_type = request.FILES['file'].content_type
                f.doc_id = doc.id
                f.public = True
                f.save(user=request.user)

                #add_history(request, tic, 5, request.FILES['file'].name)

                dest = get_doc_files_folder()
                if not os.path.exists(dest):
                    os.makedirs(dest)

                with open('%s%s.dat' % (dest, f.id), 'wb+') as destination:
                    for chunk in request.FILES['file'].chunks():
                        destination.write(chunk)

                if 'pdf' in f.content_type:
                    convertPDFtoImg('%s/%s.dat' % (dest, f.id), '%s/%s.preview' % (dest, f.id))
                else:
                    if 'image' not in f.content_type and isPreviewable(f.content_type):
                        tmp = convertOfficeTpPDF('%s/%s.dat' % (dest, f.id))
                        convertPDFtoImg(tmp, '%s/%s.preview' % (dest, f.id))
                        if os.path.isfile(tmp):
                            os.unlink(tmp)

                return HttpResponseRedirect('/docs/view/%s/' % doc.pk)

            else:
                msg = unicode(form.errors['file'])
                msg = re.sub('<[^<]+?>', '', msg)
                messages.add_message(request, messages.ERROR, msg)
                if request.GET.get('Ajax') == '1':
                    return HttpResponse('OK')
                return HttpResponseRedirect('/docs/view/%s/' % doc.pk)

        else:
            form = UploadFileForm()

        return render(request, 'docs/file.html', {'docid': doc, 'layout': 'horizontal', 'form': form})

    elif mode == 'delfile':
        file = docs_files.objects.get(pk=request.GET['fileid'], doc=doc)
        file.delete(user=request.user)

        #add_history(request, tic, 8, file.name)

        return HttpResponseRedirect('/docs/view/%s/#files' % doc.pk)
Ejemplo n.º 15
0
def show_board(request, name):
    # http://bootsnipp.com/snippets/featured/kanban-board
    
    """
        board structure
        
        [
            {
                'column': 'closed',
                'query': {'closed': False},
                'limit': 10,
                'extra_filter': 1, # 1 = days since closed, 2 = days since created, 3 = days since last changed, 4 days since last action
                'days': 1, # days
                'order_by': 'id',
                'order_dir': ''
            }
        ]
    """
    
    if request.method == 'POST':
        if 'method' in request.POST:
            board = boards.objects.get(pk=request.POST['board'], c_user=request.user)
            try:
                columns = json.loads(board.columns)
            except:
                columns = []

            if request.POST['method'] == 'add':
                form = AddToBordForm(request.POST)
                if form.is_valid():
                    cd = form.cleaned_data 
                    col = {
                           'column': cd['column'],
                           'query': request.session['last_search'],
                           'limit': cd['limit'],
                           'order_by': cd['order_by'],
                           'order_dir': cd['order_dir']
                           }
                    if cd.get('extra_filter') and cd.get('days'):
                        col['extra_filter'] = cd['extra_filter']
                        col['days'] = cd['days']
                    columns.append(col)
                    board.columns = json.dumps(columns, cls=DjangoJSONEncoder)
                    board.save(user=request.user)
                
                else:
                    err_list = []
                    for field in form:
                        for err in field.errors:
                            err_list.append('%s: %s' % (field.name, err))
                    messages.add_message(request, messages.ERROR, _('data invalid: %s') % '\n'.join(err_list))
                
                return HttpResponseRedirect('/board/%s/' % urlquote_plus(board.name))
                
        else:
            board = boards()
            board.name = request.POST['boardname']
            board.save(user=request.user)
            
            return HttpResponseRedirect('/board/%s/' % urlquote_plus(request.POST['boardname']))
    
    else:
        board = boards.objects.get(name=name, c_user=request.user)
        try:
            columns = json.loads(board.columns)
        except:
            columns = []

        if 'method' in request.GET and request.GET['method'] == 'del':
            new_columns = []
            for col in columns:
                if col['column'] != request.GET['column']:
                    new_columns.append(col)
            board.columns = json.dumps(new_columns, cls=DjangoJSONEncoder)
            board.save(user=request.user)
            
            return HttpResponseRedirect('/board/%s/' % urlquote_plus(name))
            
    for column in columns:
        column['query'] = get_ticket_model().objects.select_related('priority').filter(**column['query']).order_by('%s%s' % (column.get('order_dir', ''), column.get('order_by', 'id')))
        if column['limit']:
            column['query'] = column['query'][:column['limit']]
        if 'extra_filter' in column and 'days' in column and column['extra_filter'] and column['days']:
            print type(column['extra_filter']) 
            if column['extra_filter'] == '1': # days since closed
                column['query'] = column['query'].filter(close_date__gte=datetime.date.today() - datetime.timedelta(days=column['days'])).exclude(close_date=None)
            if column['extra_filter'] == '2': # days since created
                column['query'] = column['query'].filter(c_date__gte=datetime.date.today() - datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '3': # days since last changed
                column['query'] = column['query'].filter(u_date__gte=datetime.date.today() - datetime.timedelta(days=column['days']))
            if column['extra_filter'] == '4': # days since last action
                column['query'] = column['query'].filter(last_action_date__gte=datetime.date.today() - datetime.timedelta(days=column['days']))
        
    add_breadcrumbs(request, board.pk, '$')
    return render_to_response('board/view.html', {'columns': columns, 'board': board}, RequestContext(request))