Opened 3 years ago

# "Copying attachments" is not compatible for Trac 1.0

Reported by: Owned by: jun66j5 normal TicketMoverPlugin normal rjollos 1.0

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.

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.

### comment:1 Changed 3 years ago by jun66j5

• Cc rjollos added; anonymous removed
• Description modified (diff)

### comment:2 Changed 3 years ago by rjollos

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 3 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 3 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 3 years ago by anonymous

Hello Klaus,

thanx for your script. I will check it out.

Best regards,

didley

### comment:6 Changed 3 years ago by jun66j5

#11631 was closed as a duplicate.

### comment:7 follow-up: ↓ 9 Changed 3 years ago by giursino

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.

### comment:8 Changed 3 years ago by jun66j5

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

### comment:9 in reply to: ↑ 7 ; follow-ups: ↓ 10 ↓ 13 Changed 3 years ago by jun66j5

Moreover I add some other features:

Also, please create a new ticket for other features.

### comment:10 in reply to: ↑ 9 Changed 3 years ago by 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.

### comment:11 follow-up: ↓ 12 Changed 3 years ago by giursino

Please consider to commit all features not only this bugfix

### comment:12 in reply to: ↑ 11 Changed 3 years ago by rjollos

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 3 years ago by giursino

Moreover I add some other features:

Also, please create a new ticket for other features.

I've created #11641

### comment:14 Changed 20 months ago by rjollos

• Owner k0s deleted