Edgewall Software

Opened 3 years ago

Closed 3 years ago

Last modified 3 months ago

#12870 closed enhancement (fixed)

Add API to rename attachments

Reported by: anonymous Owned by: Ryan J Ollos
Priority: normal Milestone: 1.3.2
Component: attachment Version:
Severity: normal Keywords:
Cc: Branch:
Release Notes:

Added TracAdmin attachment move command.

API Changes:
  • Added Attachment.move. Attachment.reparent is deprecated and will be removed in 1.5.1.
  • Added IAttachmentChangeListener.attachment_moved. IAttachmentChangeListener.attachment_reparent is deprecated and will be removed in 1.5.1.
Internal Changes:


Similar to API to reparent attachments:

  • trac/attachment.py

    diff -r 0dd110ecb8e9 trac/attachment.py
    a b  
    5858class IAttachmentChangeListener(Interface):
    5959    """Extension point interface for components that require
    60     notification when attachments are created or deleted."""
     60    notification when attachments are created or deleted etc."""
    6262    def attachment_added(attachment):
    6363        """Called when an attachment is added."""
    6565    def attachment_deleted(attachment):
    6666        """Called when an attachment is deleted."""
     68    def attachment_renamed(attachment, old_filename):
     69        """Called when an attachment is renamed."""
    6871    def attachment_reparented(attachment, old_parent_realm, old_parent_id):
    6972        """Called when an attachment is reparented."""
    765768        for listener in AttachmentModule(self.env).change_listeners:
    766769            listener.attachment_deleted(self)
     771    def rename(self, new_filename):
     772        assert self.filename, "Cannot rename non-existent attachment"
     773        new_filename = unicode(new_filename)
     774        new_path = self._get_path(self.env.attachments_dir, self.parent_realm,
     775                                  self.parent_id, new_filename)
     777        # Make sure the path to the attachment is inside the environment
     778        # attachments directory
     779        commonprefix = os.path.commonprefix([self.env.attachments_dir,
     780                                             new_path])
     781        if commonprefix != self.env.attachments_dir:
     782            raise TracError(_('Cannot rename attachment "%(att)s" as '
     783                              '%(new)s is invalid',
     784                              att=self.filename, new=new_filename))
     786        if os.path.exists(new_path):
     787            raise TracError(_('Cannot rename attachment "%(att)s" to %(new)s '
     788                              'as it already exists',
     789                              att=self.filename, new=new_filename))
     790        with self.env.db_transaction as db:
     791            db("""UPDATE attachment SET filename=%s
     792                  WHERE type=%s AND id=%s AND filename=%s
     793                  """, (new_filename, self.parent_realm,
     794                        self.parent_id, self.filename))
     795            dirname = os.path.dirname(new_path)
     796            if not os.path.exists(dirname):
     797                os.makedirs(dirname)
     798            path = self.path
     799            if os.path.isfile(path):
     800                try:
     801                    os.rename(path, new_path)
     802                except OSError as e:
     803                    self.env.log.error("Failed to move attachment file %s: %s",
     804                                       path,
     805                                       exception_to_unicode(e, traceback=True))
     806                    raise TracError(_("Could not rename attachment %(name)s",
     807                                      name=self.filename))
     809        old_filename = self.filename
     810        self.filename = new_filename
     811        self.env.log.info("Attachment renamed: %s", new_filename)
     813        for listener in AttachmentModule(self.env).change_listeners:
     814            if hasattr(listener, 'attachment_renamed'):
     815                listener.attachment_renamed(self, old_filename)
    768817    def reparent(self, new_realm, new_id):
    769818        assert self.filename, "Cannot reparent non-existent attachment"
    770819        new_id = unicode(new_id)

Attachments (0)

Change History (5)

comment:1 by Ryan J Ollos, 3 years ago

API Changes: modified (diff)
Milestone: next-major-releases

Looks fine to me, but patch didn't apply cleanly to the trunk (TracDev/SubmittingPatches). It will need unit tests before we can commit the changes.

We could also add TracAdmin rename and reparent commands. Or maybe combine them in a single move <realm:id> <name> <new_realm:new_id> <new_name> command. We should also consider whether rename and reparent should be combined in a single method, adding an optional filename argument to reparent and possibly renaming the method to move.

Version 0, edited 3 years ago by Ryan J Ollos (next)

comment:2 by Ryan J Ollos, 3 years ago

API Changes: modified (diff)
Milestone: next-major-releases1.3.2
Owner: set to Ryan J Ollos
Release Notes: modified (diff)
Status: newassigned

comment:3 by Ryan J Ollos, 3 years ago

API Changes: modified (diff)
Resolution: fixed
Status: assignedclosed

Committed to trunk in r16160.

comment:4 by Jun Omae, 11 months ago

I noticed the API changes, just now….

comment:5 by Ryan J Ollos, 3 months ago

Release Notes: modified (diff)

Modify Ticket

Change Properties
Set your email in Preferences
as closed The owner will remain Ryan J Ollos.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from Ryan J Ollos to the specified user.

Add Comment

E-mail address and name can be saved in the Preferences .
Note: See TracTickets for help on using tickets.