Modify

Opened 11 years ago

Last modified 4 years ago

#11188 new defect

"Copying attachments" is not compatible for Trac 1.0

Reported by: Jun Omae Owned by:
Priority: normal Component: TicketMoverPlugin
Severity: normal Keywords:
Cc: Trac Release: 1.0

Description (last modified by Jun Omae)

The plugin copies the attachment files of the ticket when the ticket is moved. However, it determines directly the path of the attachment file without Attachment.path.

See source:ticketmoverplugin/trunk/ticketmoverplugin/ticketmover.py@13301:88-90#L80.

After Trac 1.0, the structure of the attachments directory has been changes, t:#10313. We should use Attachment.path which is available since Trac 0.10.

Attachments (3)

ticketmoverplugin_0.1.2-GU.tar.gz (3.8 KB) - added by Giuseppe Ursino 10 years ago.
ticketmoverplugin_0.1.2-GU.patch (12.1 KB) - added by Giuseppe Ursino 10 years ago.
ticketmoverplugin_0.1.2-FIX.patch (4.8 KB) - added by Giuseppe Ursino 10 years ago.

Download all attachments as: .zip

Change History (18)

comment:1 Changed 11 years ago by Jun Omae

Cc: Ryan J Ollos added; anonymous removed
Description: modified (diff)

comment:2 Changed 11 years ago by Ryan J Ollos

Jun, we can go ahead and make changes to this plugin since k0s has retired (at least temporarily) from Trac development. I'll keep your suggested change on my TODO list, in case you don't beat me to pushing a fix!

comment:3 Changed 10 years ago by didley@…

Hello,

We are using TicketMoverPlugin in a central focus point and therefore I would like to change it by myself but I'm not a good Phyton-programmer and I don't know the API of TRAC very well.

Is it possible to give me a glue to change it by myself? Or is it much more complicated than I thought?

I found the area within the programming. I know folders now named in a hash code and the path within the environment is files/attachments/ticket.

English is not my native language and what I try is asking for a hint. It's just a question. I don't wanna annoying anybody.

It would be nice to receiving a hint.

best regards,

didley

        # copy the attachments
        src_attachment_dir = os.path.join(self.env.path, 'attachments',
                                          'ticket', str(ticket_id))
        if os.path.exists(src_attachment_dir):
            dest_attachment_dir = os.path.join(env.path, 'attachments',
                                               'ticket')
            if not os.path.exists(dest_attachment_dir):
                os.makedirs(dest_attachment_dir)
            dest_attachment_dir = os.path.join(dest_attachment_dir,
                                               str(new_ticket.id))
            shutil.copytree(src_attachment_dir, dest_attachment_dir)

        # note the previous location on the new ticket
        new_ticket.save_changes(author, 'moved from %s'
                                        % self.env.abs_href('ticket',
                                                            ticket_id))

        # location of new ticket
        new_location = env.abs_href.ticket(new_ticket.id)

comment:4 Changed 10 years ago by anonymous

Hello didley,

I'd the same problem. Because i had to move many tickets (and ticketmover plugin didn't worked for me with batch modify) i've pulled out the stuff into a standalone script to be executed once on the server.

You might take the attachment part and patch it into the plugin.

import os
import shutil
import string

from genshi.builder import tag
from trac.env import open_environment
from trac.perm import PermissionCache
from trac.ticket import Ticket
from trac.ticket.api import ITicketActionController
from tracsqlhelper import get_all_dict, insert_row_from_dict
from trac.attachment import Attachment



src_env = open_environment('/path/to/sourcre/environment', use_cache=True)	
print 'src_env open...'

dst_env = open_environment('/path/to/destination/environment', use_cache=True)	
print "dst_env open..."

author = 'Your.Name'

PermissionCache(dst_env, author).require('TICKET_CREATE')						  

