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')