[Zope3-checkins] CVS: Products3/demo/smileyservice - __init__.py:1.1 configure.zcml:1.1 globalservice.py:1.1 interfaces.py:1.1 localservice.py:1.1 meta.zcml:1.1 metaconfigure.py:1.1 metadirectives.py:1.1

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Aug 22 18:27:35 EDT 2003


Update of /cvs-repository/Products3/demo/smileyservice
In directory cvs.zope.org:/tmp/cvs-serv5789/smileyservice

Added Files:
	__init__.py configure.zcml globalservice.py interfaces.py 
	localservice.py meta.zcml metaconfigure.py metadirectives.py 
Log Message:
Initial checkin of the Smiley Service. :-)

This service registers smiley text representations and their corresponding
url to an image representation. This implements a global and a local 
version. In order to make the implementation more interesting, I also support
themes, which are basically collections of similar icons. (Thanks goes to
dreamcatcher, who gave me the idea.)

In the local version of the service I implemented Themes using the new 
named utility/service pattern.

Since the service is pretty much useless without being used, I also extended
the messageboard example by another step using this service. This also 
keeps a common theme is the Devel Cookbook, which is good (thanks to 
philliKON for the tip). The new step will follow soon. This also gives me
a good base for a vocabulary and vocabulary widget, which I assume will be-
come step 14.

Finally, this product was written for the Zope Devel Cookbook. It will be 
covered in the "New Registries via Services" and "Writing Local Services".


=== Added File Products3/demo/smileyservice/__init__.py ===


=== Added File Products3/demo/smileyservice/configure.zcml ===
<configure 
    xmlns:zope="http://namespaces.zope.org/zope"
    xmlns="http://namespaces.zope.org/smiley"
    i18n_domain="smileyservice">

<!-- Global Smiley Service -->
  <zope:include file="meta.zcml" />

  <zope:serviceType 
      id="Smileys" 
      interface="zopeproducts.demo.smileyservice.interfaces.ISmileyService"/>

  <zope:service 
      serviceType="Smileys" 
      component="zopeproducts.demo.smileyservice.globalservice.smileyService"/>

  <smileys theme="plain">
    <smiley text=":D"   file="./smileys/plain/biggrin.png"/>
    <smiley text=":-D"  file="./smileys/plain/biggrin.png"/>
    <smiley text=":/"   file="./smileys/plain/confused.png"/>
    <smiley text=":-/"  file="./smileys/plain/confused.png"/>
    <smiley text="8)"   file="./smileys/plain/cool.png"/>
    <smiley text="8-)"  file="./smileys/plain/cool.png"/>
    <smiley text=":o"   file="./smileys/plain/oh.png"/>
    <smiley text=":-o"  file="./smileys/plain/oh.png"/>
    <smiley text=":("   file="./smileys/plain/sad.png"/>
    <smiley text=":-("  file="./smileys/plain/sad.png"/>
    <smiley text=":)"   file="./smileys/plain/smile.png"/>
    <smiley text=":-)"  file="./smileys/plain/smile.png"/>
    <smiley text=":P"   file="./smileys/plain/tongue.png"/>
    <smiley text=":-P"  file="./smileys/plain/tongue.png"/>
    <smiley text=";)"   file="./smileys/plain/wink.png"/>
    <smiley text=";-)"  file="./smileys/plain/wink.png"/>
  </smileys>

  <smileys theme="yazoo">
    <smiley text=":D"   file="./smileys/yazoo/biggrin.png"/>
    <smiley text=":-D"  file="./smileys/yazoo/biggrin.png"/>
    <smiley text=":/"   file="./smileys/yazoo/confused.png"/>
    <smiley text=":-/"  file="./smileys/yazoo/confused.png"/>
    <smiley text="8)"   file="./smileys/yazoo/cool.png"/>
    <smiley text="8-)"  file="./smileys/yazoo/cool.png"/>
    <smiley text=":o"   file="./smileys/yazoo/oh.png"/>
    <smiley text=":-o"  file="./smileys/yazoo/oh.png"/>
    <smiley text=":("   file="./smileys/yazoo/sad.png"/>
    <smiley text=":-("  file="./smileys/yazoo/sad.png"/>
    <smiley text=":)"   file="./smileys/yazoo/smile.png"/>
    <smiley text=":-)"  file="./smileys/yazoo/smile.png"/>
    <smiley text=":P"   file="./smileys/yazoo/tongue.png"/>
    <smiley text=":-P"  file="./smileys/yazoo/tongue.png"/>
    <smiley text=";)"   file="./smileys/yazoo/wink.png"/>
    <smiley text=";-)"  file="./smileys/yazoo/wink.png"/>
  </smileys>

  <defaultTheme theme="plain" />


