Modified: incubator/bloodhound/branches/0.5/trac/trac/attachment.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/attachment.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/attachment.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/attachment.py Fri Mar 15 
08:18:24 2013
@@ -221,7 +221,7 @@ class Attachment(object):
         with self.env.db_transaction as db:
             db("""
                 DELETE FROM attachment WHERE type=%s AND id=%s AND filename=%s
-                """, (self.parent_realm, self.parent_id, self.filename))
+                    """, (self.parent_realm, self.parent_id, self.filename))
             path = self.path
             if os.path.isfile(path):
                 try:
@@ -237,6 +237,7 @@ class Attachment(object):
 
         for listener in AttachmentModule(self.env).change_listeners:
             listener.attachment_deleted(self)
+        ResourceSystem(self.env).resource_deleted(self)
 
     def reparent(self, new_realm, new_id):
         assert self.filename, "Cannot reparent non-existent attachment"
@@ -287,6 +288,8 @@ class Attachment(object):
         for listener in AttachmentModule(self.env).change_listeners:
             if hasattr(listener, 'attachment_reparented'):
                 listener.attachment_reparented(self, old_realm, old_id)
+        old_values = dict(parent_realm=old_realm, parent_id=old_id)
+        ResourceSystem(self.env).resource_changed(self, old_values=old_values)
 
     def insert(self, filename, fileobj, size, t=None, db=None):
         """Create a new Attachment record and save the file content.
@@ -332,6 +335,7 @@ class Attachment(object):
 
         for listener in AttachmentModule(self.env).change_listeners:
             listener.attachment_added(self)
+        ResourceSystem(self.env).resource_created(self)
 
 
     @classmethod

Modified: incubator/bloodhound/branches/0.5/trac/trac/resource.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/resource.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/resource.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/resource.py Fri Mar 15 08:18:24 
2013
@@ -217,6 +217,38 @@ class Resource(object):
         """
         return Resource(realm, id, version, self)
 
+class IResourceChangeListener(Interface):
+    """Extension point interface for components that require notification
+    when resources are created, modified, or deleted.
+
+    'resource' parameters is instance of the a resource e.g. ticket, milestone
+    etc.
+    'context' is an action context, may contain author, comment etc. Context
+    content depends on a resource type.
+    """
+
+    def match_resource(resource):
+        """Return whether the listener wants to process the given resource."""
+
+    def resource_created(resource, context):
+        """
+        Called when a resource is created.
+        """
+
+    def resource_changed(resource, old_values, context):
+        """Called when a resource is modified.
+
+        `old_values` is a dictionary containing the previous values of the
+        resource properties that changed. Properties are specific for resource
+        type.
+        """
+
+    def resource_deleted(resource, context):
+        """Called when a resource is deleted."""
+
+    def resource_version_deleted(resource, context):
+        """Called when a version of a resource has been deleted."""
+
 
 class ResourceSystem(Component):
     """Resource identification and description manager.
