[Checkins] SVN: Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/ start with service view

Godefroid Chapelle gotcha at bubblenet.be
Mon Oct 11 08:07:42 EDT 2010


Log message for revision 117448:
  start with service view

Changed:
  D   Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/README.txt
  D   Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/cronjob.pt
  D   Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/icons/
  D   Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/job.py
  D   Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/table_header.pt

-=-
Deleted: Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/README.txt
===================================================================
--- Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/README.txt	2010-10-11 12:05:58 UTC (rev 117447)
+++ Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/README.txt	2010-10-11 12:07:42 UTC (rev 117448)
@@ -1,259 +0,0 @@
-==================================
-Task Service Browser Management UI
-==================================
-
-Let's start a browser:
-
-  >>> from zope.testbrowser.testing import Browser
-  >>> browser = Browser()
-  >>> browser.addHeader('Authorization','Basic mgr:mgrpw')
-  >>> browser.handleErrors = False
-
-Now we add a task service:
-
-  >>> browser.open('http://localhost/manage')
-  >>> browser.getLink('Remote Task Service').click()
-  >>> browser.getControl(name='new_value').value = 'tasks'
-  >>> browser.getControl('Apply').click()
-
-Now let's have a look at the job's table:
-
-  >>> browser.getLink('tasks').click()
-
-You can see the available tasks:
-
-  >>> 'Available Tasks' in browser.contents
-  True
-
-By default there is an "echo" task:
-
-  >>> '<div>echo</div>' in browser.contents
-  True
-
-Below you see a table of all the jobs. Initially we have no jobs, so let's add
-one via XML-RPC:
-
-  >>> print http(r"""
-  ... POST /tasks/ HTTP/1.0
-  ... Authorization: Basic mgr:mgrpw
-  ... Content-Type: text/xml
-  ...
-  ... <?xml version='1.0'?>
-  ... <methodCall>
-  ... <methodName>add</methodName>
-  ... <params>
-  ... <value><string>echo</string></value>
-  ... <value><struct>
-  ... <key><string>foo</string></key>
-  ... <value><string>bar</string></value>
-  ... </struct></value>
-  ... </params>
-  ... </methodCall>
-  ... """)
-  HTTP/1.0 200 Ok
-  ...
-
-If we now refresh the screen, we will see the new job:
-
-  >>> browser.reload()
-  >>> print browser.contents
-  <!DOCTYPE ...
-  <tbody>
-  <tr class="odd">
-    <td class="">
-      <input type="checkbox" name="jobs:list" value="1506179619">
-    </td>
-    <td class="tableId">
-      1506179619
-    </td>
-    <td class="tableTask">
-      echo
-    </td>
-    <td class="tableStatus">
-      <span class="status-queued">queued</span>
-    </td>
-    <td class="tableDetail">
-      No input detail available
-    </td>
-    <td class="tableCreated">
-      ...
-    </td>
-    <td class="tableStart">
-      [not set]
-    </td>
-    <td class="tableEnd">
-      [not set]
-    </td>
-  </tr>
-  </tbody>
-  ...
-
-It is possible to provide custom views for the details. Note the name of the
-view "echo_detail", it consists of the task name and "_detail". This allows us
-to use different detail views on the same job classes. if no such view is
-found a view with name 'detail' is searched.
-
-  >>> from zope import interface
-  >>> from zope.publisher.interfaces.browser import IBrowserView
-  >>> class EchoDetailView(object):
-  ...     interface.implements(IBrowserView)
-  ...     def __init__(self, context, request):
-  ...         self.context = context
-  ...         self.request = request
-  ...     def __call__(self):
-  ...         return u'echo: foo=%s'% self.context.input['foo']
-  >>> from lovely.remotetask.interfaces import IJob
-  >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
-  >>> from zope import component
-  >>> component.provideAdapter(EchoDetailView,
-  ...                          (IJob, IDefaultBrowserLayer),
-  ...                          name='echo_detail')
-  >>> browser.reload()
-  >>> print browser.contents
-  <!DOCTYPE
-  ...
-  <td class="tableDetail">
-    echo: foo=bar
-  ...
-
-You can cancel scheduled jobs:
-
-  >>> browser.getControl('Cancel', index=0).click()
-  >>> 'No jobs were selected.' in browser.contents
-  True
-
-  >>> browser.getControl(name='jobs:list').getControl(
-  ...     value='1506179619').click()
-  >>> browser.getControl('Cancel', index=0).click()
-  >>> 'Jobs were successfully cancelled.' in browser.contents
-  True
-
-It is also possible cancel all jobs::
-
-  >>> browser.getControl('Cancel all', index=0).click()
-  >>> 'All jobs cancelled' in browser.contents
-  True
-
-You can also clean attic jobs:
-
-  >>> browser.getControl('Remove all').click()
-  >>> 'Cleaned 1 Jobs' in  browser.contents
-  True
-
-
-Thread Exception Reporting
---------------------------
-
-If a job raises an exception the task service repeats the job 3 times. On
-every exception a traceback is written to the log.
-
-We modify the python logger to get the log output.
-
-  >>> import logging
-  >>> logger = logging.getLogger("lovely.remotetask")
-  >>> logger.setLevel(logging.ERROR)
-  >>> import StringIO
-  >>> io = StringIO.StringIO()
-  >>> ch = logging.StreamHandler(io)
-  >>> ch.setLevel(logging.DEBUG)
-  >>> logger.addHandler(ch)
-
-  >>> from time import sleep
-  >>> from zope import component
-  >>> from lovely.remotetask.interfaces import ITaskService
-  >>> service = getRootFolder()['tasks']
-
-We add a job for a task which raises a ZeroDivisionError every time it is
-called.
-
-  >>> jobid = service.add(u'exception')
-  >>> service.getStatus(jobid)
-  'queued'
-  >>> import transaction
-  >>> transaction.commit()
-  >>> service.startProcessing()
-  >>> transaction.commit()
-
-  >>> import time
-  >>> time.sleep(1.5)
-
-
-Note that the processing thread is daemonic, that way it won't keep the process
-alive unnecessarily.
-
-  >>> import threading
-  >>> for thread in threading.enumerate():
-  ...     if thread.getName().startswith('remotetasks.'):
-  ...         print thread.isDaemon()
-  True
-
-  >>> service.stopProcessing()
-  >>> transaction.commit()
-
-
-We got log entries with the tracebacks of the division error.
-
-  >>> logvalue = io.getvalue()
-  >>> print logvalue
-  Caught a generic exception, preventing thread from crashing
-  integer division or modulo by zero
-  Traceback (most recent call last):
-  ...
-  ZeroDivisionError: integer division or modulo by zero
-  <BLANKLINE>
-
-We had 3 retries, but every error is reported twice, once by the processor and
-once from by the task service.
-
-  >>> logvalue.count('ZeroDivisionError')
-  6
-
-The job status is set to 'error'.
-
-  >>> service.getStatus(jobid)
-  'error'
-
-We do the same again to see if the same thing happens again. This test is
-necessary to see if the internal runCount in the task service is reset.
-
-  >>> io.seek(0)
-  >>> jobid = service.add(u'exception')
-  >>> service.getStatus(jobid)
-  'queued'
-  >>> import transaction
-  >>> transaction.commit()
-  >>> service.startProcessing()
-  >>> transaction.commit()
-  >>> sleep(1.5)
-  >>> service.stopProcessing()
-  >>> transaction.commit()
-
-We got log entries with the tracebacks of the division error.
-
-  >>> logvalue = io.getvalue()
-  >>> print logvalue
-  Caught a generic exception, preventing thread from crashing
-  integer division or modulo by zero
-  Traceback (most recent call last):
-  ...
-  ZeroDivisionError: integer division or modulo by zero
-  <BLANKLINE>
-
-We had 3 retries, but every error is reported twice, once by the processor and
-once from by the task service.
-
-  >>> logvalue.count('ZeroDivisionError')
-  6
-
-The job status is set to 'error'.
-
-  >>> service.getStatus(jobid)
-  'error'
-
-
-Clenaup
--------
-
-Allow the threads to exit:
-
-  >>> sleep(0.2)

