[Zope3-checkins] CVS: Zope3/src/zope/products/zwiki - I18N.txt:1.1
INSTALL.txt:1.1 LICENSE.txt:1.1 README.txt:1.1 TODO.txt:1.1
VERSION.txt:1.1 __init__.py:1.1 configure.zcml:1.1
diff.py:1.1 index.py:1.1 interfaces.py:1.1 traversal.py:1.1
wiki.py:1.1 wikipage.py:1.1
K.Narasimha Murthy
nmurthy at zeomega.com
Tue Dec 16 05:05:53 EST 2003
Update of /cvs-repository/Zope3/src/zope/products/zwiki
In directory cvs.zope.org:/tmp/cvs-serv10613
Added Files:
I18N.txt INSTALL.txt LICENSE.txt README.txt TODO.txt
VERSION.txt __init__.py configure.zcml diff.py index.py
interfaces.py traversal.py wiki.py wikipage.py
Log Message:
Moved zwiki product from zopeproducts to zope.products, fixed the bugs and fixed test cases.
=== Added File Zope3/src/zope/products/zwiki/I18N.txt ===
Internationalization (I18n) and Localalization (L10n)
=====================================================
Crating/Updating Message Catalog Template (POT) Files
-----------------------------------------------------
0. Install 'zwiki' in '<zope3>/src/zopeproducts'.
1. Set the the Python path::
export PYTHONPATH=<zope3>/src
2. Go into the 'locales' directory and execute extract.py::
python2.2 extract.py
Updating Message Catalog (PO) Files
-----------------------------------
1. For each language do simply::
msgmerge -U de/LC_MESSAGES/wiki.po wiki.pot
2. Translate the updated PO file.
Note: KBabel is a great tool for this task!
Compiling Message Catalogs (PO) to binary (MO) Files
----------------------------------------------------
1. Go to the right directory, such as '<zwiki>/locales/de/LC_MESSAGES'.
2. Run the following command::
msgfmt -o wiki.mo wiki.po
=== Added File Zope3/src/zope/products/zwiki/INSTALL.txt ===
Installation
============
- create 'zopeproducts' inside your Zope 3 installation src directory
- add an empty '__init__.py' to zopeproducts
- copy the 'zwiki' folder to 'zopeproducts'
- add the following line to products.zcml file::
<include package='zopeproducts.zwiki' />
- You need to define the following role declarations to your user in order
to use the zwiki product effectively.
<grant role="zwiki.Admin" principal="user" />
<grant role="zwiki.Editor" principal="user" />
<grant role="zwiki.User" principal="user" />
<grant role="zwiki.User" principal="anybody" />
- (Optional) If you want restructured text support, you need to install the
**CVS** version of docutils, which you can retrieve from
http://docutils.sf.net.
Usage
=====
1. To see Wikis in action, go into the management interface and add a Wiki
object named 'wiki'. Leave the two preselected options.
2. To enter the end user interface, enter::
http://localhost:8080/++skin++wiki/wiki
=== Added File Zope3/src/zope/products/zwiki/LICENSE.txt ===
Zope Public License (ZPL) Version 2.0
-----------------------------------------------
This software is Copyright (c) Zope Corporation (tm) and
Contributors. All rights reserved.
This license has been certified as open source. It has also
been designated as GPL compatible by the Free Software
Foundation (FSF).
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the
following conditions are met:
1. Redistributions in source code must retain the above
copyright notice, this list of conditions, and the following
disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions, and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
3. The name Zope Corporation (tm) must not be used to
endorse or promote products derived from this software
without prior written permission from Zope Corporation.
4. The right to distribute this software or to use it for
any purpose does not give you the right to use Servicemarks
(sm) or Trademarks (tm) of Zope Corporation. Use of them is
covered in a separate agreement (see
http://www.zope.com/Marks).
5. If any files are modified, you must cause the modified
files to carry prominent notices stating that you changed
the files and the date of any change.
Disclaimer
THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
This software consists of contributions made by Zope
Corporation and many individuals on behalf of Zope
Corporation. Specific attributions are listed in the
accompanying credits file.
=== Added File Zope3/src/zope/products/zwiki/README.txt ===
ZWiki for Zope 3
================
This product is a port/rewrite of the famous Zope 2 product
Zwiki. At the current stage only the most basic Wiki functionalities
are implemented and much more work needs to be done.
Features
--------
Rendering
- Plain Text
- reStructured Text (reST)
Wiki
- Table of Contents
- Mail Subscription for entire Wiki
- Full-text Search
Wiki Page
- Proper rendering of Wiki Links
- Edit Wiki Page
- Comment on a Wiki Page
- Declare Wiki Hierarchy (Parents)
- Local, WikiPage-based Mail Subscription
- Jumping to other Wikis
Miscellaneous
- Somewhat sophisticated rendering mechanism. New source types and
their render methods can now be configured (added) via ZCML.
- A fully independent skin called 'wiki'; Note that this skill
will be only useful in the context of a Wiki Page.
=== Added File Zope3/src/zope/products/zwiki/TODO.txt ===
To Do
=====
Tests
- Write tests for diff module
Rendering/Views
- Create custom HTMLDocument class for rendering the STX and ReST in Wiki
style.
- Make sure WebDAV works.
- Add File Extension recognition.
- Create a Management screen (advancedform) that is accessible for users
without management rights.
Other Features
- Make use of Traverser features; i.e. create links that include
parents...
- Check in Traverser that found subobj has self.context as parent.
- Activating diff support for edited Wiki Pages. The main issue right now
is to get to the old version of the text. so that we can execute the
Differ.
=== Added File Zope3/src/zope/products/zwiki/VERSION.txt ===
zwiki for z3 0.0.1
=== Added File Zope3/src/zope/products/zwiki/__init__.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""ZWiki for Zope 3
$Id: __init__.py,v 1.1 2003/12/16 10:05:52 nmurthy Exp $
"""
=== Added File Zope3/src/zope/products/zwiki/configure.zcml ===
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:event="http://namespaces.zope.org/event"
xmlns:translate="http://namespaces.zope.org/gts"
i18n_domain="zwiki"
>
<!-- Security definitions -->
<role
id="zwiki.User"
title="Wiki User"
description="Wiki visitors, which can only view and comment on wikis." />
<role
id="zwiki.Editor"
title="Wiki Editor"
description="The Wiki Editor can create and edit wikis." />
<role
id="zwiki.Admin"
title="Wiki Administrator"
description="The Wiki Admin can fully manage wiki pages." />
<permission
id="zope.products.zwiki.ViewWikiPage"
title="View Wiki Page"
description="View a Wiki Page." />
<grant
permission="zope.products.zwiki.ViewWikiPage"
role="zwiki.User" />
<permission
id="zope.products.zwiki.CommentWikiPage"
title="Comment on Wiki Page"
description="Make a comment on Wiki Page." />
<grant
permission="zope.products.zwiki.CommentWikiPage"
role="zwiki.User" />
<permission
id="zope.products.zwiki.AddWikiPage"
title="Add Wiki Page"
description="Add Wiki Page." />
<grant
permission="zope.products.zwiki.AddWikiPage"
role="zwiki.Editor" />
<permission
id="zope.products.zwiki.EditWikiPage"
title="Edit Wiki Page"
description="Edit Wiki Page." />
<grant
permission="zope.products.zwiki.EditWikiPage"
role="zwiki.Editor" />
<permission
id="zope.products.zwiki.DeleteWikiPage"
title="Delete Wiki Page"
description="Delete Wiki Page." />
<grant
permission="zope.products.zwiki.DeleteWikiPage"
role="zwiki.Admin" />
<permission
id="zope.products.zwiki.ReparentWikiPage"
title="Reparent Wiki Page"
description="Reparent a Wiki Page." />
<grant
permission="zope.products.zwiki.ReparentWikiPage"
role="zwiki.Admin"/>
<!-- Content declarations -->
<content class=".wiki.Wiki">
<implements interface="zope.app.interfaces.container.IContentContainer" />
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
<factory
id="Wiki"
permission="zope.ManageContent"
description="Minimal Wiki Page Container implementation " />
<require
permission="zope.View"
interface="zope.app.interfaces.container.IReadContainer"/>
<require
permission="zope.products.zwiki.AddWikiPage"
interface="zope.app.interfaces.container.IWriteContainer"/>
</content>
<!-- Mail Subscriptions support -->
<adapter
factory=".wikipage.MailSubscriptions"
provides=".interfaces.IMailSubscriptions"
for=".interfaces.IWiki" />
<content class=".wikipage.WikiPage">
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
<factory
id="WikiPage"
permission="zope.products.zwiki.AddWikiPage"
title="Wiki Page"
description="A Wiki Page" />
<!-- XXX: I am not sure whether this is safe. We probably have to split
the interface from the schema. -->
<allow interface=".interfaces.IWikiPage" />
<require
permission="zope.products.zwiki.AddWikiPage"
set_schema=".interfaces.IWikiPage" />
</content>
<adapter
factory=".wikipage.WikiPageHierarchyAdapter"
provides=".interfaces.IWikiPageHierarchy"
for=".interfaces.IWikiPage" />
<!-- Mail Subscriptions support -->
<adapter
factory=".wikipage.MailSubscriptions"
provides=".interfaces.IMailSubscriptions"
for=".interfaces.IWikiPage" />
<adapter
factory=".traversal.WikiPageTraversable"
provides="zope.app.interfaces.traversing.ITraversable"
for=".interfaces.IWikiPage" />
<adapter
factory="zope.products.zwiki.wikipage.SearchableText"
provides="zope.app.interfaces.index.text.ISearchableText"
for="zope.products.zwiki.interfaces.IWikiPage" />
<!-- WikiPage FTP configurations -->
<adapter
for=".interfaces.IWikiPage"
provides="zope.app.interfaces.file.IReadFile"
factory=".wikipage.WikiPageReadFile"
permission="zope.products.zwiki.ViewWikiPage"
/>
<adapter
for=".interfaces.IWikiPage"
provides="zope.app.interfaces.file.IWriteFile"
factory=".wikipage.WikiPageWriteFile"
permission="zope.products.zwiki.EditWikiPage"
/>
<!-- Wiki Index registration -->
<content class=".index.WikiTextIndex">
<require
permission="zope.ManageServices"
interface="zope.app.interfaces.index.text.IUITextIndex"
attributes="query"
/>
<factory
id="zope.products.zwiki.index.WikiTextIndex"
permission="zope.ManageServices"
/>
<implements
interface="zope.app.interfaces.services.query.IQueryProcessable"
/>
</content>
<!-- Register event listener for change mails -->
<event:subscribe
subscriber=".wikipage.mailer"
event_types="zope.app.interfaces.event.IObjectAddedEvent
zope.app.interfaces.event.IObjectModifiedEvent
zope.app.interfaces.event.IObjectRemovedEvent
zope.app.interfaces.event.IObjectMovedEvent" />
<!-- Register various browser related components, including all views -->
<include package=".browser" />
<!-- Register translations -->
<translate:registerTranslations directory="locales" />
</configure>
=== Added File Zope3/src/zope/products/zwiki/diff.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Browser View Components for WikiPages
$Id: diff.py,v 1.1 2003/12/16 10:05:52 nmurthy Exp $
"""
from difflib import ndiff
MAX_OLD_LINES_DISPLAY = 40
MAX_NEW_LINES_DISPLAY = 40
def textdiff(old_text, new_text, verbose=1):
"""
generate a plain text diff, optimized for human readability,
between two revisions of this page, numbering back from the latest.
Alternately, a and/or b texts can be specified.
"""
old = split(old_text, '\n')
new = split(new_text, '\n')
cruncher=ndiff.SequenceMatcher(
isjunk=lambda x: x in " \\t",
a=old,
b=new)
r = []
for tag, old_lo, old_hi, new_lo, new_hi in cruncher.get_opcodes():
if tag == 'replace':
if verbose: r.append('??changed:')
r = r + _abbreviateDiffLines(old[old_lo:old_hi],'-',
MAX_OLD_LINES_DISPLAY)
r = r + _abbreviateDiffLines(new[new_lo:new_hi],'',
MAX_NEW_LINES_DISPLAY)
r.append('')
elif tag == 'delete':
if verbose: r.append('--removed:')
r = r + _abbreviateDiffLines(old[old_lo:old_hi],'-',
MAX_OLD_LINES_DISPLAY)
r.append('')
elif tag == 'insert':
if verbose: r.append('++added:')
r = r + _abbreviateDiffLines(new[new_lo:new_hi],'',
MAX_NEW_LINES_DISPLAY)
r.append('')
elif tag == 'equal':
pass
else:
raise ValueError, 'unknown tag ' + `tag`
return '\n' + join(r, '\n')
def _abbreviateDiffLines(lines, prefix, maxlines=5):
output = []
if maxlines and len(lines) > maxlines:
extra = len(lines) - maxlines
for i in xrange(maxlines - 1):
output.append(prefix + lines[i])
output.append(prefix + "[%d more line%s...]" %
(extra, ((extra == 1) and '') or 's')) # not working
else:
for line in lines:
output.append(prefix + line)
return output
=== Added File Zope3/src/zope/products/zwiki/index.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""A custom Text Index for Wikis
$Id: index.py,v 1.1 2003/12/16 10:05:52 nmurthy Exp $
"""
from zope.app.index.text.index import TextIndex
from zope.products.zwiki.interfaces import IWikiPage
class WikiTextIndex(TextIndex):
def notify(wrapped_self, event):
"""An event occurred. Index or unindex the object in response."""
if IWikiPage.isImplementedBy(event.object):
super(WikiTextIndex, wrapped_self).notify(event)
=== Added File Zope3/src/zope/products/zwiki/interfaces.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""ZWiki Interface Declarations
This module defines the ZWiki relevant interfaces.
$Id: interfaces.py,v 1.1 2003/12/16 10:05:52 nmurthy Exp $
"""
from zope.interface import Interface
from zope.schema import TextLine, List, SourceText
from zope.schema.vocabulary import VocabularyField
from zope.app.interfaces.container import IContentContainer
from zope.i18n import MessageIDFactory
_ = MessageIDFactory('wiki')
class IWiki(IContentContainer):
"""A simple Wiki Page container.
A simple marker interface, so that we can define special views on
Wikis."""
class IWikiPage(Interface):
"""A single Wiki Page content object.
The Wiki page is a simple content object that stores the content
(source) and the source type of the wiki page."""
source = SourceText(
title=_(u"Source Text"),
description=_(u"Renderable source text of the Wiki Page."),
default=u"",
required=True)
type = VocabularyField(
title=_(u"Source Type"),
description=_(u"Type of the source text, e.g. structured text"),
default=u"reStructured Text (reST)",
required = True,
vocabulary = "SourceTypes")
def append(source):
"""Append some text to the existing source text."""
def comment(source, user):
"""Comment on the current Wiki; add comment to source."""
def getCommentCounter():
"""Returns the amount of written comments for this wiki page."""
class IWikiPageHierarchy(Interface):
"""This interface supports the virtual hierarchical structure of the Wiki
Pages."""
parents = List(
title = _(u"Wiki Page Parents"),
description = _(u"Parents of a a Wiki"),
value_type = (TextLine(title=_(u"Parent Name"),
description=_(u"Name of the parent wiki page.")),),
required=False)
def reparent(parents):
"""Reset the parents the Wiki page belongs to.
The parents attribute is a list of unicode strings that contain the
names of the parent wiki pages.
"""
def path():
"""Return the object path of the virtual Wiki Hierarchy.
The return value for this method should be a list of wiki objects
describing the path.
XXX: Wiki Pages can have several parents, so that we should be able to
have multiple paths; but let's not worry about that right now. At some
point this needs to be done though.
"""
def findChildren(recursive=True):
"""Returns a list of children for this wiki page.
If the recursive is True, the method recurses into all children
returning the entire sub-tree of this Wiki Page. Is the recursive
argument set to False, only the first level of children will be
returned.
"""
class IMailSubscriptions(Interface):
"""This interface allows you to retrieve a list of E-mails for
mailings. In our context """
def getSubscriptions():
"""Return a list of E-mails."""
def addSubscriptions(emails):
"""Add a bunch of subscriptions, but one would be okay as well."""
def removeSubscriptions(emails):
"""Remove a set of subscriptions."""
=== Added File Zope3/src/zope/products/zwiki/traversal.py ===
##############################################################################
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
##############################################################################
"""Specific HTTP
$Id: traversal.py,v 1.1 2003/12/16 10:05:52 nmurthy Exp $
"""
from zope.interface import implements
from zope.component import getDefaultViewName, queryView
from zope.publisher.interfaces import IPublishTraverse
from zope.products.zwiki.interfaces import IWikiPage
from zope.exceptions import NotFoundError
from zope.app.traversing import getParent
from zope.proxy import removeAllProxies
from zope.app.interfaces.traversing import ITraversable
from zope.app.traversing.namespace import UnexpectedParameters
class WikiPageTraverser:
implements(IPublishTraverse)
__used_for__ = IWikiPage
def __init__(self, page, request):
self.context = page
self.wiki = getParent(page)
self.request = request
def publishTraverse(self, request, name):
subob = self.wiki.get(name, None)
# XXX: Check that subobj has self.context as parent!
if subob is None:
view = queryView(self.context, name, request)
if view is not None:
return view
raise NotFoundError(self.context, name, request)
return removeAllProxies(subob)
def browserDefault(self, request):
c = self.context
view_name = getDefaultViewName(c, request)
view_uri = "@@%s" % view_name
return c, (view_uri,)
_marker = object()
class WikiPageTraversable:
"""Traverses wikipages via wiki itself and getattr.
"""
implements(ITraversable)
__used_for__ = IWikiPage
def __init__(self, page):
self._page = page
self._wiki = getParent(page)
def traverse(self, name, parameters, original_name, furtherPath):
if parameters:
raise UnexpectedParameters(parameters)
subobj = self._wiki.get(name, _marker)
if subobj is _marker:
subobj = getattr(self._page, name, _marker)
if subobj is _marker:
raise NotFoundError, original_name
return subobj
=== Added File Zope3/src/zope/products/zwiki/wiki.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Wiki implementation
$Id: wiki.py,v 1.1 2003/12/16 10:05:52 nmurthy Exp $
"""
from zope.interface import implements
from zope.app.content.folder import Folder
from zope.products.zwiki.interfaces import IWiki
class Wiki(Folder):
__doc__ = IWiki.__doc__
implements(IWiki)
=== Added File Zope3/src/zope/products/zwiki/wikipage.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Wiki implementation
$Id: wikipage.py,v 1.1 2003/12/16 10:05:52 nmurthy Exp $
"""
import smtplib
from persistence import Persistent
from zope.interface import implements
from zope.component import getAdapter
from zope.app.traversing import getParent, getName
from zope.app.interfaces.index.text import ISearchableText
from zope.app.interfaces.file import IReadFile, IWriteFile
from zope.app.interfaces.annotation import IAnnotations
from zope.app.interfaces.event import ISubscriber
from zope.app.interfaces.event import IObjectAddedEvent, IObjectModifiedEvent
from zope.app.interfaces.event import IObjectRemovedEvent, IObjectMovedEvent
from zope.products.zwiki.interfaces import \
IWiki, IWikiPage, IWikiPageHierarchy, IMailSubscriptions
__metaclass__ = type
HierarchyKey = 'http://www.zope.org/zwiki#1.0/PageHierarchy/parents'
SubscriberKey = 'http://www.zope.org/zwiki#1.0/MailSubscriptions/emails'
class WikiPage(Persistent):
__doc__ = IWikiPage.__doc__
implements(IWikiPage)
# See zope.products.zwiki.interfaces.IWikiPage
source = u''
# See zope.products.zwiki.interfaces.IWikiPage
type = u'reStructured Text (reST)'
def __init__(self):
self.__comments = 1
def append(self, source):
"See zope.products.zwiki.interfaces.IWikiPage"
self.source += source
def comment(self, comment):
"See zope.products.zwiki.interfaces.IWikiPage"
self.__comments += 1
self.append(comment)
def getCommentCounter(self):
"See zope.products.zwiki.interfaces.IWikiPage"
return self.__comments
class WikiPageHierarchyAdapter:
__doc__ = IWikiPageHierarchy.__doc__
implements(IWikiPageHierarchy)
__used_for__ = IWikiPage
def __init__(self, context):
self.context = context
self._annotations = getAdapter(context, IAnnotations)
if not self._annotations.get(HierarchyKey):
self._annotations[HierarchyKey] = ()
def reparent(self, parents):
"See zope.products.zwiki.interfaces.IWikiPageHierarchy"
self.setParents(parents)
def setParents(self, parents):
self._annotations[HierarchyKey] = tuple(parents)
def getParents(self):
return self._annotations[HierarchyKey]
parents = property(getParents, setParents)
def path(self):
"See zope.products.zwiki.interfaces.IWikiPageHierarchy"
# XXX: Allow for multpile parents
if not self.getParents():
return [self.context]
wiki = getParent(self.context)
name = self.getParents()[0]
hier = getAdapter(wiki[name], IWikiPageHierarchy)
return hier.path() + [self.context]
def findChildren(self, recursive=True):
"See zope.products.zwiki.interfaces.IWikiPageHierarchy"
wiki = getParent(self.context)
contextName = getName(self.context)
children = []
for pageName in wiki:
hier = getAdapter(wiki[pageName], IWikiPageHierarchy)
if contextName in hier.getParents():
if recursive:
subs = hier.findChildren()
else:
subs = ()
children.append((wiki[pageName], subs))
return tuple(children)
# Adapters for file-system style access
class WikiPageReadFile:
"""Adapter for letting a Wiki Page look like a regular readable file."""
implements(IReadFile)
__used_for__ = IWikiPage
def __init__(self, context):
self.context = context
def read(self):
"""See zope.app.interfaces.file.IReadFile"""
return self.context.source
def size(self):
"""See zope.app.interfaces.file.IReadFile"""
return len(self.context.source)
class WikiPageWriteFile:
"""Adapter for letting a Wiki Page look like a regular writable file."""
implements(IWriteFile)
__used_for__ = IWikiPage
def __init__(self, context):
self.context = context
def write(self, data):
"""See zope.app.interfaces.file.IWriteFile"""
self.context.source = unicode(data)
# Adapter for ISearchableText
class SearchableText:
"""This adapter provides an API that allows the Wiki Pages to be indexed
by the Text Index."""
implements(ISearchableText)
__used_for__ = IWikiPage
def __init__(self, page):
self.page = page
def getSearchableText(self):
return [unicode(self.page.source)]
# Component to fullfill mail subscriptions
class MailSubscriptions:
"""An adapter for WikiPages to provide an interface for collecting E-mails
for sending out change notices."""
implements(IMailSubscriptions)
__used_for__ = IWikiPage, IWiki
def __init__(self, context):
self.context = context
self._annotations = getAdapter(context, IAnnotations)
if not self._annotations.get(SubscriberKey):
self._annotations[SubscriberKey] = ()
def getSubscriptions(self):
"See zope.products.zwiki.interfaces.IMailSubscriptions"
return self._annotations[SubscriberKey]
def addSubscriptions(self, emails):
"See zope.products.zwiki.interfaces.IMailSubscriptions"
subscribers = list(self._annotations[SubscriberKey])
for email in emails:
# XXX: Make sure these are actually E-mail addresses.
if email not in subscribers:
subscribers.append(email.strip())
self._annotations[SubscriberKey] = tuple(subscribers)
def removeSubscriptions(self, emails):
"See zope.products.zwiki.interfaces.IMailSubscriptions"
subscribers = list(self._annotations[SubscriberKey])
for email in emails:
if email in subscribers:
subscribers.remove(email)
self._annotations[SubscriberKey] = tuple(subscribers)
class WikiMailer:
"""Class to handle all outgoing mail."""
implements(ISubscriber)
def __init__(self, host="localhost", port="25"):
"""Initialize the the object."""
self.host = host
self.port = port
def notify(self, event):
"""See zope.app.interfaces.event.ISubscriber"""
if IWikiPage.isImplementedBy(event.object):
if IObjectAddedEvent.isImplementedBy(event):
self.handleAdded(event.object)
elif IObjectModifiedEvent.isImplementedBy(event):
self.handleModified(event.object)
elif IObjectRemovedEvent.isImplementedBy(event):
self.handleRemoved(event.object)
def handleAdded(self, object):
subject = 'Added: '+getName(object)
emails = self.getAllSubscribers(object)
body = object.source
self.mail(emails, subject, body)
def handleModified(self, object):
# XXX: Should have some nice diff code here.
# from diff import textdiff
subject = 'Modified: '+getName(object)
emails = self.getAllSubscribers(object)
body = object.source
self.mail(emails, subject, body)
def handleRemoved(self, object):
subject = 'Removed: '+getName(object)
emails = self.getAllSubscribers(object)
body = subject
self.mail(emails, subject, body)
def getAllSubscribers(self, object):
"""Retrieves all email subscribers by looking into the local Wiki Page
and into the Wiki for the global subscriptions."""
emails = tuple(getAdapter(object,
IMailSubscriptions).getSubscriptions())
emails += tuple(getAdapter(getParent(object),
IMailSubscriptions).getSubscriptions())
return emails
def mail(self, emails, subject, body):
"""Mail out the Wiki change message."""
if not emails:
return
msg = 'Subject: %s\n\n\n%s' %(subject, body)
server = smtplib.SMTP(self.host, self.port)
server.set_debuglevel(0)
server.sendmail('wiki at zope3.org', emails, msg)
server.quit()
# Create a global mailer object.
mailer = WikiMailer()
More information about the Zope3-Checkins
mailing list