@@ -226,6 +258,8 @@ class ResourceSystem(Component):
     """
 
     resource_managers = ExtensionPoint(IResourceManager)
+    change_listeners = ExtensionPoint(IResourceChangeListener)
+
 
     def __init__(self):
         self._resource_managers_map = None
@@ -255,6 +289,25 @@ class ResourceSystem(Component):
                 realms.append(realm)
         return realms
 
+    def resource_created(self, resource, context=None):
+        for listener in self.change_listeners:
+            if listener.match_resource(resource):
+                listener.resource_created(resource, context)
+
+    def resource_changed(self, resource, old_values, context=None):
+        for listener in self.change_listeners:
+            if listener.match_resource(resource):
+                listener.resource_changed(resource, old_values, context)
+
+    def resource_deleted(self, resource, context=None):
+        for listener in self.change_listeners:
+            if listener.match_resource(resource):
+                listener.resource_deleted(resource, context)
+
+    def resource_version_deleted(self, resource, context=None):
+        for listener in self.change_listeners:
+            if listener.match_resource(resource):
+                listener.resource_version_deleted(resource, context)
 
 # -- Utilities for manipulating resources in a generic way
 

Modified: incubator/bloodhound/branches/0.5/trac/trac/tests/attachment.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/tests/attachment.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/tests/attachment.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/tests/attachment.py Fri Mar 15 
08:18:24 2013
@@ -11,6 +11,7 @@ from trac.core import Component, impleme
 from trac.perm import IPermissionPolicy, PermissionCache
 from trac.resource import Resource, resource_exists
 from trac.test import EnvironmentStub
+from trac.tests.resource import TestResourceChangeListener
 
 
 hashes = {
@@ -222,9 +223,64 @@ class AttachmentTestCase(unittest.TestCa
         self.assertTrue(resource_exists(self.env, att.resource))
 
 
+class AttachmentResourceChangeListenerTestCase(unittest.TestCase):
+    DUMMY_PARENT_REALM = "wiki"
+    DUMMY_PARENT_ID = "WikiStart"
+
+    def setUp(self):
+        self.env = EnvironmentStub(default_data=True)
+        self.listener = TestResourceChangeListener(self.env)
+        self.listener.resource_type = Attachment
+        self.listener.callback = self.listener_callback
+
+    def tearDown(self):
+        self.env.reset_db()
+
+    def test_change_listener_created(self):
+        attachment = self._create_attachment()
+        self.assertEqual('created', self.listener.action)
+        self.assertIsInstance(self.listener.resource, Attachment)
+        self.assertEqual(attachment.filename, self.filename)
+        self.assertEqual(attachment.parent_realm, self.parent_realm)
+        self.assertEqual(attachment.parent_id, self.parent_id)
+
+    def test_change_listener_reparent(self):
+        attachment = self._create_attachment()
+        attachment.reparent(self.DUMMY_PARENT_REALM, "SomePage")
+
+        self.assertEqual('changed', self.listener.action)
+        self.assertIsInstance(self.listener.resource, Attachment)
+        self.assertEqual(attachment.filename, self.filename)
+        self.assertEqual(attachment.parent_realm, self.parent_realm)
+        self.assertEqual("SomePage", self.parent_id)
+        self.assertEqual(
+            self.DUMMY_PARENT_REALM, self.listener.old_values["parent_realm"])
+        self.assertEqual(
+            self.DUMMY_PARENT_ID, self.listener.old_values["parent_id"])
+
+    def test_change_listener_deleted(self):
+        attachment = self._create_attachment()
+        attachment.delete()
+        self.assertEqual('deleted', self.listener.action)
+        self.assertIsInstance(self.listener.resource, Attachment)
+        self.assertEqual(attachment.filename, self.filename)
+
+    def _create_attachment(self):
+        attachment = Attachment(
+            self.env, self.DUMMY_PARENT_REALM, self.DUMMY_PARENT_ID)
+        attachment.insert('file.txt', StringIO(''), 1)
+        return attachment
+
+    def listener_callback(self, action, resource, context, old_values = None):
+        self.parent_realm = resource.parent_realm
+        self.parent_id = resource.parent_id
+        self.filename = resource.filename
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(AttachmentTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(
+        AttachmentResourceChangeListenerTestCase, 'test'))
     return suite
 
 if __name__ == '__main__':

Modified: incubator/bloodhound/branches/0.5/trac/trac/tests/resource.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/tests/resource.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/tests/resource.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/tests/resource.py Fri Mar 15 
08:18:24 2013
@@ -15,6 +15,8 @@ import doctest
 import unittest
 
 from trac import resource
+from trac.resource import IResourceChangeListener
+from trac.core import implements, Component
 
 
 class ResourceTestCase(unittest.TestCase):
@@ -42,6 +44,46 @@ class ResourceTestCase(unittest.TestCase
         r2.parent = r2.parent(version=42)
         self.assertNotEqual(r1, r2)
 
+class TestResourceChangeListener(Component):
+    implements(IResourceChangeListener)
+
+    def __init__(self):
+        self.resource_type = None
+
+    def callback(self, action, resource, context, old_values = None):
+        pass
+
+    def match_resource(self, resource):
+        if self.resource_type is None:
+            return False
+        return isinstance(resource, self.resource_type)
+
+    def resource_created(self, resource, context):
+        self.action = "created"
+        self.resource = resource
+        self.context = context
+        self.callback(self.action, resource, context)
+
+    def resource_changed(self, resource, old_values, context):
+        self.action = "changed"
+        self.resource = resource
+        self.old_values = old_values
+        self.context = context
+        self.callback(
+            self.action, resource, context, old_values=self.old_values)
+
+    def resource_deleted(self, resource, context):
+        self.action = "deleted"
+        self.resource = resource
+        self.context = context
+        self.callback(self.action, resource, context)
+
+    def resource_version_deleted(self, resource, context):
+        self.action = "version_deleted"
+        self.resource = resource
+        self.context = context
+        self.callback(self.action, resource, context)
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(doctest.DocTestSuite(resource))

Modified: incubator/bloodhound/branches/0.5/trac/trac/ticket/api.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/ticket/api.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/ticket/api.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/ticket/api.py Fri Mar 15 
08:18:24 2013
@@ -156,31 +156,6 @@ class IMilestoneChangeListener(Interface
     def milestone_deleted(milestone):
         """Called when a milestone is deleted."""
 
-class IResourceChangeListener(Interface):
-    """Extension point interface for components that require notification
-    when resources are created, modified, or deleted.
-
-    'resource' instance of the a resource e.g. ticket, milestone etc.
-    'context' action context, may contain author, comment etc. Context
-    content depends on a resource type.
-    """
-
-    def resource_created(resource, context):
-        """
-        Called when a resource is created.
-        """
-
-    def resource_changed(resource, old_values, context):
-        """Called when a resource is modified.
-
-        `old_values` is a dictionary containing the previous values of the
-        resource properties that changed. Properties are specific for resource
-        type.
-        """
-
-    def resource_deleted(resource, context):
-        """Called when a resource is deleted."""
-
 class ITicketFieldProvider(Interface):
     """Extension point interface for components that provide fields for the
     ticket system."""
@@ -218,7 +193,6 @@ class TicketSystem(Component):
     ticket_field_providers = ExtensionPoint(ITicketFieldProvider)
     change_listeners = ExtensionPoint(ITicketChangeListener)
     milestone_change_listeners = ExtensionPoint(IMilestoneChangeListener)
-    resource_change_listeners = ExtensionPoint(IResourceChangeListener)
 
     ticket_custom_section = ConfigSection('ticket-custom',
         """In this section, you can define additional fields for tickets. See