<!-- Local Smiley Service -->
  <zope:content class=".localservice.LocalSmileyService">
    <zope:factory
        id="zope.services.SmileyService"
        permission="zope.ManageServices"
        title="Smiley Service"
        description="A Smiley Service" />

    <zope:require
        permission="zope.ManageServices"
        interface=
            "zopeproducts.demo.smileyservice.interfaces.ILocalSmileyService" />

    <zope:require
        permission="zope.ManageServices"
        interface="zope.app.interfaces.services.registration.IRegistry" />
  </zope:content>

  <zope:content class=".localservice.Theme">

    <zope:factory
        id="zope.services.SmileyService.Theme"
        permission="zope.ManageServices"
        title="Smiley Theme"
        description="A Smiley Theme" />

    <zope:allow
        interface="zope.app.interfaces.container.IReadContainer" />

    <zope:require
        permission="zope.ManageServices"
        interface="zope.app.interfaces.container.IWriteContainer" />

    <zope:implements
        interface="zope.app.interfaces.services.utility.ILocalUtility" />

    <zope:implements
        interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />

    <zope:require
        permission="zope.ManageServices"
        interface=".interfaces.ITheme"
        set_schema=".interfaces.ITheme" />

  </zope:content>

  <zope:include package=".browser" />

</configure>


=== Added File Products3/demo/smileyservice/globalservice.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.
#
##############################################################################
"""Global Smiley Service Implementation

$Id: globalservice.py,v 1.1 2003/08/22 21:27:33 srichter Exp $
"""
from zope.app import zapi
from zope.app.interfaces.traversing import IContainmentRoot
from zope.component.exceptions import ComponentLookupError
from zope.interface import implements
from zopeproducts.demo.smileyservice.interfaces import IGlobalSmileyService

class Root:
    implements(IContainmentRoot)

class GlobalSmileyService:
    __doc__ = IGlobalSmileyService.__doc__

    implements(IGlobalSmileyService)

    # See zopeproducts.demo.smileyservice.interfaces.ISmileyService
    defaultTheme = "default"

    def __init__(self):
        self.__themes = {}

    def getSmiley(self, text, request, theme=None):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        smiley = self.querySmiley(text, request, theme)
        if smiley is None:
            raise ComponentLookupError, 'Smiley not found.'
        return smiley

    def querySmiley(self, text, request, theme=None, default=None):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        if theme is None:
            theme = self.defaultTheme
        if theme not in self.__themes or self.__themes[theme].get(text) is None:
            return default
        root_url = str(zapi.getView(Root(), 'absolute_url', request))
        return root_url + '/' + self.__themes[theme][text]

    def getThemes(self):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        return self.__themes.keys()

    def getSmileysMapping(self, request, theme=None):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        if theme is None:
            theme = self.defaultTheme
        
        smileys = self.__themes.get(theme, {}).copy()
        root_url = str(zapi.getView(Root(), 'absolute_url', request))
        for name, smiley in smileys.items():
            smileys[name] = root_url + '/' + smiley

        return smileys

    def provideSmiley(self, text, smiley_path, theme):
        "See zopeproducts.demo.smileyservice.interfaces.IGlobalSmileyService"
        themeDict = self.__themes.setdefault(theme, {})
        themeDict[text] = smiley_path