for src_ticket_id in range(1,44):
  # get the src ticket  										     
  src_ticket = Ticket(src_env, src_ticket_id)							     
  print "\nsrc_ticket %s open..." % (src_ticket_id)


  # make a new ticket from the src ticket values
  dst_ticket	    = Ticket(dst_env)
  print "dst_ticket open..."
  
  dst_ticket.values = src_ticket.values.copy()     # copies also custom fields...
  print "ticket values copied..."

  #dst_ticket.insert(when=src_ticket.time_created)
  dst_ticket.insert()
  print 'dst_ticket %s inserted...' % (dst_ticket.id)

  ############################################################################################################ 
  # copy the changelog table...
  table = 'ticket_change'
  _id	= 'ticket'
  for row in get_all_dict(src_env,					  
  		      "SELECT * FROM %s WHERE %s = %%s" % (table, _id),    
  		      str(src_ticket_id)):					  
      row[_id] = dst_ticket.id  				  
      insert_row_from_dict(dst_env, table, row)				  
  print "changelog copied..."
  														  
  														  
  ############################################################################################################ 
  # copy the attachment table...
  # in attachemnt table check for type (=ticket) AND id(=ticketID)...					   
  table = 'attachment'
  _id	= 'id'
  filenames = []
  for row in get_all_dict(src_env,
  		      "SELECT * FROM %s WHERE type = 'ticket' AND %s = %%s" % (table , _id),
  		      str(src_ticket_id)):
      row[_id] = dst_ticket.id
      insert_row_from_dict(dst_env, table, row)
      # remember file name...
      filenames.append(row['filename'])
  print "attachments checked..."




  ############################################################################################################ 
  # copy the attachments
  for filename in filenames:										   
    src_path_file = Attachment._get_path(src_env.path , 'ticket' , str(src_ticket_id) , filename)
    dst_path_file = Attachment._get_path(dst_env.path , 'ticket' , str(dst_ticket.id) , filename)     

    dst_path , dst_file = os.path.split(dst_path_file)  						   
    
    if not os.path.exists(dst_path):
      os.makedirs(dst_path)

    shutil.copyfile(src_path_file , dst_path_file)
    print "attachments copy '%s' -> '%s'..." % (src_path_file , dst_path_file)



  ############################################################################################################ 
  # note the previous location on the new ticket
  dst_ticket.save_changes(author ,'moved to here from %s' % src_env.abs_href('ticket', src_ticket_id))         
  print "dst_ticket annotated..."


  ############################################################################################################ 
  # close old ticket and point to new one				
  src_ticket['status'] = u'closed'				       
  src_ticket['resolution'] = u'duplicate'			       
  src_ticket.save_changes(author, 'moved to %s' % dst_env.abs_href('ticket', dst_ticket.id))
  print "src_ticket closed..."

Hope this helps.

With best regards,

Klaus

comment:5 Changed 10 years ago by anonymous

Hello Klaus,

thanx for your script. I will check it out.

Best regards,

didley

comment:6 Changed 10 years ago by Jun Omae

#11631 was closed as a duplicate.

comment:7 Changed 10 years ago by Giuseppe Ursino

Hello,

I have opened the ticket #11631 that was redirect to this ticket.

So I have modified the plugin as in the attachment (ticketmoverplugin_0.1.2-GU.tar.gz) to fix the problem. Thanks to Klaus for sharing its script.

Moreover I add some other features:

  • Checkbox with the possibility to keep the ticket status (default: moved ticket will have 'new' as ticket status)
  • Checks that ticket fields are present on destination environment
  • Correct "moved to" url that didn't work when the 'base_url' was not set (in my case I have different environment on the same base directory that inherit a global trac configuration file
  • Changed version to 1.0.2-GU

Please consider to commit my patch.

Changed 10 years ago by Giuseppe Ursino

comment:8 Changed 10 years ago by Jun Omae

Could you please post the patch as unified diff format? See trac:TracDev/SubmittingPatches for good patch.

comment:9 in reply to:  7 ; Changed 10 years ago by Jun Omae

Moreover I add some other features:

Also, please create a new ticket for other features.

Changed 10 years ago by Giuseppe Ursino

comment:10 in reply to:  9 Changed 10 years ago by Jun Omae

Replying to jun66j5:

Moreover I add some other features:

Also, please create a new ticket for other features.

That means the patch should be only changes for this ticket. Otherwise, it would be difficult to consider whether to apply the patch.

Changed 10 years ago by Giuseppe Ursino

comment:11 Changed 10 years ago by Giuseppe Ursino

Please consider to commit all features not only this bugfix

comment:12 in reply to:  11 Changed 10 years ago by Ryan J Ollos

Replying to giursino:

Please consider to commit all features not only this bugfix

To expand on what Jun said, the patch in it's current state puts the burden on the committer to figure out which feature or fix each line in the patch is associated with. The committer must then parse up your patch and test each change. It's unlikely to get committed unless you break up the patch into multiple patches, each targeting a specific feature or defect.

comment:13 in reply to:  9 Changed 10 years ago by Giuseppe Ursino

Replying to jun66j5:

Moreover I add some other features:

Also, please create a new ticket for other features.

I've created #11641

comment:14 Changed 9 years ago by Ryan J Ollos

Owner: Jeff Hammel deleted

comment:15 Changed 4 years ago by Ryan J Ollos

Cc: Ryan J Ollos removed

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The ticket will remain with no owner.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.