Modified: incubator/bloodhound/branches/0.5/trac/trac/ticket/model.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/ticket/model.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/ticket/model.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/ticket/model.py Fri Mar 15 
08:18:24 2013
@@ -26,7 +26,7 @@ from trac.attachment import Attachment
 from trac import core
 from trac.cache import cached
 from trac.core import TracError
-from trac.resource import Resource, ResourceNotFound
+from trac.resource import Resource, ResourceNotFound, ResourceSystem
 from trac.ticket.api import TicketSystem
 from trac.util import embedded_numbers, partition
 from trac.util.text import empty
@@ -254,6 +254,7 @@ class Ticket(object):
 
         for listener in TicketSystem(self.env).change_listeners:
             listener.ticket_created(self)
+        ResourceSystem(self.env).resource_created(self)
 
         return self.id
 
@@ -363,6 +364,9 @@ class Ticket(object):
 
         for listener in TicketSystem(self.env).change_listeners:
             listener.ticket_changed(self, comment, author, old_values)
+        context = dict(comment=comment, author=author)
+        ResourceSystem(self.env).resource_changed(self, old_values, context)
+
         return int(cnum.rsplit('.', 1)[-1])
 
     def get_changelog(self, when=None, db=None):
@@ -427,6 +431,7 @@ class Ticket(object):
 
         for listener in TicketSystem(self.env).change_listeners:
             listener.ticket_deleted(self)
