From d7d6558b3a34d1ed3e083d1cccfc386a8f7c28d1 Mon Sep 17 00:00:00 2001 From: helmutm Date: Fri, 6 Feb 2009 16:05:05 +0000 Subject: [PATCH] add track-base link and link manager implementation git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@3213 fd906abe-77d9-0310-91a1-e0d9ade77398 --- wiki/README.txt | 8 ++- wiki/base/link.py | 2 +- wiki/interfaces.py | 4 ++ wiki/tests.py | 4 ++ wiki/tracking/__init__.py | 3 + wiki/tracking/link.py | 140 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 wiki/tracking/__init__.py create mode 100644 wiki/tracking/link.py diff --git a/wiki/README.txt b/wiki/README.txt index 8befe1d..db0ecdd 100644 --- a/wiki/README.txt +++ b/wiki/README.txt @@ -14,9 +14,13 @@ An Example for an Elementary Wiki Structure >>> from cybertools.wiki.base.wiki import WikiManager, Wiki We create a wiki manager with one wiki that in turn contains a simple -start page. +start page. We also set the ``linkManager`` configuration option explicitly +to make sure the btree-based tracking link manager will be used. >>> manager = WikiManager() + + >>> linkManagerName = 'tracking' + >>> manager.linkManager = linkManagerName >>> wiki = manager.addWiki(Wiki('demo_wiki')) >>> startPage = wiki.createPage('start_page') @@ -56,7 +60,7 @@ Let's now have a look at the link manager - it should have recorded the link from the page content. >>> from cybertools.wiki.interfaces import ILinkManager - >>> linkManager = manager.getPlugin(ILinkManager, 'basic') + >>> linkManager = manager.getPlugin(ILinkManager, linkManagerName) >>> links = linkManager.links >>> len(links) 1 diff --git a/wiki/base/link.py b/wiki/base/link.py index 5c42a77..8bdbacb 100644 --- a/wiki/base/link.py +++ b/wiki/base/link.py @@ -116,7 +116,7 @@ class LinkProcessor(object): lm = wiki.getManager().getPlugin(ILinkManager, lmName) existing = lm.query(source=sourceUid, name=self.targetName) if existing: - link = existing[0] + link = list(existing)[0] target = manager.getObject(link.target) else: target = wiki.getPage(self.targetName) diff --git a/wiki/interfaces.py b/wiki/interfaces.py index 8e903d4..d7b8492 100644 --- a/wiki/interfaces.py +++ b/wiki/interfaces.py @@ -203,6 +203,10 @@ class ILinkManager(Interface): Additional (optional) criteria may be supported by the implementation. """ + def __iter__(): + """ Return an iterator of all links. + """ + class ILink(Interface): """ A hyperlink between two local or foreign objects. diff --git a/wiki/tests.py b/wiki/tests.py index 1921ee1..d27e465 100755 --- a/wiki/tests.py +++ b/wiki/tests.py @@ -21,6 +21,7 @@ from cybertools.wiki.dcu.html import Writer as DocutilsHTMLWriter from cybertools.wiki.dcu.rstx import Parser as DocutilsRstxParser from cybertools.wiki.dcu import process from cybertools.wiki.interfaces import IWiki, IWikiPage +from cybertools.wiki.tracking import link class WikiURL(object): @@ -58,6 +59,9 @@ def setUp(testCase): component.provideUtility(DocutilsRstxParser(), name='docutils.rstx') component.provideAdapter(process.Reference, name='default') component.provideUtility(LinkManager(), name='basic') + component.provideAdapter(link.LinkManager) + links = link.setupLinkManager(None) + component.provideUtility(links, name='tracking') def test_suite(): diff --git a/wiki/tracking/__init__.py b/wiki/tracking/__init__.py new file mode 100644 index 0000000..38314f3 --- /dev/null +++ b/wiki/tracking/__init__.py @@ -0,0 +1,3 @@ +""" +$Id$ +""" diff --git a/wiki/tracking/link.py b/wiki/tracking/link.py new file mode 100644 index 0000000..3aa5521 --- /dev/null +++ b/wiki/tracking/link.py @@ -0,0 +1,140 @@ +# +# Copyright (c) 2009 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +Planning and recording activities (work items). + +$Id$ +""" + +from zope import component +from zope.component import adapts +from zope.interface import implementer, implements +from zope.traversing.api import getName, getParent + +from cybertools.stateful.base import Stateful +from cybertools.stateful.definition import StatesDefinition +from cybertools.stateful.definition import State, Transition +from cybertools.stateful.interfaces import IStatesDefinition +from cybertools.tracking.btree import TrackingStorage, Track +from cybertools.tracking.interfaces import ITrackingStorage +from cybertools.wiki.base.link import Link as BaseLink +from cybertools.wiki.base.link import LinkManager as BaseLinkManager +from cybertools.wiki.interfaces import ILink, ILinkManager + + +@implementer(IStatesDefinition) +def linkStates(): + return StatesDefinition('wiki.linkStates', + State('valid', 'valid', ('invalidate',), color='green'), + State('invalid', 'invalid', ('validate',), color='red'), + # transitions: + Transition('invalidate', 'invalidate', 'invalid'), + Transition('validate', 'validate', 'valid'), + initialState='valid') + + +class Link(BaseLink, Stateful, Track): + """ A link that is stored as a track in a tracking storage. + """ + + statesDefinition = 'wiki.linkStates' + + metadata_attributes = Track.metadata_attributes + ('name', 'targetId') + index_attributes = metadata_attributes + typeName = 'Link' + + def __init__(self, taskId, runId, userName, data={}): + self.name = data.pop('name', '???') + self.targetId = data.pop('targetId', '') + Track.__init__(self, taskId, runId, userName, data={}) + + @property + def identifier(self): + return self.__name__ + #return getName(self) + + @property + def source(self): + return self.taskId + + @property + def target(self): + return self.targetId + + def __getattr__(self, k): + if k not in ILink: + raise AttributeError(k) + return self.data.get(k) + + def getManager(self): + return getParent(self) + + # IStateful + + def getStatesDefinition(self): + return component.getUtility(IStatesDefinition, name=self.statesDefinition) + + +class LinkManager(BaseLinkManager): + """ A tracking storage adapter managing wiki links. + """ + + adapts(ITrackingStorage) + + def __init__(self, context): + self.context = context + + def getLink(self, identifier): + return self.context.get(identifier) + + def query(self, source=None, target=None, name=None, **kw): + criteria = kw + if source is not None: + criteria['taskId'] = source + if target is not None: + criteria['targetId'] = target + if name is not None: + criteria['name'] = name + return self.context.query(**criteria) + + def createLink(self, name, source, target, **kw): + taskId = source + runId = kw.pop('runId', 0) or 0 + userName = kw.pop('userName', '') or '' + if not runId: + runId = self.context.startRun() + kw['name'] = name + kw['targetId'] = target + trackId = self.context.saveUserTrack(taskId, runId, userName, kw) + track = self.context[trackId] + return track + + def removeLink(self, link): + id = link.identifier + if id in self.context: + del self.context[id] + + @property + def links(self): + return self.context + + +def setupLinkManager(manager): + ts = TrackingStorage(trackFactory=Link) + return ILinkManager(ts)