From Request Tracker Wiki
Jump to navigation Jump to search

Edit Attachment

Sometimes, it becomes difficult to follow a ticket because your users do top-posting or they have a disclamer of 2 pages. It's not in RT philosophy to change an Object after his creation, even if adding this modification as a transaction and a new version can be very useful. The hack presented here won't work if you are using GPG to sign messages.

First, add this CallBack


 / <% loc('Edit') %>
$AttachPath => RT->Config->Get('WebPath')."/Ticket/Attachment"
$message => $ARGS{Attachment}
$ticket => $ARGS{Ticket}
$trans => $ARGS{Transaction}

Then, add this module (You can limit this function to a special group, here "Support Group"


    my ($ticket, $trans, $attach, $filename);
    my $arg = $m->dhandler_arg;                # get rest of path
    if ($arg =~ '^(\d+)/(\d+)/(\d+)') {
        $ticket = $1;
        $trans = $2;
        $attach = $3;
    else {
        Abort("Corrupted attachment URL.");

    my $ok=0;
    my $BSGroup = RT::Group->new($RT::SystemUser);
    $BSGroup->LoadUserDefinedGroup('Support Group');
    my $principal = $session{'CurrentUser'}->PrincipalObj;
    # by default, users goes to SelfService
    if ($BSGroup->HasMemberRecursively($principal)) {
        $ok = 1;
    } elsif ($principal->HasRight(Right => 'SuperUser', Object=>$RT::System)) {
        $ok = 1;

    if (!$ok) {
       Abort("You can't edit a message");
     my $AttachmentObj = new RT::Attachment($session{'CurrentUser'});
     $AttachmentObj->Load($attach) || Abort("Attachment '$attach' could not be loaded");

     unless ($AttachmentObj->id) {
        Abort("Bad attachment id. Couldn't find attachment '$attach'\n");

     if ($ARGS{'content'}) {
        my $dbh = DBI->connect(RT::Handle->DSN, RT->Config->Get('DatabaseUser'), RT->Config->Get('DatabasePassword'));
        unless ( $dbh ) {
           Abort("Can't connect to database\n");
        my $text = $dbh->quote($ARGS{'content'});
        my $old = $dbh->quote($AttachmentObj->OriginalContent);

        # CREATE TABLE AttachmentsHistory (Id int, Content text, Updated TimeStamp)
        $dbh->do("INSERT INTO AttachmentsHistory (Id, Content, Updated) VALUES ($attach, $old, NOW())");
        $dbh->do("UPDATE Attachments SET Content=$text WHERE Id=$attach");
        return RT::Interface::Web::Redirect( RT->Config->Get('WebURL') . "Ticket/Display.html?id=" . $ticket . "#txn-" . $trans);

     my $content_type = $AttachmentObj->ContentType || 'text/plain';

     if ($content_type !~ /^text\/plain/i) {
        Abort("Can't edit non text attachment\n");

     if (my $enc = $AttachmentObj->OriginalEncoding) {
        my $iana = Encode::find_encoding( $enc );
        $iana = $iana? $iana->mime_name : $enc;
        $content_type .= ";charset=$iana";

     # unless (RT->Config->Get('TrustMIMEAttachments')) {
     #     $content_type = 'application/octet-stream';
     # }

     $m->out("Edit Attachment Id $attach
"); if ($ARGS{'content'}) { $m->out("<pre>"); $m->out($ARGS{'content'}); $m->out("</pre>"); } $m->out("
"); $m->abort; <%attr> AutoFlush => 0 <%ARGS> $id => undef

To keep version history, you can create this table to your RT instance

CREATE TABLE AttachmentsHistory (Id int, Content text, Updated TimeStamp);

A future version can also log the current user name, and display versions in a tab.