+        ResourceSystem(self.env).resource_deleted(self)
 
     def get_change(self, cnum=None, cdate=None, db=None):
         """Return a ticket change by its number or date.
@@ -712,6 +717,8 @@ class AbstractEnum(object):
                 except ValueError:
                     pass # Ignore cast error for this non-essential operation
             TicketSystem(self.env).reset_ticket_fields()
+
+        ResourceSystem(self.env).resource_deleted(self)
         self.value = self._old_value = None
         self.name = self._old_name = None
 
@@ -739,6 +746,7 @@ class AbstractEnum(object):
 
         self._old_name = self.name
         self._old_value = self.value
+        ResourceSystem(self.env).resource_created(self)
 
     def update(self, db=None):
         """Update the enum value.
@@ -762,8 +770,10 @@ class AbstractEnum(object):
                    (self.name, self._old_name))
             TicketSystem(self.env).reset_ticket_fields()
 
+        old_values = dict(name=self._old_name, value=self._old_value)
         self._old_name = self.name
         self._old_value = self.value
+        ResourceSystem(self.env).resource_changed(self, old_values)
 
     @classmethod
     def select(cls, env, db=None):
@@ -846,8 +856,7 @@ class Component(object):
             db("DELETE FROM component WHERE name=%s", (self.name,))
             TicketSystem(self.env).reset_ticket_fields()
 
-        for listener in TicketSystem(self.env).resource_change_listeners:
-            listener.resource_deleted(self)
+        ResourceSystem(self.env).resource_deleted(self)
         self.name = self._old_name = None
 
     def insert(self, db=None):
@@ -869,8 +878,7 @@ class Component(object):
             self._old_name = self.name
             TicketSystem(self.env).reset_ticket_fields()
 
-        for listener in TicketSystem(self.env).resource_change_listeners:
-            listener.resource_created(self)
+        ResourceSystem(self.env).resource_created(self)
 
     def update(self, db=None):
         """Update the component.
@@ -898,8 +906,7 @@ class Component(object):
             TicketSystem(self.env).reset_ticket_fields()
 
         old_values = dict(name=old_name)
-        for listener in TicketSystem(self.env).resource_change_listeners:
-            listener.resource_changed(self, old_values)
+        ResourceSystem(self.env).resource_changed(self, old_values)
 
     @classmethod
     def select(cls, env, db=None):
@@ -1037,6 +1044,7 @@ class Milestone(object):
 
         for listener in TicketSystem(self.env).milestone_change_listeners:
             listener.milestone_deleted(self)
+        ResourceSystem(self.env).resource_deleted(self)
 
     def insert(self, db=None):
         """Insert a new milestone.
@@ -1059,6 +1067,7 @@ class Milestone(object):
 
         for listener in TicketSystem(self.env).milestone_change_listeners:
             listener.milestone_created(self)
+        ResourceSystem(self.env).resource_created(self)
 
     def update(self, db=None):
         """Update the milestone.
@@ -1098,6 +1107,7 @@ class Milestone(object):
                           if getattr(self, k) != v)
         for listener in TicketSystem(self.env).milestone_change_listeners:
             listener.milestone_changed(self, old_values)
+        ResourceSystem(self.env).resource_changed(self, old_values)
 
     @classmethod
     def select(cls, env, include_completed=True, db=None):
@@ -1161,9 +1171,11 @@ class Version(object):
         with self.env.db_transaction as db:
             self.env.log.info("Deleting version %s", self.name)
             db("DELETE FROM version WHERE name=%s", (self.name,))
-            self.name = self._old_name = None
             TicketSystem(self.env).reset_ticket_fields()
 
+        ResourceSystem(self.env).resource_deleted(self)
+        self.name = self._old_name = None
+
     def insert(self, db=None):
         """Insert a new version.
 
@@ -1182,6 +1194,8 @@ class Version(object):
             self._old_name = self.name
             TicketSystem(self.env).reset_ticket_fields()
 
