[Zope3-checkins] CVS: zopeproducts/bugtracker - exportimport.py:1.1 template.xml:1.1 TODO.txt:1.3 VERSION.txt:1.2 configure.zcml:1.3 mail.py:1.2 tracker.py:1.2

Stephan Richter srichter@cosmos.phy.tufts.edu
Sat, 26 Jul 2003 09:41:20 -0400


Update of /cvs-repository/zopeproducts/bugtracker
In directory cvs.zope.org:/tmp/cvs-serv13760

Modified Files:
	TODO.txt VERSION.txt configure.zcml mail.py tracker.py 
Added Files:
	exportimport.py template.xml 
Log Message:
- Added XML Export/Import capabilities

- User Vocabularies now only store informational data about the principal,
  since exposing the entire principal is just too dangerous.

- Made Bug Tracker title the same attribute at the DC title and corrected
  permissions.


=== Added File zopeproducts/bugtracker/exportimport.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.
# 
##############################################################################
"""XML Import/Export facility

$Id: exportimport.py,v 1.1 2003/07/26 13:40:43 srichter Exp $
"""
VERSION = '1.0'

import base64

from xml.sax import parse
from xml.sax.handler import ContentHandler

from zope.app.interfaces.dublincore import IZopeDublinCore
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.app.traversing import getParent
from zope.component import getAdapter, getService
from zope.i18n.locales import locales
from zope.schema.vocabulary import getVocabularyRegistry
from zopeproducts.bugtracker.interfaces import IBugDependencies, IComment
from zopeproducts.bugtracker.bug import Bug
from zopeproducts.bugtracker.comment import Comment
from zope.app.content.file import File
from zope.app.content.image import Image

class XMLExport:

    template = ViewPageTemplateFile('template.xml')

    def __init__(self, tracker):
        self.context = tracker
        self.request = None

    def getXML(self):
        return self.template()

    def title(self):
        return self.context.title        

    def version(self):
        return VERSION

    def vocabularies(self):
        registry = getVocabularyRegistry()
        vocabs = []
        for name in ('Stati', 'Priorities', 'BugTypes', 'Releases'):
            vocabs.append({'name': name,
                           'terms' : iter(registry.get(self.context, name))})
        return vocabs

    def bugs(self):
        return map(lambda item: BugInfo(item[0], item[1]), self.context.items())
            

class BugInfo:

    def __init__(self, name, bug):
        self.context = bug
        self.name = name
        self.locale = locales.getLocale()

    def id(self):
        return self.name

    def title(self):
        return self.context.title
        
    def description(self):
        return '\n'+self.context.description+'\n      '

    def submitter(self):
        return self.context.submitter
        
    def created(self):
        dc = getAdapter(self.context, IZopeDublinCore)
        return self.locale.getDateTimeFormatter('medium').format(dc.created)

    def modified(self):
        dc = getAdapter(self.context, IZopeDublinCore)
        if dc.modified is None:
            return self.created()
        return self.locale.getDateTimeFormatter('medium').format(dc.modified)

    def status(self):
        return self.context.status

    def type(self):        
        return self.context.type

    def release(self):
        return self.context.release

    def priority(self):
        return self.context.priority

    def owners(self):
        return ', '.join(self.context.owners)

    def dependencies(self):
        deps = getAdapter(self.context, IBugDependencies)
        return ", ".join(deps.dependencies)

    def comments(self):
        comments = []
        for name, obj in self.context.items():
            if IComment.isImplementedBy(obj):
                comments.append(CommentInfo(name, obj))
        return comments
        
    def attachments(self):
        attachs = []
        for name, obj in self.context.items():
            if not IComment.isImplementedBy(obj):
                attachs.append(AttachmentInfo(name, obj))
        return attachs
    

class CommentInfo:

    def __init__(self, name, comment):
        self.context = comment
        self.name = name
        self.locale = locales.getLocale()

    def id(self):
        return self.name

    def body(self):
        return '\n'+self.context.body+'\n        '

    def creator(self):
        dc = getAdapter(self.context, IZopeDublinCore)
        return dc.creators[0]
        
    def created(self):
        dc = getAdapter(self.context, IZopeDublinCore)
        return self.locale.getDateTimeFormatter('medium').format(dc.created)


class AttachmentInfo:

    def __init__(self, name, attach):
        self.context = attach
        self.name = name
        self.locale = locales.getLocale()

    def id(self):
        return self.name

    def type(self):
        if isinstance(self.context, Image):
            return 'Image'
        return 'File'
    
    def data(self):
        return base64.encodestring(self.context.data)

    def creator(self):
        dc = getAdapter(self.context, IZopeDublinCore)
        return dc.creators[0]
        
    def created(self):
        dc = getAdapter(self.context, IZopeDublinCore)
        return self.locale.getDateTimeFormatter('medium').format(dc.created)