Deleted: Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/cronjob.pt
===================================================================
--- Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/cronjob.pt	2010-10-11 12:05:58 UTC (rev 117447)
+++ Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/cronjob.pt	2010-10-11 12:07:42 UTC (rev 117448)
@@ -1,9 +0,0 @@
-<div metal:use-macro="view/base_template/macros/main" >
-  <div metal:fill-slot="above_buttons"
-       tal:define="inputForm view/inputForm | nothing"
-       tal:condition="inputForm">
-    <p>Job input parameter</p>
-    <div tal:replace="structure inputForm" /><hr/>
-  </div>
-</div>
-

Deleted: Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/job.py
===================================================================
--- Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/job.py	2010-10-11 12:05:58 UTC (rev 117447)
+++ Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/job.py	2010-10-11 12:07:42 UTC (rev 117448)
@@ -1,218 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Lovely Systems and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (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.
-#
-##############################################################################
-"""Task detail view
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-from datetime import datetime
-
-from zope import interface
-from zope import component
-from zope import schema
-from zope.browserpage import namedtemplate
-
-from zope import formlib
-
-from zope.traversing.browser.absoluteurl import absoluteURL
-from zope.publisher.browser import BrowserPage
-
-from zope.app.pagetemplate import ViewPageTemplateFile
-from zope.app.form.browser.textwidgets import TextWidget
-from zope.app.form.browser.itemswidgets import DropdownWidget
-from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
-
-from lovely.remotetask.interfaces import CRONJOB, ICronJob
-
-
-def noValidation(self, *args, **kwargs):
-    return ()
-
-
-class JobDetail(BrowserPage):
-    """A simple task input detail view."""
-
-    def __call__(self):
-        return u'No input detail available'
-
-
-class CronJobDetail(BrowserPage):
-    """A simple task input detail view."""
-
-    def __call__(self):
-        job = self.context
-        if job.scheduledFor is None:
-            return u'not yet scheduled'
-        if job.status == CRONJOB:
-            dformat = self.request.locale.dates.getFormatter('dateTime',
-                                                             'short')
-        else:
-            dformat = self.request.locale.dates.getFormatter('dateTime',
-                                                             'medium')
-        return u'Scheduled for %s'% dformat.format(job.scheduledFor)
-
-
-class StringTupleWidget(TextWidget):
-
-    values = None
-
-    def _toFormValue(self, input):
-        if not input:
-            return u''
-        return u' '.join([str(v) for v in input])
-
-    def _toFieldValue(self, input):
-        input = input.strip()
-        if self.convert_missing_value and input == self._missing:
-            return self.context.missing_value
-        if self.values is not None and input == '*':
-            return self.values
-        return tuple([int(v) for v in input.split()])
-
-
-class HourWidget(StringTupleWidget):
-
-    values = tuple(range(0,24))
-
-
-class MinuteWidget(StringTupleWidget):
-
-    values = tuple(range(0,60))
-
-
-class DayOfMonthWidget(StringTupleWidget):
-
-    values = tuple(range(0,31))
-
-
-class MonthWidget(StringTupleWidget):
-
-    values = tuple(range(0,12))
-
-
-class DayOfWeekWidget(StringTupleWidget):
-
-    values = tuple(range(0,7))
-
-class TaskWidget(DropdownWidget):
-
-    def __init__(self, field, request):
-        terms = [SimpleTerm(name) for name in field.context.getAvailableTasks()]
-        vocabulary = SimpleVocabulary(terms)
-        super(TaskWidget, self).__init__(field, vocabulary, request)
-
-class CronJobFormBase(object):
-    """base settings for all cron job forms"""
-
-    form_fields = formlib.form.Fields(ICronJob).select(
-            'task',
-            'hour',
-            'minute',
-            'dayOfMonth',
-            'month',
-            'dayOfWeek',
-            'delay',
-            )
-    form_fields['task'].custom_widget = TaskWidget
-    form_fields['hour'].custom_widget = HourWidget
-    form_fields['minute'].custom_widget = MinuteWidget
-    form_fields['dayOfMonth'].custom_widget = DayOfMonthWidget
-    form_fields['month'].custom_widget = MonthWidget
-    form_fields['dayOfWeek'].custom_widget = DayOfWeekWidget
-
-    base_template = formlib.form.EditForm.template
-    template = ViewPageTemplateFile('cronjob.pt')
-
-
-class CronJobEdit(formlib.form.EditForm, CronJobFormBase):
-    """An edit view for cron jobs."""
-
-    inputForm = None
-
-    def setUpWidgets(self, ignore_request=False):
-        jobtask = component.queryUtility(self.context.__parent__.taskInterface,
-                                       name=self.context.task)
-        if (    jobtask is not None
-            and hasattr(jobtask, 'inputSchema')
-            and jobtask.inputSchema is not interface.Interface
-           ):
-            subform = InputSchemaForm(context=self.context,
-                                      request=self.request,
-                                     )
-            subform.prefix = 'taskinput'
-            subform.form_fields = formlib.form.Fields(jobtask.inputSchema)
-            self.inputForm = subform
-        super(CronJobEdit, self).setUpWidgets(ignore_request=ignore_request)
-
-    @formlib.form.action(u'Apply')
-    def handle_apply_action(self, action, data):
-        inputData = None
-        if self.inputForm is not None:
-            self.inputForm.update()
-            inputData = {}
-            errors = formlib.form.getWidgetsData(self.inputForm.widgets,
-                                                 self.inputForm.prefix,
-                                                 inputData)
-            if len(inputData) == 0:
-                inputData = None
-        self.context.task = data['task']
-        self.context.update(
-                hour = data['hour'],
-                minute = data['minute'],
-                dayOfMonth = data['dayOfMonth'],
-                month = data['month'],
-                dayOfWeek = data['dayOfWeek'],
-                delay = data['delay'],
-                )
-        self.context.__parent__.reschedule(self.context.id)
-
-    @formlib.form.action(u'Cancel', validator=noValidation)
-    def handle_cancel_action(self, action, data):
-        self.request.response.redirect(self.nextURL())
-
-    def nextURL(self):
-        return '%s/@@jobs.html'% absoluteURL(self.context.__parent__,
-                                             self.request)
-
-
-class AddCronJob(formlib.form.Form, CronJobFormBase):
-    """An edit view for cron jobs."""
-
-    @formlib.form.action(u'Add')
-    def handle_add_action(self, action, data):
-        self.context.addCronJob(
-                task = data['task'],
-                hour = data['hour'],
-                minute = data['minute'],
-                dayOfMonth = data['dayOfMonth'],
-                month = data['month'],
-                dayOfWeek = data['dayOfWeek'],
-                delay = data['delay'],
-                )
-
-    @formlib.form.action(u'Cancel', validator=noValidation)
-    def handle_cancel_action(self, action, data):
-        self.request.response.redirect(self.nextURL())
-
-    def nextURL(self):
-        return '%s/@@jobs.html'% absoluteURL(self.context,
-                                             self.request)
-
-
-class InputSchemaForm(formlib.form.AddForm):
-    """An editor for input data of a job"""
-    interface.implements(formlib.interfaces.ISubPageForm)
-    template = namedtemplate.NamedTemplate('default')
-    actions = []

Deleted: Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/table_header.pt
===================================================================
--- Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/table_header.pt	2010-10-11 12:05:58 UTC (rev 117447)
+++ Sandbox/gotcha/z3c.taskqueue_ui/trunk/src/z3c/taskqueue_ui/browser/table_header.pt	2010-10-11 12:07:42 UTC (rev 117448)
@@ -1,11 +0,0 @@
-<html tal:omit-tag="">
-  <a href=""
-     tal:attributes="href string:${request/URL}?sort-on=${options/name}"
-     tal:content="options/header" />
-  <img src="" width="7" height="4" style="vertical-align: middle"
-       tal:condition="options/isAscending"
-       tal:attributes="src context/++resource++lovely-remotetask-icons/ascending.gif" />
-  <img src="" width="7" height="4" style="vertical-align: middle"
-       tal:condition="options/isDecending"
-       tal:attributes="src context/++resource++lovely-remotetask-icons/decending.gif" />
-</html>



More information about the checkins mailing list