+        ResourceSystem(self.env).resource_created(self)
+
     def update(self, db=None):
         """Update the version.
 
@@ -1193,6 +1207,7 @@ class Version(object):
         if not self.name:
             raise TracError(_("Invalid version name."))
 
+        old_name=self._old_name
         with self.env.db_transaction as db:
             self.env.log.info("Updating version '%s'", self.name)
             db("""UPDATE version
@@ -1206,6 +1221,9 @@ class Version(object):
                 self._old_name = self.name
             TicketSystem(self.env).reset_ticket_fields()
 
+        old_values = dict(name=old_name)
+        ResourceSystem(self.env).resource_changed(self, old_values)
+
     @classmethod
     def select(cls, env, db=None):
         """

Modified: incubator/bloodhound/branches/0.5/trac/trac/ticket/tests/model.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/ticket/tests/model.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/ticket/tests/model.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/ticket/tests/model.py Fri Mar 
15 08:18:24 2013
@@ -15,10 +15,10 @@ from trac.ticket.model import (
     Ticket, Component, Milestone, Priority, Type, Version
 )
 from trac.ticket.api import (
-    IMilestoneChangeListener, ITicketChangeListener, TicketSystem,
-    IResourceChangeListener,
+    IMilestoneChangeListener, ITicketChangeListener, TicketSystem
 )
 from trac.test import EnvironmentStub
+from trac.tests.resource import TestResourceChangeListener
 from trac.util.datefmt import from_utimestamp, to_utimestamp, utc
 
 
@@ -1006,27 +1006,6 @@ class MilestoneTestCase(unittest.TestCas
         self.assertEqual('deleted', listener.action)
         self.assertEqual(milestone, listener.milestone)
 
-class TestResourceChangeListener(core.Component):
-    implements(IResourceChangeListener)
-
-    def callback(self, action, resource, old_values = None):
-        pass
-
-    def resource_created(self, resource):
-        self.action = "created"
-        self.resource = resource
-        self.callback(self.action, self.resource)
-
-    def resource_changed(self, resource, old_values):
-        self.action = "changed"
-        self.resource = resource
-        self.old_values = old_values
-        self.callback(self.action, self.resource, old_values=self.old_values)
-
-    def resource_deleted(self, resource):
-        self.action = "deleted"
-        self.resource = resource
-        self.callback(self.action, self.resource)
 
 class ComponentTestCase(unittest.TestCase):
 
@@ -1063,49 +1042,6 @@ class ComponentTestCase(unittest.TestCas
         self.assertEqual([('Test', 'joe', None)], self.env.db_query(
             "SELECT name, owner, description FROM component WHERE 
name='Test'"))
 
-    def test_change_listener_created(self):
-        listener = TestResourceChangeListener(self.env)
-        self._create_component(name='Component 1')
-        self.assertEqual('created', listener.action)
-        self.assertIsInstance(listener.resource, Component)
-        self.assertEqual('Component 1', listener.resource.name)
-
-    def test_change_listener_changed(self):
-        listener = TestResourceChangeListener(self.env)
-        component = self._create_component(name='Component 1')
-        component.name = 'Component 2'
-        component.update()
-        self.assertEqual('changed', listener.action)
-        self.assertIsInstance(listener.resource, Component)
-        self.assertEqual('Component 2', listener.resource.name)
-        self.assertEqual("Component 1" ,listener.old_values["name"])
-
-    def test_change_listener_deleted(self):
-        listener = TestResourceChangeListener(self.env)
-
-        #component.name property is set to None during delete operation
-        #We need mechanism to remember component name
-        listener.callback = self.listener_callback
-
-        component = self._create_component(name='Component 1')
-        component.delete()
-        self.assertEqual('deleted', listener.action)
-        self.assertIsInstance(listener.resource, Component)
-        self.assertEqual('Component 1', self.resource_name)
-
-    def listener_callback(self, action, resource, old_values = None):
-        self.resource_name = resource.name
-
-    def _create_component(self, name, description = None, owner=None):
-        component = Component(self.env)
-        component.name = name
-        if description is None:
-            component.description = description
-        if owner is None:
-            component.owner = owner
-        component.insert()
-        return component
-
 class VersionTestCase(unittest.TestCase):
 
     def setUp(self):
@@ -1140,6 +1076,107 @@ class VersionTestCase(unittest.TestCase)
         self.assertEqual([('Test', 0, 'Some text')], self.env.db_query(
             "SELECT name, time, description FROM version WHERE name='Test'"))
 
+class BaseResourceChangeListenerTestCase(unittest.TestCase):
+    DUMMY_RESOURCE_NAME = "Resource 1"
+    resource_type = None
+    name_field = "name"
+
+    def setUp(self):
+        self.env = EnvironmentStub(default_data=True)
+        self.listener = TestResourceChangeListener(self.env)
+        self.listener.resource_type = self.resource_type
+        self.listener.callback = self.listener_callback
+
+    def tearDown(self):
+        self.env.reset_db()
+
+    def test_change_listener_created(self):
+        self._create_resource(self.DUMMY_RESOURCE_NAME)
+        self.assertEqual('created', self.listener.action)
+        self.assertIsInstance(self.listener.resource, self.resource_type)
+        self.assertEqual(
+            self.DUMMY_RESOURCE_NAME,
+            self.resource_name)
+
+    def test_change_listener_changed(self):
+        resource = self._create_resource(self.DUMMY_RESOURCE_NAME)
+        self._rename_resource(resource, "UpdatedName")
+        self.assertEqual('changed', self.listener.action)
+        self.assertIsInstance(self.listener.resource, self.resource_type)
+        self.assertEqual("UpdatedName", self.resource_name)
+        self.assertEqual(
+            self.DUMMY_RESOURCE_NAME,
+            self.listener.old_values[self.name_field])
+
+    def test_change_listener_deleted(self):
+        resource = self._create_resource(self.DUMMY_RESOURCE_NAME)
+        resource.delete()
+        self.assertEqual('deleted', self.listener.action)
+        self.assertIsInstance(self.listener.resource, self.resource_type)
+        self.assertEqual(self.DUMMY_RESOURCE_NAME, self.resource_name)
+
+    def _create_resource(self, name):
+        resource = self.resource_type(self.env)
+        resource.name = name
+        resource.insert()
+        return resource
+
+    def _rename_resource(self, resource, new_name):
+        resource.name = new_name
+        resource.update()
+        return resource
+
+    def _get_resource_name(self, resource):
+        return resource.name
+
+    def listener_callback(self, action, resource, context, old_values = None):
+        self.resource_name = self._get_resource_name(resource)
+
+class ComponentResourceChangeListenerTestCase(
+    BaseResourceChangeListenerTestCase):
+    resource_type = Component
+
+class VersionResourceChangeListenerTestCase(
+    BaseResourceChangeListenerTestCase):
+    resource_type = Version
+
+class PriorityResourceChangeListenerTestCase(
+    BaseResourceChangeListenerTestCase):
+    resource_type = Priority
+
+class MilestoneResourceChangeListenerTestCase(
+    BaseResourceChangeListenerTestCase):
+    resource_type = Milestone
+
+class TicketResourceChangeListenerTestCase(
+    BaseResourceChangeListenerTestCase):
+    resource_type = Ticket
+    name_field = "summary"
+    dummy_author = "anAuthor"
+    dummy_comment = "some comment"
+
+    def test_change_listener_changed(self):
+        super(
+            TicketResourceChangeListenerTestCase,
+            self).test_change_listener_changed()
+
+        self.assertEqual(self.dummy_author, self.listener.context["author"])
+        self.assertEqual(self.dummy_comment, self.listener.context["comment"])
+
+
+    def _create_resource(self, name):
+        ticket = Ticket(self.env)
+        ticket["summary"] = name
+        ticket.insert()
+        return ticket
+
+    def _rename_resource(self, resource, new_name):
+        resource["summary"] = new_name
+        resource.save_changes(self.dummy_author, self.dummy_comment)
+        return resource
+
+    def _get_resource_name(self, resource):
+        return resource["summary"]
 
 def suite():
     suite = unittest.TestSuite()
@@ -1150,6 +1187,16 @@ def suite():
     suite.addTest(unittest.makeSuite(MilestoneTestCase, 'test'))
     suite.addTest(unittest.makeSuite(ComponentTestCase, 'test'))
     suite.addTest(unittest.makeSuite(VersionTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(
+        ComponentResourceChangeListenerTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(
+        VersionResourceChangeListenerTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(
+        PriorityResourceChangeListenerTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(
+        MilestoneResourceChangeListenerTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(
+        TicketResourceChangeListenerTestCase, 'test'))
     return suite
 
 if __name__ == '__main__':

Modified: incubator/bloodhound/branches/0.5/trac/trac/wiki/model.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/wiki/model.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/wiki/model.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/wiki/model.py Fri Mar 15 
08:18:24 2013
@@ -21,7 +21,7 @@ from __future__ import with_statement
 from datetime import datetime
 
 from trac.core import *
-from trac.resource import Resource
+from trac.resource import Resource, ResourceSystem
 from trac.util.datefmt import from_utimestamp, to_utimestamp, utc
 from trac.util.translation import _
 from trac.wiki.api import WikiSystem, validate_page_name
@@ -112,10 +112,12 @@ class WikiPage(object):
         if not self.exists:
             for listener in WikiSystem(self.env).change_listeners:
                 listener.wiki_page_deleted(self)
+            ResourceSystem(self.env).resource_deleted(self)
         else:
             for listener in WikiSystem(self.env).change_listeners:
                 if hasattr(listener, 'wiki_page_version_deleted'):
                     listener.wiki_page_version_deleted(self)
+            ResourceSystem(self.env).resource_version_deleted(self)
 
     def save(self, author, comment, remote_addr, t=None, db=None):
         """Save a new version of a page.