class XMLImporter(ContentHandler):

    def __init__(self, context, encoding='latin-1'):
        self.context = context
        self.encoding = encoding
        self.locale = locales.getLocale()
        self.parser = self.locale.getDateTimeFormatter('medium')
        self.chars = u''

    def startElement(self, name, attrs):
        handler = getattr(self, 'start' + name.title().replace('-', ''), None)
        if not handler:
            raise ValueError, 'Unknown element %s' % name

        handler(attrs)

    def endElement(self, name):
        handler = getattr(self, 'end' + name.title().replace('-', ''), None)
        if handler:
            handler()


    def characters(self, content):
        self.chars += content

    def noop(*args):
        pass

    startVocabularies = noop
    startBugs = noop
    startComments = noop
    startAttachments = noop
    
    def startBugtracker(self, attrs):
        assert attrs.get('version') == VERSION
        self.context.title = attrs.get('title')

    def startVocabulary(self, attrs):
        self.vocab_name = attrs.get('name', None)

    def endVocabulary(self):
        self.vocab_name = None

    def startTerm(self, attrs):
        registry = getVocabularyRegistry()
        vocab = registry.get(self.context, self.vocab_name)
        vocab.add(attrs.get('value'), attrs.get('title'))

    def startBug(self, attrs):
        bug = Bug()
        bug.title = attrs.get('title')
        bug.status = attrs.get('status')
        bug.priority = attrs.get('priority')
        bug.type = attrs.get('type')
        bug.release = attrs.get('release')
        owners = attrs.get('owners').split(', ')
        bug.owners = filter(lambda o: o.strip() != u'', owners)
        deps_adapter = getAdapter(bug, IBugDependencies)
        deps = attrs.get('dependencies').split(', ')
        deps_adapter.setDependencies(filter(lambda o: o.strip() != u'', deps))
        dc = getAdapter(bug, IZopeDublinCore)
        dc.created = self.parser.parse(attrs.get('created'))
        dc.modified = self.parser.parse(attrs.get('modified'))
        dc.creators = [attrs.get('submitter')]
        self.bug = bug
        self.bug_name = attrs.get('id')

    def endBug(self):
        self.context.setObject(self.bug_name, self.bug)
        
    def startDescription(self, attrs):
        self.chars = u''

    def endDescription(self):
        self.bug.description = self.chars.strip()

    def startComment(self, attrs):
        self.chars = u''
        comment = Comment()
        dc = getAdapter(comment, IZopeDublinCore)
        dc.created = self.parser.parse(attrs.get('created'))
        dc.creators = [attrs.get('creator')]        
        self.comment = comment
        self.comment_name = attrs.get('id')

    def endComment(self):
        # Stripping off whitespace and first and last newline
        self.comment.body = self.chars.strip(' ')[1:-1]
        self.bug.setObject(self.comment_name, self.comment)

    def startAttachment(self, attrs):
        self.chars = u''
        type = attrs.get('type')
        if type == 'Image':
            attach = Image()
        else:
            attach = File()
        dc = getAdapter(attach, IZopeDublinCore)
        dc.created = self.parser.parse(attrs.get('created'))
        dc.creators = [attrs.get('creator')]        
        self.attach = attach
        self.attach_name = attrs.get('id')

    def endAttachment(self):
        self.attach.data = base64.decodestring(self.chars.strip(' '))
        self.bug.setObject(self.attach_name, self.attach)


class XMLImport:

    def __init__(self, tracker):
        self.context = tracker

    def processXML(self, xml):
        parse(xml, XMLImporter(self.context))