smileyService = GlobalSmileyService()

_clear = smileyService.__init__
provideSmiley = smileyService.provideSmiley

def defaultTheme(theme):
    smileyService.defaultTheme = theme


=== Added File Products3/demo/smileyservice/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.
#
##############################################################################
"""Smiley Service Interfaces

$Id: interfaces.py,v 1.1 2003/08/22 21:27:33 srichter Exp $
"""
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.interface import Interface
from zope.schema import BytesLine

class ISmileyService(Interface):
    """The smiley service converts smiley text representations to a URL
    linking to a real smiley image.

    In the following documentation 'smiley' refers to a URL that represents a
    smiley image. This service does not deal at all the image itself or its
    registration.
    """

    defaultTheme = BytesLine(
        title=_("Default Theme"),
        description=_("Specifies the theme that is usually used."),
        default=None,
        required=False)

    def getSmiley(text, request, theme=None):
        """Returns a smiley for the given text and theme.

        If no theme was specified the default theme is used.

        If no smiley was found, a ComponentLookupError should be raised.
        """

    def querySmiley(text, request, theme=None, default=None):
        """Returns a smiley for the given text and theme.

        If no theme was specified the default theme is used.

        If no smiley was found, the default value is returned.
        """

    def getThemes():
        """Returns a list of available theme names."""

    def getSmileysMapping(request, theme=None):
        """Return a mapping of text to URL.

        This is incredibly useful when actually attempting to substitute the
        smiley texts with a URL.
        """


class IGlobalSmileyService(ISmileyService):
    """Global version of the SmileyService, which deals with the write
    interface."""

    def provideSmiley(text, smiley_path, theme):
        """Provide a smiley for the service."""


class ITheme(Interface):
    """A theme is a collection of smileys having a stylistic theme.

    Themes are intened to be implemented as named utilities, which will be
    available via a local smiley service.
    """

    def getSmiley(text, request):
        """Returns a smiley for the given text and theme.

        If no smiley was found, a ComponentLookupError should be raised.
        """

    def querySmiley(text, request, default=None):
        """Returns a smiley for the given text and theme.

        If no smiley was found, the default value is returned.
        """

    def getSmileysMapping(request):
        """Return a mapping of text to URL.

        This is incredibly useful when actually attempting to substitute the
        smiley texts with a URL.
        """


class ILocalSmileyService(ISmileyService):
    """A local smiley service that can be added via the Web in a Site
    Manager.

    Instead of containing its data, a local smiley service looks for named
    utilities that are available as ITheme implementations. The name of the
    utility is then the name of the theme.
    """

    def getLocalThemes():
        """Return a list of locally defined theme names."""

    def getTheme(name, localOnly=False):
        """Return the theme object of the given name.

        If localOnly is set to True, then only local entries will be searched.

        If no theme was found, raise a ComponentLookupError.
        """

    def queryTheme(name, localOnly=False, default=None):
        """Return the theme object of the given name.

        If localOnly is set to True, then only local entries will be searched.

        If no theme was found, the default value is returned.
        """


=== Added File Products3/demo/smileyservice/localservice.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.
#
##############################################################################
"""Global Smiley Service Implementation

$Id: localservice.py,v 1.1 2003/08/22 21:27:33 srichter Exp $
"""
__metaclass__ = type 

from persistence import Persistent
from zope.app import zapi
from zope.app.component.nextservice import getNextService
from zope.app.container.btree import BTreeContainer
from zope.app.interfaces.services.service import ISimpleService
from zope.app.services.servicenames import Utilities
from zope.component.exceptions import ComponentLookupError
from zope.context import ContextMethod
from zope.interface import implements
from zope.publisher.browser import TestRequest

