[Zope3-checkins] CVS: Products3/bugtracker - bug.py:1.2 configure.zcml:1.5 exportimport.py:1.4 interfaces.py:1.2 template.xml:1.2 tracker.py:1.6 vocabulary.py:1.3

Stephan Richter srichter@cosmos.phy.tufts.edu
Mon, 28 Jul 2003 13:14:19 -0400


Update of /cvs-repository/Products3/bugtracker
In directory cvs.zope.org:/tmp/cvs-serv11336

Modified Files:
	bug.py configure.zcml exportimport.py interfaces.py 
	template.xml tracker.py vocabulary.py 
Log Message:
I dunno what bit me, but I thought that having numeric bug ids would be 
better. It turns out that a lot of the Zope 3 machinery depends on the 
names being strings, so I useually convert the names to strings anyway.
Oh well.

I also implemented default values for the vocabularies. Updated the export/
import accordingly.


=== Products3/bugtracker/bug.py 1.1 => 1.2 ===
--- Products3/bugtracker/bug.py:1.1	Thu Jul 24 14:08:03 2003
+++ Products3/bugtracker/bug.py	Mon Jul 28 13:13:41 2003
@@ -23,9 +23,12 @@
 from zope.app.traversing import getParent, getName
 from zope.app.container.btree import BTreeContainer
 from zope.app.context import ContextWrapper
+from zope.context import ContextProperty
 from zope.proxy import removeAllProxies
 from zopeproducts.bugtracker.interfaces import IBug, IComment
 from zopeproducts.bugtracker.interfaces import IBugDependencies
+from zopeproducts.bugtracker.vocabulary import \
+     VocabularyPropertyGetter, VocabularyPropertySetter
 
 DependencyKey = 'http://www.zope.org/bugtracker#1.0/Dependencies'
 
@@ -35,16 +38,25 @@
     implements(IBug)
 
     # See zopeproducts.bugtracker.interfaces.IBug
-    status = u'new'
+    status = ContextProperty(
+        VocabularyPropertyGetter('_status', 'Stati'),
+        VocabularyPropertySetter('_status', 'Stati'))
+
 
     # See zopeproducts.bugtracker.interfaces.IBug
-    priority = u'normal'
+    priority = ContextProperty(
+        VocabularyPropertyGetter('_priority', 'Priorities'),
+        VocabularyPropertySetter('_priority', 'Priorities'))
 
     # See zopeproducts.bugtracker.interfaces.IBug
-    type = u'bug'
+    type = ContextProperty(
+        VocabularyPropertyGetter('_type', 'BugTypes'),
+        VocabularyPropertySetter('_type', 'BugTypes'))
 
     # See zopeproducts.bugtracker.interfaces.IBug
-    release = u'None'
+    release = ContextProperty(
+        VocabularyPropertyGetter('_release', 'Releases'),
+        VocabularyPropertySetter('_release', 'Releases'))
 
     def getOwners(self):
         return getattr(self, '_owners', [])


=== Products3/bugtracker/configure.zcml 1.4 => 1.5 ===
--- Products3/bugtracker/configure.zcml:1.4	Sat Jul 26 17:25:52 2003
+++ Products3/bugtracker/configure.zcml	Mon Jul 28 13:13:41 2003
@@ -109,10 +109,11 @@
   <content class=".vocabulary.ManagableVocabulary">
     <allow interface="zope.schema.interfaces.IVocabulary"/>
     <allow interface="zope.schema.interfaces.IVocabularyTokenized"/>
-    <allow attributes="__contains__"/>
+    <allow attributes="__contains__ default"/>
     <require
         permission="bugtracker.ManageBugTracker"
-        attributes="add delete"/>
+        attributes="add delete"
+        set_attributes="default"/>
   </content>
 
   <content class=".vocabulary.StatusVocabulary">


=== Products3/bugtracker/exportimport.py 1.3 => 1.4 ===
--- Products3/bugtracker/exportimport.py:1.3	Mon Jul 28 07:49:31 2003
+++ Products3/bugtracker/exportimport.py	Mon Jul 28 13:13:41 2003
@@ -22,17 +22,18 @@
 from xml.sax import parse
 from xml.sax.handler import ContentHandler
 
+from zope.app.content.file import File
+from zope.app.content.image import Image
 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 zope.security.proxy import trustedRemoveSecurityProxy 
 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:
 
