Example #1
0
def ticket_edit_POST(owner, name, ticket_id):
    tracker, _ = get_tracker(owner, name)
    if not tracker:
        abort(404)
    ticket, access = get_ticket(tracker, ticket_id)
    if not ticket:
        abort(404)
    if not TicketAccess.edit in access:
        abort(401)

    valid = Validation(request)
    title = valid.require("title", friendly_name="Title")
    desc = valid.optional("description")

    valid.expect(not title or 3 <= len(title) <= 2048,
                 "Title must be between 3 and 2048 characters.",
                 field="title")
    valid.expect(not desc or len(desc) < 16384,
                 "Description must be no more than 16384 characters.",
                 field="description")

    if not valid.ok:
        return render_template("edit_ticket.html",
                               tracker=tracker,
                               ticket=ticket,
                               **valid.kwargs)

    ticket.title = title
    ticket.description = desc
    db.session.commit()

    return redirect(ticket_url(ticket))
Example #2
0
def test_mark_seen(client):
    ticket = TicketFactory()
    user = UserFactory()
    db.session.commit()

    url = ticket_url(ticket)

    query = TicketSeen.query.filter_by(user=user, ticket=ticket)
    assert query.count() == 0

    # Created on first visit
    with logged_in_as(user):
        response = client.get(url)
        assert response.status_code == 200

    first_time = query.one().last_view

    # Updated on second visit
    with logged_in_as(user):
        response = client.get(url)
        assert response.status_code == 200

    second_time = query.one().last_view

    assert second_time > first_time
Example #3
0
def ticket_remove_label(owner, name, ticket_id, label_id):
    tracker, _ = get_tracker(owner, name)
    if not tracker:
        abort(404)
    ticket, access = get_ticket(tracker, ticket_id)
    if not ticket:
        abort(404)
    if not TicketAccess.edit in access:
        abort(401)
    label = Label.query.filter(Label.id == label_id).first()
    if not label:
        abort(404)

    ticket_label = (TicketLabel.query.filter(
        TicketLabel.label_id == label_id).filter(
            TicketLabel.ticket_id == ticket.id)).first()

    if ticket_label:
        event = Event()
        event.event_type = EventType.label_removed
        event.user_id = current_user.id
        event.ticket_id = ticket.id
        event.label_id = label.id

        db.session.add(event)
        db.session.delete(ticket_label)
        db.session.commit()

    return redirect(ticket_url(ticket))
Example #4
0
def disable_notifications(owner, name, ticket_id):
    tracker, access = get_tracker(owner, name)
    if not tracker:
        abort(404)
    ticket, access = get_ticket(tracker, ticket_id)
    if not ticket:
        abort(404)

    sub = (TicketSubscription.query.filter(
        TicketSubscription.tracker_id == None).filter(
            TicketSubscription.ticket_id == ticket.id).filter(
                TicketSubscription.user_id == current_user.id)).one_or_none()

    if not sub:
        return redirect(ticket_url(ticket))

    db.session.delete(sub)
    db.session.commit()
    return redirect(ticket_url(ticket))
Example #5
0
def ticket_unassign(owner, name, ticket_id):
    valid = Validation(request)
    ticket = _assignment_get_ticket(owner, name, ticket_id)
    user = _assignment_get_user(valid)
    if not valid.ok:
        _, access = get_ticket(ticket.tracker, ticket_id)
        ctx = get_ticket_context(ticket, ticket.tracker, access)
        return render_template("ticket.html", valid, **ctx)

    unassign(ticket, user, current_user)
    db.session.commit()

    return redirect(ticket_url(ticket))