from zopeproducts.demo.smileyservice.interfaces import \
     ILocalSmileyService, ITheme

class Theme(BTreeContainer):
    __doc__ = ITheme.__doc__

    implements(ITheme)

    def getSmiley(self, text, request):
        "See zopeproducts.demo.smileyservice.interfaces.ITheme"
        if text not in self:
            raise ComponentLookupError(text)
        return getURL(self[text], request)
    getSmiley = ContextMethod(getSmiley)
        
    def querySmiley(self, text, request, default=None):
        "See zopeproducts.demo.smileyservice.interfaces.ITheme"
        if text not in self:
            return default
        return getURL(self[text], request)
    querySmiley = ContextMethod(querySmiley)

    def getSmileysMapping(self, request):
        "See zopeproducts.demo.smileyservice.interfaces.ITheme"
        smileys = {}
        for name, smiley in self.items():
            smileys[name] = getURL(smiley, request)
        return smileys
    getSmileysMapping = ContextMethod(getSmileysMapping)


class LocalSmileyService(Persistent):
    __doc__ = ILocalSmileyService.__doc__

    implements(ILocalSmileyService, ISimpleService)

    _defaultTheme = None

    def getDefaultTheme(self):
        if self._defaultTheme is not None:
            return self._defaultTheme
        else:
            next = getNextService(self, 'Smileys')
            return next.defaultTheme
            
    def setDefaultTheme(self, value):
        if value == '':
            self._defaultTheme = None            
        else:
            self._defaultTheme = value

    # See zopeproducts.demo.smileyservice.interfaces.ISmileyService
    defaultTheme = zapi.ContextProperty(getDefaultTheme, setDefaultTheme)
    
    def getSmiley(self, text, request, theme=None):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        smiley = self.querySmiley(text, request, theme)
        if smiley is None:
            raise ComponentLookupError(text)
        return smiley
    getSmiley = ContextMethod(getSmiley)


    def querySmiley(self, text, request, theme=None, default=None):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        if theme is None:
            theme = self.defaultTheme
        theme_obj = self.queryTheme(theme, True)
        if theme_obj is not None and \
               theme_obj.querySmiley(text, request) is not None:
            return theme_obj.querySmiley(text, request)
        next = getNextService(self, 'Smileys')
        return next.querySmiley(text, request, theme, default)
    querySmiley = ContextMethod(querySmiley)
        

    def getThemes(self):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        names = self.getLocalThemes()
        next = getNextService(self, 'Smileys')
        for name in next.getThemes():
            if name not in names:
                names.append(name)
        return names
    getThemes = ContextMethod(getThemes)


    def getLocalThemes(self):
        "See zopeproducts.demo.smileyservice.interfaces.ILocalSmileyService"
        utilities = zapi.getService(self, Utilities)
        themes = utilities.getLocalUtilitiesFor(ITheme)
        return map(lambda t: t[0], themes)
    getLocalThemes = ContextMethod(getLocalThemes)


    def getSmileysMapping(self, request, theme=None):
        "See zopeproducts.demo.smileyservice.interfaces.ISmileyService"
        next = getNextService(self, 'Smileys')
        mapping = next.getSmileysMapping(request, theme)
        theme_obj = self.queryTheme(theme, localOnly=True)
        if theme_obj is None:
            return mapping
        mapping.update(theme_obj.getSmileysMapping(request))
        return mapping
    getSmileysMapping = ContextMethod(getSmileysMapping)


    def getTheme(self, name, localOnly=False):
        "See zopeproducts.demo.smileyservice.interfaces.ILocalSmileyService"
        theme = self.queryTheme(name, localOnly)
        if theme is None:
            raise ComponentLookupError(name)
        return theme
    getTheme = ContextMethod(getTheme)


    def queryTheme(self, name, localOnly=False, default=None):
        "See zopeproducts.demo.smileyservice.interfaces.ILocalSmileyService"
        if name is None:
            name = self.defaultTheme
        utilities = zapi.getService(self, Utilities)
        themes = utilities.getLocalUtilitiesFor(ITheme)
        for id, theme in themes:
            if id == name:
                return theme

        if localOnly is True:
            return default

        next = getNextService(self, 'Smileys')
        if not ILocalSmileyService.isImplementedBy(next):
            return default
        return next.queryTheme(name, default=default)
    queryTheme = ContextMethod(queryTheme)