@@ -159,6 +161,23 @@ class WikiPage(object):
             else:
                 listener.wiki_page_changed(self, self.version, t, comment,
                                            author, remote_addr)
+        context=dict(
+            version=self.version,
+            time=t,
+            comment=comment,
+            author=author,
+            remote_addr=remote_addr,
+            source_action="save")
+        if self.version == 1:
+            ResourceSystem(self.env).resource_created(self, context)
+        else:
+            ResourceSystem(self.env).resource_changed(
+                self,
+                old_values=dict(
+                    name=self.name,
+                    readonly = self.old_readonly,
+                    text = self.old_text),
+                context = context)
 
         self.old_readonly = self.readonly
         self.old_text = self.text
@@ -196,6 +215,15 @@ class WikiPage(object):
             if hasattr(listener, 'wiki_page_renamed'):
                 listener.wiki_page_renamed(self, old_name)
 
+        ResourceSystem(self.env).resource_changed(
+            self,
+            old_values=dict(
+                name=old_name,
+                readonly = self.readonly,
+                text = self.text),
+            context=dict(source_action="rename")
+        )
+
     def get_history(self, db=None):
         """Retrieve the edit history of a wiki page.
 

Modified: incubator/bloodhound/branches/0.5/trac/trac/wiki/tests/model.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/0.5/trac/trac/wiki/tests/model.py?rev=1456798&r1=1456797&r2=1456798&view=diff
==============================================================================
--- incubator/bloodhound/branches/0.5/trac/trac/wiki/tests/model.py (original)
+++ incubator/bloodhound/branches/0.5/trac/trac/wiki/tests/model.py Fri Mar 15 
08:18:24 2013
@@ -12,6 +12,7 @@ import unittest
 from trac.attachment import Attachment
 from trac.core import *
 from trac.test import EnvironmentStub
+from trac.tests.resource import TestResourceChangeListener
 from trac.util.datefmt import utc, to_utimestamp
 from trac.wiki import WikiPage, IWikiChangeListener
 
@@ -266,9 +267,83 @@ class WikiPageTestCase(unittest.TestCase
             page = WikiPage(self.env, 'TestPage')
             self.assertRaises(TracError, page.rename, name)
 
+class WikiResourceChangeListenerTestCase(unittest.TestCase):
+    INITIAL_NAME = "Wiki page 1"
+    INITIAL_TEXT = "some text"
+    INITIAL_AUTHOR = "anAuthor"
+    INITIAL_COMMENT = "some comment"
+    INITIAL_REMOTE_ADDRESS = "::1"
+
+    def setUp(self):
+        self.env = EnvironmentStub(default_data=True)
+        self.listener = TestResourceChangeListener(self.env)
+        self.listener.resource_type = WikiPage
+        self.listener.callback = self.listener_callback
+
+    def tearDown(self):
+        self.env.reset_db()
+
+    def test_change_listener_created(self):
+        self._create_wiki_page(self.INITIAL_NAME)
+        self.assertEqual('created', self.listener.action)
+        self.assertIsInstance(self.listener.resource, WikiPage)
+        self.assertEqual(self.INITIAL_NAME, self.wiki_name)
+        self.assertEqual(self.INITIAL_TEXT, self.wiki_text)
+
+    def test_change_listener_text_changed(self):
+        wiki_page = self._create_wiki_page(self.INITIAL_NAME)
+        CHANGED_TEXT = "some other text"
+        wiki_page.text = CHANGED_TEXT
+        wiki_page.save("author1", "renamed_comment", "::2")
+        self.assertEqual('changed', self.listener.action)
+        self.assertIsInstance(self.listener.resource, WikiPage)
+        self.assertEqual(self.INITIAL_NAME, self.wiki_name)
+        self.assertEqual(CHANGED_TEXT, self.wiki_text)
+        self.assertEqual(
+            dict(text=self.INITIAL_TEXT, readonly=0, name=self.INITIAL_NAME),
+            self.listener.old_values)
+        self.assertEqual("save", self.listener.context["source_action"])
+
+    def test_change_listener_renamed(self):
+        wiki_page = self._create_wiki_page(self.INITIAL_NAME)
+        CHANGED_NAME = "NewWikiName"
+        wiki_page.rename(CHANGED_NAME)
+        self.assertEqual('changed', self.listener.action)
+        self.assertIsInstance(self.listener.resource, WikiPage)
+        self.assertEqual(CHANGED_NAME, self.wiki_name)
+        self.assertEqual(self.INITIAL_TEXT, self.wiki_text)
+        self.assertEqual(
+            dict(text=self.INITIAL_TEXT, readonly=0, name=self.INITIAL_NAME),
+            self.listener.old_values)
+        self.assertEqual("rename", self.listener.context["source_action"])
+
+    def test_change_listener_deleted(self):
+        wiki_page = self._create_wiki_page(self.INITIAL_NAME)
+        wiki_page.delete()
+        self.assertEqual('deleted', self.listener.action)
+        self.assertIsInstance(self.listener.resource, WikiPage)
+        self.assertEqual(self.INITIAL_NAME, self.wiki_name)
+
+    def _create_wiki_page(self, name=None):
+        name = name or self.INITIAL_NAME
+        wiki_page = WikiPage(self.env, name)
+        wiki_page.text = self.INITIAL_TEXT
+        wiki_page.save(
+            self.INITIAL_AUTHOR,
+            self.INITIAL_COMMENT,
+            self.INITIAL_REMOTE_ADDRESS)
+        return wiki_page
+
+    def listener_callback(self, action, resource, context, old_values = None):
+        self.wiki_name = resource.name
+        self.wiki_text = resource.text
 
 def suite():
-    return unittest.makeSuite(WikiPageTestCase, 'test')
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(WikiPageTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(
+        WikiResourceChangeListenerTestCase, 'test'))
+    return suite
 
 if __name__ == '__main__':
     unittest.main(defaultTest='suite')


Reply via email to