=== Added File zopeproducts/bugtracker/template.xml ===
<?xml version="1.0"?>
<bugtracker version="1.0"
    xmlns:tal="http://xml.zope.org/namespaces/tal"
    tal:attributes="version view/version;
                    title view/title">

  <vocabularies>
    <vocabulary 
        tal:repeat="vocab view/vocabularies"
        tal:attributes="name vocab/name">
      <term 
          tal:repeat="term vocab/terms"
          tal:attributes="value term/value;
                          title term/title" />
    </vocabulary>
  </vocabularies>

  <bugs>
    <bug 
        id="1" 
        title="Title of Bug" 
        submitter="srichter"
        status="new"
        priority="normal"
        type="bug"
        release="zope_x3"
        owners="srichter, jim"
        dependencies="2, 3"
        created="Jan 01, 2003 12:00:00 AM"
        modified="Jan 01, 2003 12:00:00 AM"

        tal:repeat="bug view/bugs"
        tal:attributes="id bug/id;
                        title bug/title;
                        submitter bug/submitter;
                        status bug/status;
                        priority bug/priority;
                        type bug/type;
                        release bug/release;
                        owners bug/owners;
                        dependencies bug/dependencies;
                        created bug/created;
                        modified bug/modified;
                        ">

      <description tal:content="bug/description" >
      </description>

      <comments>
        <comment
            tal:repeat="comment bug/comments"
            tal:attributes="creator comment/creator;
                            created comment/created;
                            id comment/id" 
            tal:content="structure comment/body" />
      </comments>

      <attachments>
        <attachment
            tal:repeat="attachment bug/attachments"
            tal:attributes="type attachment/type;
                            creator attachment/creator;
                            created attachment/created;
                            id attachment/id" 
            tal:content="attachment/data" />   
      </attachments>

    </bug>
  </bugs>

</bugtracker>


=== zopeproducts/bugtracker/TODO.txt 1.2 => 1.3 ===
--- zopeproducts/bugtracker/TODO.txt:1.2	Thu Jul 24 17:39:07 2003
+++ zopeproducts/bugtracker/TODO.txt	Sat Jul 26 09:40:43 2003
@@ -17,13 +17,6 @@
     - Provide a sample translation (probably German). 
 
 
-  UI
-
-    - Display Term title instead of value in the drop-down elements.
-
-
   Other Features
 
     - Improve Mailings (use some sort of diff library)
-
-    - XML Import and Export
\ No newline at end of file


=== zopeproducts/bugtracker/VERSION.txt 1.1 => 1.2 ===
--- zopeproducts/bugtracker/VERSION.txt:1.1	Thu Jul 24 14:08:03 2003
+++ zopeproducts/bugtracker/VERSION.txt	Sat Jul 26 09:40:43 2003
@@ -1 +1 @@
-0.1
\ No newline at end of file
+0.2
\ No newline at end of file


=== zopeproducts/bugtracker/configure.zcml 1.2 => 1.3 ===
--- zopeproducts/bugtracker/configure.zcml:1.2	Thu Jul 24 17:39:07 2003
+++ zopeproducts/bugtracker/configure.zcml	Sat Jul 26 09:40:43 2003
@@ -178,6 +178,10 @@
         interface="zope.app.interfaces.container.IWriteContainer"/>
 
     <require
+        permission="bugtracker.ViewBugTracker"
+        attributes="title" />
+
+    <require
         permission="zope.ManageContent"
         set_schema=".interfaces.IBugTracker" />
 


=== zopeproducts/bugtracker/mail.py 1.1 => 1.2 ===
--- zopeproducts/bugtracker/mail.py:1.1	Thu Jul 24 14:08:03 2003
+++ zopeproducts/bugtracker/mail.py	Sat Jul 26 09:40:43 2003
@@ -90,7 +90,7 @@
     def handleRemoved(self, object):
         subject = 'Removed: %s (%s)' %(object.title, getName(object))
         emails = self.getAllSubscribers(object)
-        body = self.description
+        body = object.description
         self.mail(emails, subject, body)
 
     def getAllSubscribers(self, object):


=== zopeproducts/bugtracker/tracker.py 1.1 => 1.2 ===
--- zopeproducts/bugtracker/tracker.py:1.1	Thu Jul 24 14:08:03 2003
+++ zopeproducts/bugtracker/tracker.py	Sat Jul 26 09:40:43 2003
@@ -15,8 +15,10 @@
 
 $Id$
 """
-from zope.interface import implements
 from zope.app.content.folder import Folder
+from zope.app.interfaces.dublincore import IZopeDublinCore
+from zope.component import queryAdapter
+from zope.interface import implements
 from zopeproducts.bugtracker.interfaces import IBugTracker
 
 
@@ -24,5 +26,15 @@
 
     implements(IBugTracker)
 
+    def setTitle(self, title):
+        """Set bug tracker title."""
+        dc = queryAdapter(self, IZopeDublinCore)
+        dc.title = title
+
+    def getTitle(self):
+        """Get bug tracker title."""
+        dc = queryAdapter(self, IZopeDublinCore)
+        return dc.title
+
     # See zopeproducts.bugtracker.interfaces.IBugTracker
-    title = u''
+    title = property(getTitle, setTitle)