[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