Ignore:
Timestamp:
2 Nov 2012, 13:39:31 (12 years ago)
Author:
uli
Message:

More report related components we need for UI.
Also make ReportJobs? more convenient to use from other components.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/reports.py

    r9344 r9510  
    2121import zc.async.interfaces
    2222from persistent.list import PersistentList
    23 from zope.component import getUtility, getUtilitiesFor
     23from zope import schema
     24from zope.component import getUtility, getUtilitiesFor, queryUtility
    2425from zope.component.hooks import setSite
    2526from zope.interface import implementer
     
    2728from waeup.kofa.async import AsyncJob
    2829from waeup.kofa.interfaces import (
    29     IJobManager, JOB_STATUS_MAP,)
     30    IJobManager, JOB_STATUS_MAP, IKofaPluggable, IKofaObject)
     31from waeup.kofa.interfaces import MessageFactory as _
    3032from waeup.kofa.utils.helpers import now
    3133
     
    3335    """A report.
    3436    """
     37    args = Attribute("""The args passed to constructor""")
     38
     39    kwargs = Attribute("""The keywords passed to constructor""")
     40
    3541    creation_dt = Attribute(
    3642        """Datetime when a report was created. The datetime should """
     
    4248        """
    4349
    44 class IReportGenerator(Interface):
     50class IReportGenerator(IKofaObject):
    4551    """A report generator.
    4652    """
    47     def generate(site):
     53    title = Attribute("""Human readable description of report type.""")
     54    def generate(site, args=[], kw={}):
    4855        """Generate a report.
    49         """
    50         return Report()
     56
     57        `args` and `kw` are the parameters needed to create a specific
     58        report (if any).
     59        """
    5160
    5261class IReportJob(zc.async.interfaces.IJob):
    53     def __init__(site, exporter_name):
    54         pass
     62
     63    finished = schema.Bool(
     64        title = u'`True` if the job finished.`',
     65        default = False,
     66        )
     67
     68    failed = schema.Bool(
     69        title = u"`True` iff the job finished and didn't provide a report.",
     70        default = None,
     71        )
     72
     73    description = schema.TextLine(
     74        title = u"""Textual representation of arguments and keywords.""",
     75        default = u"",
     76        )
     77
     78    def __init__(site, generator_name):
     79        """Create a report job via generator."""
    5580
    5681class IReportJobContainer(Interface):
     
    113138        """
    114139
     140class IReportsContainer(grok.interfaces.IContainer, IReportJobContainer,
     141                        IKofaObject):
     142    """A grok container that holds report jobs.
     143    """
     144
     145class manageReportsPermission(grok.Permission):
     146    """A permission to manage reports.
     147    """
     148    grok.name('waeup.manageReports')
     149
    115150def get_generators():
    116151    """Get available report generators.
     
    128163    creation_dt = None
    129164
    130     def __init__(self):
     165    def __init__(self, args=[], kwargs={}):
     166        self.args = args
     167        self.kwargs = kwargs
    131168        self.creation_dt = now()
    132169
    133170    def create_pdf(self):
    134         raise NotImplemented
     171        raise NotImplementedError()
    135172
    136173@implementer(IReportGenerator)
    137174class ReportGenerator(object):
    138     def generate(self, site):
     175
     176    title = _("Unnamed Report")
     177    def generate(self, site, args=[], kw={}):
    139178        result = Report()
    140179        return result
     
    179218    """
    180219    def __init__(self, site, generator_name, args=[], kw={}):
     220        self._generator_name = generator_name
    181221        super(AsyncReportJob, self).__init__(
    182             report_job, site, generator_name, *args, **kw)
     222            report_job, site, generator_name, args=args, kw=kw)
     223
     224    @property
     225    def finished(self):
     226        """A job is marked `finished` if it is completed.
     227
     228        Please note: a finished report job does not neccessarily
     229        provide an IReport result. See meth:`failed`.
     230        """
     231        return self.status == zc.async.interfaces.COMPLETED
     232
     233    @property
     234    def failed(self):
     235        """A report job is marked failed iff it is finished and the
     236        result does not provide IReport.
     237
     238        While a job is unfinished, the `failed` status is ``None``.
     239
     240        Failed jobs normally provide a `traceback` to examine reasons.
     241        """
     242        if not self.finished:
     243            return None
     244        if not IReport.providedBy(self.result):
     245            return True
     246        return False
     247
     248    @property
     249    def description(self):
     250        """A description gives a representation of the report to generate.
     251
     252        The description contains the name of the report generator
     253        (trying to fetch the `name` attribute of the requested report
     254        generator) and the arguments and keywords passed in.
     255
     256        Please note that this method is expensive!
     257        """
     258        args = self.kwargs.get('args', [])
     259        kw = self.kwargs.get('kw', dict())
     260        args = ', '.join(["%r" % x for x in args])
     261        kw = ', '.join(['%s=%r' % (key, val) for key, val in kw.items()])
     262        if len(args) and len(kw):
     263            str_repr = args + ', ' + kw
     264        else:
     265            str_repr = args + kw
     266        str_repr = '(' + str_repr + ')'
     267        try:
     268            generator = queryUtility(
     269                IReportGenerator, name=self._generator_name)
     270            name = generator.name
     271        except:
     272            name = _('Invalid Report Generator')
     273        return name + ' ' + str_repr
     274
    183275
    184276@implementer(IReportJobContainer)
     
    212304        # Make sure that the persisted list is stored in ZODB
    213305        self.running_report_jobs = PersistentList(self.running_report_jobs)
    214         self.running_report_jobs.append((job_id, generator_name, user_id))
     306        self.running_report_jobs.append((job_id, generator_name, user_id),)
    215307        return job_id
    216308
     
    253345        for entry in entries:
    254346            job = manager.get(entry[0])
    255             if job is None:
    256                 continue
    257347            status, status_translated = JOB_STATUS_MAP[job.status]
    258348            generator = getUtility(IReportGenerator, name=entry[1])
     
    287377                return entry
    288378        return None
     379
     380@implementer(IReportsContainer)
     381class ReportsContainer(grok.Container, ReportJobContainer):
     382    """A container for reports.
     383    """
     384
     385@implementer(IKofaPluggable)
     386class ReportsContainerPlugin(grok.GlobalUtility):
     387    """A plugin that updates sites to contain a reports container.
     388    """
     389
     390    grok.name('reports')
     391
     392    deprecated_attributes = []
     393
     394    def setup(self, site, name, logger):
     395        """Add a reports container for `site`.
     396
     397        If there is such an object already, we install a fresh one.
     398        """
     399        if site.get('reports', None) is not None:
     400            del site['reports']
     401            logger.info('Removed reports container for site "%s"' % name)
     402        return self.update(site, name, logger)
     403
     404    def update(self, site, name, logger):
     405        """Install a reports container in `site`.
     406
     407        If one exists already, do nothing.
     408        """
     409        if site.get('reports', None) is not None:
     410            return
     411        site['reports'] = ReportsContainer()
     412        logger.info('Added reports container for site "%s"' % name)
     413        return
Note: See TracChangeset for help on using the changeset viewer.