def getURL(smiley, request):
    url = zapi.getView(smiley, 'absolute_url', request=request)
    return str(url)


=== Added File Products3/demo/smileyservice/meta.zcml ===
<configure xmlns:meta="http://namespaces.zope.org/meta">

  <meta:directives namespace="http://namespaces.zope.org/smiley">

    <meta:directive
        name="smiley"
        schema=".metadirectives.ISmileyDirective"
        handler=".metaconfigure.smiley" />

    <meta:complexDirective
        name="smileys"
        schema=".metadirectives.ISmileysDirective"
        handler=".metaconfigure.smileys">

      <meta:subdirective
          name="smiley"
          schema=".metadirectives.ISmileySubdirective" />

    </meta:complexDirective>

    <meta:directive
        name="defaultTheme"
        schema=".metadirectives.IDefaultThemeDirective"
        handler=".metaconfigure.defaultTheme" />

  </meta:directives>

</configure>


=== Added File Products3/demo/smileyservice/metaconfigure.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""Smiley Configuration code

$Id: metaconfigure.py,v 1.1 2003/08/22 21:27:33 srichter Exp $
"""
import os
from zope.app.publisher.browser.resourcemeta import resource
from zopeproducts.demo.smileyservice.globalservice import \
     provideSmiley, defaultTheme as declareDefaultTheme

__registered_resources = []

class smileys:

    def __init__(self, _context, theme):
        self.theme = theme

    def smiley(self, _context, text, file):
        return smiley(_context, text, file, self.theme)

    def __call__(self):
        return

def smiley(_context, text, file, theme):

    name = theme + '__' + os.path.split(file)[1]
    path = '/++resource++' + name

    if name not in __registered_resources:
        resource(_context, name, image=file)
        __registered_resources.append(name)

    _context.action(
        discriminator = ('smiley', theme, text),
        callable = provideSmiley,
        args = (text, path, theme),
        )


def defaultTheme(_context, theme=None):
    _context.action(
        discriminator = ('smiley', 'defaultTheme',),
        callable = declareDefaultTheme,
        args = (theme,),
        )



=== Added File Products3/demo/smileyservice/metadirectives.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""Smiley Configuration interfaces

$Id: metadirectives.py,v 1.1 2003/08/22 21:27:33 srichter Exp $
"""
from zope.interface import Interface
from zope.configuration.fields import Path
from zope.schema import TextLine, Id


class IThemeSpecification(Interface):
    
    theme = TextLine(
        title=u"Theme",
        description=u"The theme the smiley belongs to.",
        default=None,
        required=False)


class ISmileysDirective(IThemeSpecification):
    """Wrapper directive defining a global theme for the contained smiley
    registrations."""

class ISmileySubdirective(Interface):
    """This directive adds a new smiley using the theme information of the
    complex smileys directive."""

    text = TextLine(
        title=u"Smiley Text",
        description=u"The text that represents the smiley, i.e. ':-)'",
        required=True)

    file = Path(
        title=u"Image file",
        description=u"Path to the image that represents the smiley.",
        required=True)


class ISmileyDirective(ISmileySubdirective, IThemeSpecification):
    """This is a standalone directive registering a smiley for a certain
    theme."""


class IDefaultThemeDirective(IThemeSpecification):
    """Specify the default theme."""




More information about the Zope3-Checkins mailing list