incubator-bloodhound-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From and...@apache.org
Subject svn commit: r1449780 - in /incubator/bloodhound/trunk/trac/trac/ticket: api.py model.py tests/model.py
Date Mon, 25 Feb 2013 17:10:42 GMT
Author: andrej
Date: Mon Feb 25 17:10:42 2013
New Revision: 1449780

URL: http://svn.apache.org/r1449780
Log:
patch Trac to enable genereic IResourceChangeListener interfce required for support of consistancy
between DB and index (#394, #411)

Modified:
    incubator/bloodhound/trunk/trac/trac/ticket/api.py
    incubator/bloodhound/trunk/trac/trac/ticket/model.py
    incubator/bloodhound/trunk/trac/trac/ticket/tests/model.py

Modified: incubator/bloodhound/trunk/trac/trac/ticket/api.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/api.py?rev=1449780&r1=1449779&r2=1449780&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/api.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/api.py Mon Feb 25 17:10:42 2013
@@ -156,6 +156,31 @@ 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."""
@@ -193,6 +218,7 @@ 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/trunk/trac/trac/ticket/model.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/model.py?rev=1449780&r1=1449779&r2=1449780&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/model.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/model.py Mon Feb 25 17:10:42 2013
@@ -844,9 +844,12 @@ class Component(object):
         with self.env.db_transaction as db:
             self.env.log.info("Deleting component %s", self.name)
             db("DELETE FROM component WHERE name=%s", (self.name,))
-            self.name = self._old_name = None
             TicketSystem(self.env).reset_ticket_fields()
 
+        for listener in TicketSystem(self.env).resource_change_listeners:
+            listener.resource_deleted(self)
+        self.name = self._old_name = None
+
     def insert(self, db=None):
         """Insert a new component.
 
@@ -866,6 +869,9 @@ 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)
+
     def update(self, db=None):
         """Update the component.
 
@@ -877,6 +883,7 @@ class Component(object):
         if not self.name:
             raise TracError(_("Invalid component name."))
 
+        old_name = self._old_name
         with self.env.db_transaction as db:
             self.env.log.info("Updating component '%s'", self.name)
             db("""UPDATE component SET name=%s,owner=%s, description=%s
@@ -890,6 +897,10 @@ class Component(object):
                 self._old_name = self.name
             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)
+
     @classmethod
     def select(cls, env, db=None):
         """

Modified: incubator/bloodhound/trunk/trac/trac/ticket/tests/model.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/tests/model.py?rev=1449780&r1=1449779&r2=1449780&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/tests/model.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/tests/model.py Mon Feb 25 17:10:42 2013
@@ -15,7 +15,8 @@ from trac.ticket.model import (
     Ticket, Component, Milestone, Priority, Type, Version
 )
 from trac.ticket.api import (
-    IMilestoneChangeListener, ITicketChangeListener, TicketSystem
+    IMilestoneChangeListener, ITicketChangeListener, TicketSystem,
+    IResourceChangeListener,
 )
 from trac.test import EnvironmentStub
 from trac.util.datefmt import from_utimestamp, to_utimestamp, utc
@@ -1005,6 +1006,27 @@ 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):
 
@@ -1041,6 +1063,49 @@ 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):



Mime
View raw message