@@ -55,8 +56,10 @@
         registry = getVocabularyRegistry()
         vocabs = []
         for name in ('Stati', 'Priorities', 'BugTypes', 'Releases'):
+            vocab = registry.get(self.context, name)
             vocabs.append({'name': name,
-                           'terms' : iter(registry.get(self.context, name))})
+                           'terms' : iter(vocab),
+                           'default' : vocab.default})
         return vocabs
 
     def bugs(self):
@@ -227,6 +230,9 @@
         registry = getVocabularyRegistry()
         vocab = registry.get(self.context, self.vocab_name)
         vocab.add(attrs.get('value'), attrs.get('title'))
+        if attrs.get('default', None) is not None:
+            # XXX: I do not understand why my security does not work here.
+            trustedRemoveSecurityProxy(vocab).default = attrs.get('value')
 
     def startBug(self, attrs):
         bug = Bug()
@@ -257,7 +263,7 @@
         self.bug_name = attrs.get('id')
 
     def endBug(self):
-        self.context.setObject(self.bug_name, self.bug, True)
+        self.context.setObject(self.bug_name, self.bug)
         
     def startDescription(self, attrs):
         self.chars = u''


=== Products3/bugtracker/interfaces.py 1.1 => 1.2 ===
--- Products3/bugtracker/interfaces.py:1.1	Thu Jul 24 14:08:03 2003
+++ Products3/bugtracker/interfaces.py	Mon Jul 28 13:13:41 2003
@@ -157,6 +157,11 @@
     def delete(value):
         """Delete an entry from the vocabulary."""
 
+    default = TextLine(
+        title = _(u"Default"),
+        description = _(u"Default value of the vocabulary."),
+        required=True)
+
     
 class IStatusVocabulary(IManagableVocabulary):
     """Manageable vocabulary that stores stati."""


=== Products3/bugtracker/template.xml 1.1 => 1.2 ===
--- Products3/bugtracker/template.xml:1.1	Sat Jul 26 09:40:43 2003
+++ Products3/bugtracker/template.xml	Mon Jul 28 13:13:41 2003
@@ -8,10 +8,16 @@
     <vocabulary 
         tal:repeat="vocab view/vocabularies"
         tal:attributes="name vocab/name">
-      <term 
-          tal:repeat="term vocab/terms"
+     <tal:block repeat="term vocab/terms">
+       <term value="" title="" 
+          tal:condition="python: vocab['default'].value != term.value"
           tal:attributes="value term/value;
                           title term/title" />
+       <term value="" title="" default=""
+          tal:condition="python: vocab['default'].value == term.value"
+          tal:attributes="value term/value;
+                          title term/title" />
+     </tal:block>
     </vocabulary>
   </vocabularies>
 


=== Products3/bugtracker/tracker.py 1.5 => 1.6 ===
--- Products3/bugtracker/tracker.py:1.5	Mon Jul 28 07:49:31 2003
+++ Products3/bugtracker/tracker.py	Mon Jul 28 13:13:41 2003
@@ -49,11 +49,11 @@
     
     def keys(self):
         """See zope.interface.common.mapping.IEnumerableMapping"""
-        return self.data.keys()
+        return map(lambda k: str(k), self.data.keys())
 
     def __iter__(self):
         """See zope.interface.common.mapping.IEnumerableMapping"""
-        return iter(self.data.keys())
+        return iter(self.keys())
 
     def values(self):
         """See zope.interface.common.mapping.IEnumerableMapping"""
@@ -61,7 +61,7 @@
 
     def items(self):
         """See zope.interface.common.mapping.IEnumerableMapping"""
-        return self.data.items()
+        return map(lambda i: (str(i[0]), i[1]), self.data.items())
 
     def __len__(self):
         """See zope.interface.common.mapping.IEnumerableMapping"""
@@ -91,13 +91,14 @@
         # to each other. This is particualry important when importing XML
         # data.
         if forceName == False:
-            name = max(list(self.keys())+[0])+1
+            name = max(list(self.data.keys())+[0])+1
         else:
             name = int(name)
             if name in self:
                 raise ValueError, 'Name (%i) already in Bug Tracker.' %name 
         self.data[name] = object
