Edgewall Software

Version 10 (modified by Ryan J Ollos, 4 years ago) ( diff )

Modify in response to gmessage:trac-users:MNvfBPbiAS0/AgrNxg40BgAJ.

Signed Tickets

Some projects require a special workflow where tickets can be signed.

This recipe shows steps to implement various aspects of such a feature using a combination of configuration, existing plugins and a small custom permission policy containing the authorization rules.


  1. Users with TICKET_SIGN permission can sign tickets.
  2. Signed tickets are considered closed with resolution signed.
  3. Signed tickets are read only, except to users with TICKET_ADMIN permission.
  4. Signed tickets are visually distinguished.


TICKET_SIGN permission

Enable the optional component ExtraPermissionsProvider and configure a new permission:

_perms = TICKET_SIGN

Signed Resolution

Add signed as a Resolution through the web admin page AdminTicket SystemResolutions (/admin/ticket/resolution), or using TracAdmin:

trac-admin $env resolution add signed

Sign workflow step

Configure your workflow adding a step to resolve as signed:

sign = new,assigned,accepted,reopened -> closed
sign.name = resolve
sign.permissions = TICKET_SIGN
sign.operations = set_resolution
sign.set_resolution = signed

You probably also want to configure the list of Resolutions for other actions with a set_resolution operation, so that the Signed resolution does not appear in the list.

resolve.set_resolution = fixed, invalid, wontfix, duplicate, worksforme

Readonly logic

Create a single file plugin that implements IPermissionPolicy:

# -*- coding: utf-8 -*-

from trac.core import *
from trac.perm import IPermissionPolicy
from trac.ticket.model import Ticket

class ReadonlySignedTickets(Component):


    allowed_actions = ('TICKET_VIEW',)

    def check_permission(self, action, username, resource, perm):
        if resource is None or resource.realm != 'ticket' or \
                resource.id is None or \
                action in self.allowed_actions or \
                action in ('TICKET_ADMIN', 'TRAC_ADMIN') or \
                'TICKET_ADMIN' in perm:
            return None

        t = Ticket(self.env, resource.id)
        if t['status'] == 'closed' and t['resolution'] == 'signed':
            return False

Edit the permission_policies option in the [trac] section of trac.ini, adding the component before the default permission policy:

permission_policies = ReadonlySignedTickets, ...

Visual indication

  1. Install th:ContextChromePlugin#TicketcolorbyType and enable it:
    contextchrome.style.typeclasstoticket = enabled
  2. Configure it to decorate based on the ticket's resolution:
    decorate_fields = resolution
  3. Add site.html (the first code snippet in that section) to your Environment templates directory.
  4. Add style.css to your Environment htdocs directory. Add CSS using the selector body.resolution_is_signed. For example:
    body.resolution_is_signed {
        background: #f5deb3 url(signed.png);
  5. Add signed.png to the htdocs directory.


Allow ticket comments

Additional permissions can be specified in allowed_actions. If you wish to allow commenting on signed tickets, add TICKET_APPEND to the allowed_actions:

    allowed_actions = ('TICKET_VIEW', 'TICKET_APPEND')

Status instead of resolution

If you want to use a signed status instead of a resolution, change the last two lines of code to:

         # ...
        if t['status'] == 'signed':
            return False

And change the workflow step to:

sign = closed -> signed
sign.permissions = TICKET_SIGN

And configure signed as an end state for milestone progress:

closed = closed,signed

Change resolution to status in the visual steps.

See original mailing list discussion

Attachments (1)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.