changeset 5279:2aa43685e17b

AttachFile: added remove_attachment(), made nuke_page use it (details below) AttachFile was missing a remove_attachment function (in the style of add_attachment), added it. It triggers an event FileRemovedEvent. FileRemovedEvent handling: * implemented for mail notifications * implemented for xapian index updates * not implemented for jabber notifications (this also needs some work in the jabber bot + testing) nuke_page was broken because it did not remove attachments from xapian index, fixed it by using remove_attachment (which triggers indexing via FileRemovedEvent).
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sun, 15 Nov 2009 10:08:13 +0100
parents 66f7fd87b2ae
children d25574af97eb
files MoinMoin/_tests/__init__.py MoinMoin/action/AttachFile.py MoinMoin/events/__init__.py MoinMoin/events/emailnotify.py MoinMoin/events/jabbernotify.py MoinMoin/events/notification.py MoinMoin/events/xapian_index.py
diffstat 7 files changed, 142 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/_tests/__init__.py	Sat Nov 14 13:57:18 2009 +0100
+++ b/MoinMoin/_tests/__init__.py	Sun Nov 15 10:08:13 2009 +0100
@@ -15,6 +15,7 @@
 from MoinMoin.PageEditor import PageEditor
 from MoinMoin.util import random_string
 from MoinMoin import caching, user
+from MoinMoin.action import AttachFile
 
 # Promoting the test user -------------------------------------------
 # Usually the tests run as anonymous user, but for some stuff, you
@@ -93,6 +94,9 @@
 
 def nuke_page(request, pagename):
     """ completely delete a page, everything in the pagedir """
+    attachments = AttachFile._get_files(request, pagename)
+    for attachment in attachments:
+        AttachFile.remove_attachment(request, pagename, attachment)
     page = PageEditor(request, pagename, do_editor_backup=False)
     page.deletePage()
     # really get rid of everything there:
--- a/MoinMoin/action/AttachFile.py	Sat Nov 14 13:57:18 2009 +0100
+++ b/MoinMoin/action/AttachFile.py	Sun Nov 15 10:08:13 2009 +0100
@@ -43,7 +43,7 @@
 from MoinMoin.Page import Page
 from MoinMoin.util import filesys, timefuncs
 from MoinMoin.security.textcha import TextCha
-from MoinMoin.events import FileAttachedEvent, send_event
+from MoinMoin.events import FileAttachedEvent, FileRemovedEvent, send_event
 from MoinMoin.support import tarfile
 
 action_name = __name__.split('.')[-1]