-        return name
+        # Too much code depends on this being a string type
+        return unicode(name)
 
     def __delitem__(self, name):
         """Delete the named object from the folder. Raises a KeyError


=== Products3/bugtracker/vocabulary.py 1.2 => 1.3 ===
--- Products3/bugtracker/vocabulary.py:1.2	Thu Jul 24 17:39:07 2003
+++ Products3/bugtracker/vocabulary.py	Mon Jul 28 13:13:41 2003
@@ -21,18 +21,18 @@
 from persistence import Persistent
 from persistence.dict import PersistentDict
 
-from zope.schema.interfaces import \
-     ITokenizedTerm, IVocabulary, IVocabularyTokenized
 from zope.app.interfaces.annotation import IAnnotatable, IAnnotations
 from zope.app.interfaces.security import IAuthenticationService
-
 from zope.app.services.servicenames import Authentication
+from zope.schema.interfaces import \
+     ITokenizedTerm, IVocabulary, IVocabularyTokenized
+from zope.schema.vocabulary import getVocabularyRegistry
 from zope.security.proxy import trustedRemoveSecurityProxy 
 from zopeproducts.bugtracker.interfaces import IManagableVocabulary, IBugTracker
 from zopeproducts.bugtracker.interfaces import \
      IStatusVocabulary, IReleaseVocabulary, IPriorityVocabulary 
 from zopeproducts.bugtracker.interfaces import \
-     IBugTypeVocabulary 
+     IBugTypeVocabulary
 
 class SimpleTerm(Persistent):
 
@@ -62,6 +62,7 @@
         self.annotations = getAdapter(self.context, IAnnotations)
         if not self.annotations.get(self.key):
             self.annotations[self.key] = PersistentDict()
+            self.annotations[self.key+'/default'] = None
     
     def __contains__(self, value):
         return value in self.annotations[self.key].keys()
@@ -81,10 +82,14 @@
     def getTermByToken(self, token):
         return self.getTerm(token)
     
-    def add(self, value, title):
+    def add(self, value, title, default=False):
         self.annotations[self.key][value] = SimpleTerm(value, title)
+        if default:
+            self.default = value
 
     def delete(self, value):
+        if value == self.default.value:
+            raise ValueError, "Cannot delete default value '%s'." %value
         del self.annotations[self.key][value]
 
     def _getRealContext(self, context):
@@ -93,6 +98,23 @@
                 return obj
         return context
 
+    def getDefault(self):
+        value = self.annotations[self.key+'/default']
+        if value is None:
+            return None
+        return self.getTerm(self.annotations[self.key+'/default'])
+
+    def setDefault(self, value):
+        """Set the default value/term. Both, a token and a term are accepted."""
+        if ITokenizedTerm.isImplementedBy(value):
+            value = value.value
+        if value not in self:
+            raise ValueError, \
+                  "The value '%s' was not found in the vocabulary" %value
+        self.annotations[self.key+'/default'] = value
+
+    default = property(getDefault, setDefault)
+
 
 class StatusVocabulary(ManagableVocabulary):
 
@@ -176,6 +198,50 @@
 
     def getTermByToken(self, token):
         return self.getTerm(token)
+
+
+class VocabularyPropertyGetter(object):
+    
+    def __init__(self, name, vocab_name):
+        self.name = name
+        self._vocab_name = vocab_name
+
+    def __call__(self, instance):
+        registry = getVocabularyRegistry()
+        try:
+            vocab = registry.get(instance, self._vocab_name)
+            default = vocab.default.value
+        except TypeError:
+            # We cannot assume that the bug will always have a context to
+            # find the vocabulary data. In these cases, we just skip the
+            # default lookup.
+            default = None
+        return getattr(instance, self.name, default)
+
+
+class VocabularyPropertySetter(object):
+    """This generic vocabulary property setter class ensures that the set
+    value is in the vocabulary."""
+    
+    def __init__(self, name, vocab_name):
+        self.name = name
+        self._vocab_name = vocab_name
+
+    def __call__(self, instance, value):
+        registry = getVocabularyRegistry()
+        try:
+            vocab = registry.get(instance, self._vocab_name)
+            if value not in vocab:
+                raise ValueError, \
+                      "The value '%s' was not found in vocabulary '%s'" %(
+                    value, self._vocab_name)
+        except TypeError:
+            # We cannot assume that the bug will always have a context to
+            # find the vocabulary data. In these cases, we just skip the
+            # verification.
+            vocab = None
+
+        setattr(instance, self.name, value)
 
 
 # Monkey Patching going on...