[Zope3-checkins] CVS: Zope3/src/zope/app/browser/services/service - __init__.py:1.1 add_svc_config.pt:1.1 configure.zcml:1.1 service.gif:1.1 service_manager.gif:1.1 service_manager.png:1.1 serviceactivation.pt:1.1 services.pt:1.1

Jim Fulton jim at zope.com
Tue Sep 2 17:45:58 EDT 2003


Update of /cvs-repository/Zope3/src/zope/app/browser/services/service
In directory cvs.zope.org:/tmp/cvs-serv16533/src/zope/app/browser/services/service

Added Files:
	__init__.py add_svc_config.pt configure.zcml service.gif 
	service_manager.gif service_manager.png serviceactivation.pt 
	services.pt 
Log Message:
Moved the view for making a site (turning a folder into a site 
by creating a site manager) in with the other service-management
views.

Moved the service-management views into their own package.


=== Added File Zope3/src/zope/app/browser/services/service/__init__.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""View support for adding and configuring services and other components.

$Id: __init__.py,v 1.1 2003/09/02 20:45:56 jim Exp $
"""

from zope.app import zapi
from zope.app.browser.container.adding import Adding
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.app.interfaces.container import IZopeContainer
from zope.app.interfaces.services.registration import UnregisteredStatus
from zope.app.interfaces.services.registration import RegisteredStatus
from zope.app.interfaces.services.registration import ActiveStatus
from zope.app.interfaces.services.service import ILocalService
from zope.app.interfaces.services.utility import ILocalUtility
from zope.app.services.service import ServiceRegistration
from zope.publisher.browser import BrowserView
from zope.app.interfaces.services.service import ISite
from zope.app.services.service import ServiceManager

class ComponentAdding(Adding):
    """Adding subclass used for registerable components."""

    menu_id = "add_component"

    def add(self, content):
        # Override so as to save a reference to the added object
        self.added_object = zapi.ContextSuper(
            ComponentAdding, self).add(content)
        return self.added_object

    def nextURL(self):
        v = zapi.queryView(
            self.added_object, "addRegistration.html", self.request)
        if v is not None:
            url = str(
                zapi.getView(self.added_object, 'absolute_url', self.request))
            return url + "/@@addRegistration.html"

        return zapi.ContextSuper(ComponentAdding, self).nextURL()

    def action(self, type_name, id):
        # For special case of that we want to redirect to another adding view
        # (usually another menu such as AddService)
        if type_name.startswith("../"):
            # Special case
            url = type_name
            if id:
                url += "?id=" + id
            self.request.response.redirect(url)
            return

        if not id:
            # Generate an id from the type name
            id = type_name
            l = id.rfind('.')
            if l >= 0:
                id = id[l+1:]
            i = 1
            while ("%s-%s" % (id, i)) in self.context:
                i=i+1
            id = "%s-%s" % (id, i)

        # Call the superclass action() method.
        # As a side effect, self.added_object is set by add() above.
        zapi.ContextSuper(ComponentAdding, self).action(type_name, id)

    action = zapi.ContextMethod(action)


class ServiceAdding(ComponentAdding):
    """Adding subclass used for adding services."""

    menu_id = "add_service"

    def add(self, content):
        # Override so as to check the type of the new object.
        # XXX This wants to be generalized!
        if not ILocalService.isImplementedBy(content):
            raise TypeError("%s is not a local service" % content)

        return zapi.ContextSuper(ServiceAdding, self).add(content)


class UtilityAdding(ComponentAdding):
    """Adding subclass used for adding utilities."""

    menu_id = "add_utility"

    def add(self, content):
        # Override so as to check the type of the new object.
        # XXX This wants to be generalized!
        if not ILocalUtility.isImplementedBy(content):
            raise TypeError("%s is not a local utility" % content)
        return zapi.ContextSuper(UtilityAdding, self).add(content)
    

class AddServiceRegistration(BrowserView):
    """A view on a service implementation, used by add_svc_config.py."""

    def listServiceTypes(self):

        # Collect all defined services interfaces that it implements.
        sm = zapi.getServiceManager(self.context)
        lst = []
        for servicename, interface in sm.getServiceDefinitions():
            if interface.isImplementedBy(self.context):
                registry = sm.queryRegistrations(servicename)
                checked = True
                if registry and registry.active():
                    checked = False
                d = {'name': servicename, 'checked': checked}
                lst.append(d)
        return lst

    def action(self, name=[], active=[]):
        path = zapi.name(self.context)
        configure = zapi.getWrapperContainer(
            self.context).getRegistrationManager()
        container = zapi.getAdapter(configure, IZopeContainer)

        for nm in name:
            sc = ServiceRegistration(nm, path, self.context)
            name = container.setObject("", sc)
            sc = container[name]
            if nm in active:
                sc.status = ActiveStatus
            else:
                sc.status = RegisteredStatus

        self.request.response.redirect("@@SelectedManagementView.html")


class ServiceSummary(BrowserView):
    """A view on the service manager, used by services.pt."""

    def update(self):
        """Possibly delete one or more services.

        In that case, issue a message.
        """
        todo = self.request.get("selected")
        doActivate = self.request.get("Activate")
        doDeactivate = self.request.get("Deactivate")
        doDelete = self.request.get("Delete")
        if not todo:
            if doDeactivate or doDelete:
                return "Please select at least one checkbox"
            return None
        if doActivate:
            return self._activate(todo)
        if doDeactivate:
            return self._deactivate(todo)
        if doDelete:
            return self._delete(todo)

    def _activate(self, todo):
        done = []
        for name in todo:
            registry = self.context.queryRegistrations(name)
            obj = registry.active()
            if obj is None:
                # Activate the first registered registration
                obj = registry.info()[0]['registration']
                obj.status = ActiveStatus
                done.append(name)
        if done:
            s = _("Activated: ${activated_services}")
            s.mapping = {'activated_services': ", ".join(done)}
            return s
        else:
            return _("All of the checked services were already active")

    def _deactivate(self, todo):
        done = []
        for name in todo:
            registry = self.context.queryRegistrations(name)
            obj = registry.active()
            if obj is not None:
                obj.status = RegisteredStatus
                done.append(name)
        if done:
            s = _("Deactivated: ${deactivated_services}")
            s.mapping = {'deactivated_services': ", ".join(done)}
            return s
        else:
            return _("None of the checked services were active")

    def _delete(self, todo):
        errors = []
        for name in todo:
            registry = self.context.queryRegistrations(name)
            assert registry
            if registry.active() is not None:
                errors.append(name)
                continue
        if errors:
            s = _("Can't delete active service(s): ${service_names}; "
                  "use the Deactivate button to deactivate")
            s.mapping = {'service_names': ", ".join(errors)}
            return s

        # 1) Delete the registrations
        services = {}
        for name in todo:
            registry = self.context.queryRegistrations(name)
            assert registry
            assert registry.active() is None # Phase error
            for info in registry.info():
                conf = info['registration']
                obj = conf.getComponent()
                path = zapi.getPath(obj)
                services[path] = obj
                conf.status = UnregisteredStatus
                parent = zapi.getParent(conf)
                name = zapi.name(conf)
                container = zapi.getAdapter(parent, IZopeContainer)
                del container[name]

        # 2) Delete the service objects
        # XXX Jim doesn't like this very much; he thinks it's too much
        #     magic behind the user's back.  OTOH, Guido believes that
        #     we're providing an abstraction here that hides the
        #     existence of the folder and its registration manager as
        #     much as possible, so it's appropriate to clean up when
        #     deleting a service; if you don't want that, you can
        #     manipulate the folder explicitly.
        for path, obj in services.items():
            parent = zapi.getParent(obj)
            name = zapi.name(obj)
            container = zapi.getAdapter(parent, IZopeContainer)
            del container[name]

        s = _("Deleted: ${service_names}")
        s.mapping = {'service_names': ", ".join(todo)}
        return s

    def listConfiguredServices(self):
        names = list(self.context.listRegistrationNames())
        names.sort()

        items = []
        for name in names:
            registry = self.context.queryRegistrations(name)
            assert registry
            infos = [info for info in registry.info() if info['active']]
            if infos:
                configobj = infos[0]['registration']
                component = configobj.getComponent()
                url = str(
                    zapi.getView(component, 'absolute_url', self.request))
            else:
                url = ""
            items.append({'name': name, 'url': url})

        return items


class ServiceActivation(BrowserView):
    """A view on the service manager, used by serviceactivation.pt.

    This really wants to be a view on a registration registry
    containing service registrations, but registries don't have names,
    so we make it a view on the service manager; the request parameter
    'type' determines which service is to be configured."""

    def isDisabled(self):
        sm = zapi.getServiceManager(self.context)
        registry = sm.queryRegistrations(self.request.get('type'))
        return not (registry and registry.active())

    def listRegistry(self):
        sm = zapi.getServiceManager(self.context)
        registry = sm.queryRegistrations(self.request.get('type'))
        if not registry:
            return []

        # XXX this code path is not being tested
        result = []
        dummy = {'id': 'None',
                 'active': False,
                 'registration': None,
                 'name': '',
                 'url': '',
                 'config': '',
                }
        for info in registry.info(True):
            configobj = info['registration']
            if configobj is None:
                info = dummy
                dummy = None
                if not result:
                    info['active'] = True
            else:
                component = configobj.getComponent()
                path = zapi.getPath(component)
                path = path.split("/")
                info['name'] = "/".join(path[-2:])
                info['url'] = str(
                    zapi.getView(component, 'absolute_url', self.request))
                info['config'] = str(zapi.getView(configobj, 'absolute_url',
                                             self.request))
            result.append(info)
        if dummy:
            result.append(dummy)
        return result

    def update(self):
        active = self.request.get("active")
        if not active:
            return ""

        sm = zapi.getServiceManager(self.context)
        registry = sm.queryRegistrations(self.request.get('type'))
        if not registry:
            return _("Invalid service type specified")
        old_active = registry.active()
        if active == "None":
            new_active = None
        else:
            new_active = zapi.traverse(sm, active)
        if old_active == new_active:
            return _("No change")

        if new_active is None:
            registry.activate(None)
            return _("Service deactivated")
        else:
            new_active.status = ActiveStatus
            s = "${active_services} activated"
            s.mapping = {'active_services': active}
            return s

class MakeSite(BrowserView):
    """View for convering a possible site to a site
    """

    def addSiteManager(self):
        """Convert a possible site to a site

        XXX we should also initialize some user-selected services.

        >>> class PossibleSite:
        ...     def setSite(self, sm):
        ...         from zope.interface import directlyProvides
        ...         directlyProvides(self, ISite)

        
        >>> folder = PossibleSite()

        >>> from zope.publisher.browser import TestRequest
        >>> request = TestRequest()
        
        Now we'll make out folder a site:

        >>> MakeSite(folder, request).addSiteManager()

        Now verify that we have a site:

        >>> ISite.isImplementedBy(folder)
        1

        Note that we've also redirected the request:

        >>> request.response.getStatus()
        302

        >>> request.response.getHeader('location')
        '++etc++site/'

        If we try to do it again, we'll fail:

        >>> MakeSite(folder, request).addSiteManager()
        Traceback (most recent call last):
        ...
        UserError: This is already a site
                
        
        """
        if ISite.isImplementedBy(self.context):
            raise zapi.UserError('This is already a site')
        sm = ServiceManager()
        self.context.setSite(sm)
        self.request.response.redirect("++etc++site/")

    


=== Added File Zope3/src/zope/app/browser/services/service/add_svc_config.pt ===
<html metal:use-macro="context/@@standard_macros/dialog">
<body>
<div metal:fill-slot="body">

  <form action="add_svc_config.html" method="post">

    <p i18n:translate="">
      Register this object to provide the following service(s):
    </p>

    <table>
      <thead>
        <tr>
          <th i18n:translate="register-button">Register</th>
          <th i18n:translate="">Service name</th>
          <th i18n:translate="activate-button">Activate</th>
        </tr>
      </thead>
      <tbody>
        <tr tal:repeat="item view/listServiceTypes">
          <td>
            <input type="checkbox" name="name:list" value="value"
                   checked="checked" tal:attributes="value item/name" />
          </td>
          <td tal:content="item/name">Events</td>
          <td>
            <input type="checkbox" name="active:list" value="value"
                   tal:attributes="value item/name;
                                   checked item/checked" />
          </td>
        </tr>
      </tbody>
    </table>

    <input type="reset" value="Reset form"
           i18n:attributes="value reset-button" />
    <input type="submit" value="Submit"
           i18n:attributes="value submit-button" />

  </form>

</div>
</body>
</html>


=== Added File Zope3/src/zope/app/browser/services/service/configure.zcml ===
<zope:configure 
   xmlns:zope="http://namespaces.zope.org/zope"
   xmlns="http://namespaces.zope.org/browser">

<!-- For services, just treat @@manage as @@index.html by default -->

  <!-- Get first accessable item from zmi_views menu -->
  <page
     for="zope.app.interfaces.services.service.ILocalService"
     name="index.html"
     permission="zope.ManageServices"
     class="zope.app.browser.managementviewselector.ManagementViewSelector"
     allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher" 
     />

<!-- Service Manager navigation action -->

  <page
      for="zope.app.interfaces.services.service.IPossibleSite"
      name="addServiceManager.html" 
      permission="zope.ManageServices" 
      class=".MakeSite"
      attribute="addSiteManager" 
      />

  <menuItem 
      menu="zmi_actions" title="Make a site"
      for="zope.app.interfaces.services.service.IPossibleSite"
      action="addServiceManager.html" 
      filter="python:not modules['zope.app.interfaces.services.service'
                  ].ISite.isImplementedBy(context)"
      permission="zope.ManageServices" 
      />

  <menuItem 
      menu="zmi_actions"
      title="Manage Site"
      for="zope.app.interfaces.services.service.ISite"
      action="++etc++site/@@SelectedManagementView.html"
      permission="zope.ManageServices" 
      />

<!-- ServiceManager -->

  <page
     for="zope.app.interfaces.services.service.IServiceManager"
     name="services.html"
     menu="zmi_views" title="Services"
     template="services.pt"
     class=".ServiceSummary"
     permission="zope.ManageServices" />

  <page
     for="zope.app.interfaces.services.service.IServiceManager"
     name="serviceActivation.html"
     template="serviceactivation.pt"
     class=".ServiceActivation"
     permission="zope.ManageServices" />

  <icon
      name="zmi_icon"
      for="zope.app.interfaces.services.service.IServiceManager" 
      file="service_manager.gif" />

  <menuItems
      menu="zmi_actions"
      for="zope.app.interfaces.services.service.IServiceManager">

    <menuItem
        title="Visit default package"
        action="default/@@SelectedManagementView.html"
        permission="zope.ManageServices" />
    <menuItem
        title="Add service"
        action="default/AddService"
        permission="zope.ManageServices" />

  </menuItems>

  <page
      name="contents.html"
      for="zope.app.interfaces.services.service.IServiceManager"
      menu="zmi_views" title="Contents"
      permission="zope.ManageServices"
      class="zope.app.browser.container.contents.Contents"
      attribute="contents" />

  <!-- Override the add action with a link to add a page folder -->
  <menuItem
      menu="zmi_actions"
      for="zope.app.interfaces.services.service.IServiceManager"
      title="Add"
      action=
      "@@contents.html?type_name=zope.app.services.folder.SiteManagementFolder"
      permission="zope.ManageServices"/>

  <pages
      for="zope.app.interfaces.services.service.IServiceManager"
      permission="zope.ManageServices"
      class="zope.app.browser.container.contents.JustContents">

    <page name="index.html" attribute="index" />

  </pages>

  <!-- ServiceRegistration -->

  <page
      name="addRegistration.html"
      for="zope.app.interfaces.services.service.ILocalService"
      template="add_svc_config.pt"
      class=".AddServiceRegistration"
      permission="zope.ManageServices" />

  <page
      name="add_svc_config.html"
      for="zope.app.interfaces.services.service.ILocalService"
      attribute="action"
      class=".AddServiceRegistration"
      permission="zope.ManageServices" />

<!-- "Add Service" menu -->

  <menuItem
    menu="add_component"
    for="zope.app.interfaces.container.IAdding"
    action="../AddService"
    title="Service"
    description="Takes you to a menu of services to add"
    permission="zope.ManageServices" />

  <view
     name="AddService"
     for="zope.app.interfaces.services.folder.ISiteManagementFolder"
     permission="zope.ManageServices"
     class=".ServiceAdding">

    <page name="index.html"  attribute="index"  />
    <page name="action.html" attribute="action" />

  </view>

</zope:configure>


=== Added File Zope3/src/zope/app/browser/services/service/service.gif ===
  <Binary-ish file>

=== Added File Zope3/src/zope/app/browser/services/service/service_manager.gif ===
  <Binary-ish file>

=== Added File Zope3/src/zope/app/browser/services/service/service_manager.png ===
  <Binary-ish file>

=== Added File Zope3/src/zope/app/browser/services/service/serviceactivation.pt ===
<html metal:use-macro="views/standard_macros/page">
<body>
<tal:block
    metal:fill-slot="headers"
    tal:define="global pagetip string:
    To activate a particular service implementation,
    check its radio button and click Update.
    "/>

<div metal:fill-slot="body">

  <h2 i18n:translate="">Registrations for service
    <i tal:content="request/type|default" i18n:name="service_type"
       i18n:translate="">No service type specified</i>
  </h2>

  <p tal:content="view/update">Message from update() goes here</p>

  <form action="." method="post"
        tal:attributes="action request/URL">
    <table tal:define="registry view/listRegistry">

      <thead>
        <tr> 
          <td></td> 
          <th align="left" i18n:translate="">Service</th> 
          <th align="left" i18n:translate="">Registration</th>
        </tr>
      </thead>

      <tbody>

        <tr tal:repeat="config registry">
          <td><input type="radio" name="active" value="default/configure/1"
                     tal:attributes="value config/id;
                                     checked config/active" /></td>
          <td tal:condition="not:config/name">Disabled</td>
          <td tal:condition="config/name"><a href="foo"
                 tal:content="config/name"
                 tal:attributes="href config/url">Implementation</a>
          </td>
          <td tal:condition="config/name"><a href="foo"
                 tal:content="config/id"
                 tal:attributes="href config/config">Registration</a>
          </td>
        </tr>
      
      </tbody>
  
    </table>

    <input type="hidden" name="type" value="Events"
           tal:attributes="value request/type|nothing" />
    <input type="submit" value="Submit" 
           i18n:attributes="value submit-button" />

  </form>

</div>
</body>
</html>


=== Added File Zope3/src/zope/app/browser/services/service/services.pt ===
<html metal:use-macro="views/standard_macros/page">
<body>
<div metal:fill-slot="body">

  <h2 i18n:translate="">
    Services registered in this service manager
  </h2>

  <div tal:define="message view/update;
                   registries view/listConfiguredServices">

    <div class="message" tal:condition="message">
       <span tal:replace="message">view/update message here</span>
       <br /><br />
       <i><a href="" i18n:translate="">(click to clear message)</a></i>
    </div>
    
    <p tal:condition="not:registries" i18n:translate="">
      No services are registered.
    </p>
    
    <div tal:condition="registries">
      <p i18n:translate="">
         Unless a service is disabled, the service name
         links to the active service.  The (change registration)
         link allows activating a different implementation or
         disabling the service altogether.
      </p>
    
      <form method="POST" action="services.html">
    
        <table>
          <tr tal:repeat="reg registries">
            <td><input type="checkbox" name="selected:list"
                       tal:attributes="value reg/name" /></td>
            <td>
              <a href="(link to the active service)"
                 tal:condition="reg/url"
                 tal:attributes= "href reg/url"
                 tal:content="reg/name">
                Foobar (the service type)
              </a>
              <span tal:condition="not:reg/url">
                <span tal:content="reg/name" />(disabled)</span>
            </td>
            <td>
              <a href="xxx"
                 tal:attributes=
                 "href string:@@serviceActivation.html?type=${reg/name}"
                 i18n:translate="">
                (change registration)
              </a>
            </td>
          </tr>
        </table>

        <input type="submit" name="Activate" value="Activate" 
               i18n:attributes="value activate-button"/>
        <input type="submit" name="Deactivate" value="Deactivate"
               i18n:attributes="value deactivate-button"/>
        &nbsp;
        <input type="submit" name="Delete" value="Delete"
               i18n:attributes="value delete-button"/>
        &nbsp;
        <input type="submit" name="Refresh" value="Refresh"
               i18n:attributes="value refresh-button"/>

      </form>

      <p><a href="default/AddService" i18n:translate="">
        Add a service to this service manager</a></p>

    </div>
  </div>

</div>
</body>
</html>




More information about the Zope3-Checkins mailing list