@@ -198,34 +198,56 @@
         filecontent can be either a str (in memory file content),
         or an open file object (file content in e.g. a tempfile).
     """
-    _ = request.getText
-
     # replace illegal chars
     target = wikiutil.taintfilename(target)
 
     # get directory, and possibly create it
     attach_dir = getAttachDir(request, pagename, create=1)
-    # save file
     fpath = os.path.join(attach_dir, target).encode(config.charset)
+
     exists = os.path.exists(fpath)
-    if exists and not overwrite:
-        raise AttachmentAlreadyExists
+    if exists:
+        if overwrite:
+            remove_attachment(request, pagename, target)
+        else:
+            raise AttachmentAlreadyExists
+
+    # save file
+    stream = open(fpath, 'wb')
+    try:
+        _write_stream(filecontent, stream)
+    finally:
+        stream.close()
+
+    _addLogEntry(request, 'ATTNEW', pagename, target)
+
+    filesize = os.path.getsize(fpath)
+    event = FileAttachedEvent(request, pagename, target, filesize)
+    send_event(event)
+
+    return target, filesize
+
+
+def remove_attachment(request, pagename, target):
+    """ remove attachment <target> of page <pagename>
+    """
+    # replace illegal chars
+    target = wikiutil.taintfilename(target)
+
+    # get directory, do not create it
+    attach_dir = getAttachDir(request, pagename, create=0)
+    # remove file
+    fpath = os.path.join(attach_dir, target).encode(config.charset)
+    try:
+        filesize = os.path.getsize(fpath)
+        os.remove(fpath)
+    except:
+        # either it is gone already or we have no rights - not much we can do about it
+        filesize = 0
     else:
-        if exists:
-            try:
-                os.remove(fpath)
-            except:
-                pass
-        stream = open(fpath, 'wb')
-        try:
-            _write_stream(filecontent, stream)
-        finally:
-            stream.close()
+        _addLogEntry(request, 'ATTDEL', pagename, target)
 
-        _addLogEntry(request, 'ATTNEW', pagename, target)
-
-        filesize = os.path.getsize(fpath)
-        event = FileAttachedEvent(request, pagename, target, filesize)
+        event = FileRemovedEvent(request, pagename, target, filesize)
         send_event(event)
 
     return target, filesize
@@ -619,15 +641,7 @@
     if not filename:
         return # error msg already sent in _access_file
 
-    # delete file
-    os.remove(fpath)
-    _addLogEntry(request, 'ATTDEL', pagename, filename)
-
-    if request.cfg.xapian_search:
-        from MoinMoin.search.Xapian import XapianIndex
-        index = XapianIndex(request)
-        if index.exists:
-            index.update_item(pagename, filename)
+    remove_attachment(request, pagename, filename)
 
     upload_form(pagename, request, msg=_("Attachment '%(filename)s' deleted.") % {'filename': filename})
 
--- a/MoinMoin/events/__init__.py	Sat Nov 14 13:57:18 2009 +0100
+++ b/MoinMoin/events/__init__.py	Sun Nov 15 10:08:13 2009 +0100
@@ -119,6 +119,20 @@
         self.size = size
 
 
+class FileRemovedEvent(PageEvent):
+
+    name = u"FileRemovedEvent"
+    description = _(u"""An attachment has been removed""")
+    req_superuser = False
+
+    def __init__(self, request, pagename, filename, size):
+        PageEvent.__init__(self, request)
+        self.request = request
+        self.pagename = pagename
+        self.filename = filename
+        self.size = size
+
+
 class PageRevertedEvent(PageEvent):
 
     name = u"PageRevertedEvent"
--- a/MoinMoin/events/emailnotify.py	Sat Nov 14 13:57:18 2009 +0100
+++ b/MoinMoin/events/emailnotify.py	Sun Nov 15 10:08:13 2009 +0100
@@ -162,6 +162,42 @@
     return notification.Success(names)
 
 
+def handle_file_removed(event):
+    """Sends an email to super users that have subscribed to this event type"""
+
+    names = set()
+    from_address = event.request.cfg.mail_from
+    request = event.request
+    page = Page(request, event.pagename)
+
+    subscribers = page.getSubscribers(request, return_users=1)
+    notification.filter_subscriber_list(event, subscribers, False)
+    recipients = []
+
+    for lang in subscribers:
+        recipients.extend(subscribers[lang])
+
+    attachlink = request.getQualifiedURL(getAttachUrl(event.pagename, event.filename, request))
+    pagelink = request.getQualifiedURL(page.url(request, {}))
+
+    for lang in subscribers:
+        emails = []
+        _ = lambda text: request.getText(text, lang=lang)
+
+        links = _("Attachment link: %(attach)s\n" \
+                  "Page link: %(page)s\n") % {'attach': attachlink, 'page': pagelink}
+
+        data = notification.attachment_removed(request, _, event.pagename, event.filename, event.size)
+        data['text'] = data['text'] + links
+
+        emails = [usr.email for usr in subscribers[lang]]
+
+        if send_notification(request, from_address, emails, data):
+            names.update(recipients)
+
+    return notification.Success(names)
+
+
 def handle(event):
     """An event handler"""
 
@@ -174,3 +210,6 @@
         return handle_user_created(event)
     elif isinstance(event, ev.FileAttachedEvent):
         return handle_file_attached(event)
+    elif isinstance(event, ev.FileRemovedEvent):
+        return handle_file_removed(event)
+
--- a/MoinMoin/events/jabbernotify.py	Sat Nov 14 13:57:18 2009 +0100
+++ b/MoinMoin/events/jabbernotify.py	Sun Nov 15 10:08:13 2009 +0100
@@ -37,6 +37,9 @@
         return handle_jid_changed(event)
     elif isinstance(event, ev.FileAttachedEvent):
         return handle_file_attached(event)
+    # TODO (needs also corresponding changes in xmppbot + testing)
+    #elif isinstance(event, ev.FileRemovedEvent):
+    #    return handle_file_removed(event)
     elif isinstance(event, ev.PageDeletedEvent):
         return handle_page_deleted(event)
     elif isinstance(event, ev.PageRenamedEvent):
--- a/MoinMoin/events/notification.py	Sat Nov 14 13:57:18 2009 +0100
+++ b/MoinMoin/events/notification.py	Sun Nov 15 10:08:13 2009 +0100
@@ -172,6 +172,40 @@
     return data
 
 
+def attachment_removed(request, _, page_name, attach_name, attach_size):
+    """Formats a message used to notify about removed attachments
+
+    @param _: a gettext function
+    @return: a dict with notification data
+
+    """
+    data = {}
+
+    data['subject'] = _("Removed attachment from page %(pagename)s on %(sitename)s") % {
+                'pagename': page_name,
+                'sitename': request.cfg.sitename or request.url_root,
+                }
+
+    data['text'] = _("Dear Wiki user,\n\n"
+    'You have subscribed to a wiki page "%(page_name)s" for change notification. '
+    "An attachment has been removed from that page by %(editor)s. "
+    "Following detailed information is available:\n\n"
+    "Attachment name: %(attach_name)s\n"
+    "Attachment size: %(attach_size)s\n") % {
+        'editor': user.getUserIdentification(request),
+        'page_name': page_name,
+        'attach_name': attach_name,
+        'attach_size': attach_size,
+    }
+
+    data['editor'] = user.getUserIdentification(request)
+    data['page_name'] = page_name
+    data['attach_size'] = attach_size
+    data['attach_name'] = attach_name
+
+    return data
+
+
 # XXX: clean up this method to take a notification type instead of bool for_jabber
 def filter_subscriber_list(event, subscribers, for_jabber):
     """Filter a list of page subscribers to honor event subscriptions
--- a/MoinMoin/events/xapian_index.py	Sat Nov 14 13:57:18 2009 +0100
+++ b/MoinMoin/events/xapian_index.py	Sun Nov 15 10:08:13 2009 +0100
@@ -53,8 +53,8 @@
     handle_changed(event)
 
 
-def handle_attached(event):
-    """Updates Xapian index when a new attachment is added"""
+def handle_attachment_change(event):
+    """Updates Xapian index when attachment is added or removed"""
 
     request = event.request
 
@@ -73,5 +73,6 @@
         handle_changed(event)
     elif isinstance(event, ev.PageDeletedEvent):
         handle_deleted(event)
-    elif isinstance(event, ev.FileAttachedEvent):
-        handle_attached(event)
+    elif isinstance(event, ev.FileAttachedEvent) or isinstance(event, ev.FileRemovedEvent):
+        handle_attachment_change(event)
+