Example #6
0
def ticket_add_label(owner, name, ticket_id):
    tracker, _ = get_tracker(owner, name)
    if not tracker:
        abort(404)
    ticket, access = get_ticket(tracker, ticket_id)
    if not ticket:
        abort(404)
    if not TicketAccess.edit in access:
        abort(401)

    valid = Validation(request)
    label_id = valid.require("label_id", friendly_name="A label")
    if not valid.ok:
        ctx = get_ticket_context(ticket, tracker, access)
        return render_template("ticket.html", **ctx, **valid.kwargs)

    valid.expect(re.match(r"^\d+$", label_id),
                 "Label ID must be numeric",
                 field="label_id")
    if not valid.ok:
        ctx = get_ticket_context(ticket, tracker, access)
        return render_template("ticket.html", **ctx, **valid.kwargs)

    label_id = int(request.form.get('label_id'))
    label = Label.query.filter(Label.id == label_id).first()
    if not label:
        abort(404)

    ticket_label = (TicketLabel.query.filter(
        TicketLabel.label_id == label.id).filter(
            TicketLabel.ticket_id == ticket.id)).first()

    if not ticket_label:
        ticket_label = TicketLabel()
        ticket_label.ticket_id = ticket.id
        ticket_label.label_id = label.id
        ticket_label.user_id = current_user.id

        event = Event()
        event.event_type = EventType.label_added
        event.user_id = current_user.id
        event.ticket_id = ticket.id
        event.label_id = label.id

        db.session.add(ticket_label)
        db.session.add(event)
        db.session.commit()

    return redirect(ticket_url(ticket))
Example #7
0
def ticket_comment_POST(owner, name, ticket_id):
    tracker, access = get_tracker(owner, name)
    if not tracker:
        abort(404)
    ticket, access = get_ticket(tracker, ticket_id)
    if not ticket:
        abort(404)

    valid = Validation(request)
    text = valid.optional("comment")
    resolve = valid.optional("resolve")
    resolution = valid.optional("resolution")
    reopen = valid.optional("reopen")

    valid.expect(not text or 3 <= len(text) <= 16384,
                 "Comment must be between 3 and 16384 characters.",
                 field="comment")
    valid.expect(text or resolve or reopen,
                 "Comment is required",
                 field="comment")

    if (resolve or reopen) and TicketAccess.edit not in access:
        abort(403)

    if resolve:
        try:
            resolution = TicketResolution(int(resolution))
        except Exception as ex:
            abort(400, "Invalid resolution")
    else:
        resolution = None

    if not valid.ok:
        ctx = get_ticket_context(ticket, tracker, access)
        return render_template("ticket.html", **ctx, **valid.kwargs)

    comment = add_comment(current_user,
                          ticket,
                          text=text,
                          resolve=resolve,
                          resolution=resolution,
                          reopen=reopen)

    return redirect(ticket_url(ticket, comment))
Example #8
0
def notify_assignee(subscription, ticket, assigner, assignee):
    """
    Sends a notification email to the person who was assigned to the issue.
    """
    ticket_path = "{}/{}/#{}".format(ticket.tracker.owner.canonical_name,
                                     ticket.tracker.name, ticket.scoped_id)
    subject = "{}: {}".format(ticket_path, ticket.title)

    headers = {
        "From": "~{} <{}>".format(assigner.username, notify_from),
        "Sender": smtp_user,
    }

    context = {
        "assigner": assigner.canonical_name,
        "ticket_path": ticket_path,
        "ticket_url": ticket_url(ticket)
    }

    notify(subscription, "ticket_assigned", subject, headers, **context)
Example #9
0
def _send_comment_notification(subscription, ticket, user, comment,
                               resolution):
    subject = "Re: {}/{}/#{}: {}".format(ticket.tracker.owner.canonical_name,
                                         ticket.tracker.name, ticket.scoped_id,
                                         ticket.title)

    headers = {
        "From": "~{} <{}>".format(user.username, notify_from),
        "Sender": smtp_user,
    }

    url = ticket_url(ticket, comment=comment)

    notify(subscription,
           "ticket_comment",
           subject,
           headers=headers,
           ticket=ticket,
           comment=comment,
           resolution=resolution.name if resolution else None,
           ticket_url=url)