incubator-bloodhound-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrej Golcov <and...@digiverse.si>
Subject Re: svn commit: r1449780 - in /incubator/bloodhound/trunk/trac/trac/ticket: api.py model.py tests/model.py
Date Mon, 25 Feb 2013 17:19:17 GMT
As previously  discussed on the mailing list, a new generic interface
IResourceChangeListener should be introduced.
The commit introduces the interface and provides the first usage of
the interface for Component resource.
I would kindly ask community to review the change and provide feedback.

For the next step, I plan to add usage of IResourceChangeListener by
other resources such as ticket, milestone, version and other
AbstractEnum based resources.

Cheers, Andrej

On 25 February 2013 18:10,  <andrej@apache.org> wrote:
> 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