changeset 39:bbad6a092861

more work on projects. extended bibliography still borked.
author casties
date Fri, 26 Apr 2013 20:31:21 +0200
parents 3c98cc79dd14
children fd8e78bbc5ed
files HashTree.py MPIWGDepartment.py MPIWGProjects.py MPIWGRoot.py zpt/changeMPIWGRootForm.zpt zpt/project/extendedBibliography_template.zpt zpt/project/project_template.zpt
diffstat 7 files changed, 424 insertions(+), 306 deletions(-) [+]
line wrap: on
line diff
--- a/HashTree.py	Fri Apr 26 19:09:50 2013 +0200
+++ b/HashTree.py	Fri Apr 26 20:31:21 2013 +0200
@@ -67,6 +67,8 @@
                 
             return sub + "] "
 
+    
+
 
 class HashTree:
     """Tree using dictionaries"""
@@ -82,6 +84,23 @@
         self.keyFn = keyFn
     
 
+    def _splitkey(self, key):
+        """returns a list of key parts"""
+        if isinstance(key, basestring):
+            # its a string - split
+            keys = key.split(self.keySeparator)
+            if self.keyFn is not None:
+                keys = [self.keyFn(k) for k in keys]
+        elif isinstance(key, list):
+            # its a list - keep
+            keys = key
+        else:
+            # not a list - wrap in list
+            keys = [key]
+            
+        return keys
+
+
     def getNode(self, key):
         """gets node under key from the tree.
         key can be sequence of key string or a single string using keySeparator.
@@ -90,22 +109,11 @@
         if key is None:
             return self.root
 
-        if isinstance(key, basestring):
-            keys = key.split(self.keySeparator)
-            if self.keyFn is not None:
-                keys = [self.keyFn(k) for k in keys]
-                
-        elif isinstance(key, list):
-            keys = key
-            
-        else:
-            keys = [key]
+        keys = self._splitkey(key)
             
         node = self.root
         for k in keys:
-            #logging.debug("getNode node=%s k=%s"%(node, repr(k)))
             node = node.getNode(k)
-            #logging.debug("getNode got:%s"%(node))
             if node is None:
                 return None
             
@@ -127,16 +135,7 @@
         """adds value under key to the tree.
         key can be sequence of key string or a single string using keySeparator.
         """
-        #logging.debug("add(key=%s, value=%s)"%(repr(key), value))
-        if isinstance(key, basestring):
-            keys = key.split(self.keySeparator)
-            if self.keyFn is not None:
-                keys = [self.keyFn(k) for k in keys]
-        elif isinstance(key, list):
-            keys = key
-        else:
-            keys = [key]
-            
+        keys = self._splitkey(key)
         node = self.root
         for k in keys:
             nextnode = node.getNode(k)
@@ -147,6 +146,31 @@
             node = nextnode
             
         node.value = value
+
         
-    
+    def getChildrenOf(self, key):
+        """returns the list of child (values) of the node under key."""
+        node = self.getNode(key)
+        if node.children is None:
+            return []
+        else:
+            return [n.value for (k, n) in node.children.items() if n.value is not None]
+
+
+    def getAncestorsOf(self, key):
+        """returns the list of ancestor (values) of the node under key.
+        ordered from root up."""
+        keys = self._splitkey(key)
+        node = self.root
+        ancestors = []
+        for k in keys:
+            if node.value is not None:
+                ancestors.append(node.value)
+                
+            node = node.getNode(k)
+            if node is None:
+                return ancestors
+            
+        return ancestors
+
         
--- a/MPIWGDepartment.py	Fri Apr 26 19:09:50 2013 +0200
+++ b/MPIWGDepartment.py	Fri Apr 26 20:31:21 2013 +0200
@@ -91,12 +91,12 @@
         """returns the name of the director"""
         return self.director
     
-    def getDirectorId(self):
-        """returns the id of the director"""
+    def getDirectorUsername(self):
+        """returns the username of the director"""
         return self.director_id
 
-    def getProjectId(self):
-        """return the project id"""
+    def getProjectNumber(self):
+        """return the project number"""
         return self.project_id
     
     def getUrl(self, baseUrl=None):
@@ -141,8 +141,9 @@
 
     def getProject(self):
         """returns the default project"""
-        proj = self.getProjects(count=1, onlyActive=1, onlyArchived=1)
-        return getAt(proj, 0, None) 
+        pf = self.getMPIWGRoot().getProjectFolder()
+        proj = pf.getProject(projectNumber=self.getProjectNumber())
+        return proj
 
     def getProjects(self, count=0, onlyActive=0, onlyArchived=0):
         """returns a list of projects of this department.
@@ -155,8 +156,8 @@
         onlyArchived = 1 : current projects
         onlyArchived = 2 : archived projects
         """
-        pf = self.en.getProjectFolder()
-        projects = pf.getProjectsAsList(self.getProjectId(), active=onlyActive, archived=onlyArchived)
+        pf = self.getMPIWGRoot().getProjectFolder()
+        projects = pf.getProjectsAsList(self.getProjectNumber(), active=onlyActive, archived=onlyArchived)
         #logging.debug("getProjects projects=%s"%repr(projects))
         if count > 0:
             return projects[:count]
@@ -168,7 +169,7 @@
         self.weight=weight
         if RESPONSE is not None:
             RESPONSE.redirect('manage_main')
-
+            
     def changeMPIWGDepartment(self, title=None, weight=None, project_id=None, director=None, director_id=None, 
                               type_en=None, type_de=None, title_en=None, title_de=None, RESPONSE=None):
         """change everything"""
--- a/MPIWGProjects.py	Fri Apr 26 19:09:50 2013 +0200
+++ b/MPIWGProjects.py	Fri Apr 26 20:31:21 2013 +0200
@@ -1,7 +1,7 @@
 """This contains the class MPIWG Projects
 for organizing and maintaining the different project pages
 
-$author dwinter   - last change  26.06.2008
+$author dwinter 26.06.2008
 
 """
 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
@@ -51,25 +51,7 @@
 import transaction
 
 
-# TODO: fix this
-definedFields = ['WEB_title', 
-                 'xdata_01', 
-                 'xdata_02', 
-                 'xdata_03', 
-                 'xdata_04', 
-                 'xdata_05', 
-                 'xdata_06', 
-                 'xdata_07', 
-                 'xdata_08', 
-                 'xdata_09', 
-                 'xdata_10', 
-                 'xdata_11', 
-                 'xdata_12', 
-                 'xdata_13', 
-                 'WEB_project_header', 
-                 'WEB_project_description', 
-                 'WEB_related_pub']
-
+# TODO: better names for the fields
 fieldLabels = {'WEB_title':'WEB_Title',
          'xdata_01':'Responsible Scientists',
          'xdata_02':'Department',
@@ -88,6 +70,8 @@
          'WEB_project_description':'WEB_project_description',
          'WEB_related_pub':'WEB_related_pub'}
 
+definedFields = fieldLabels.keys() # TODO: should this be sorted?
+
 checkFields = ['xdata_01']
 
 
@@ -146,7 +130,6 @@
             logging.debug("MPIWGProject_publication - end FALSE ")
             self._v_hasLinkToBookPage = True
             return False
-        
     
     
     def getImageUrls(self, mode="not_cached"):
@@ -175,6 +158,7 @@
             return []
         self._v_imageUrls = ret[0:]
         return ret
+
         
     def editPublication(self, text=None, image1=None, image2=None, description=None, link=None, RESPONSE=None):
         """edit a publication"""
@@ -206,12 +190,12 @@
             else:
                 nO = Image('publicationImage2', '', image2)
                 self._setObject('publicationImage2', nO)
-                   
-
+ 
         self.ZCacheable_invalidate()
         if RESPONSE:
             self.redirect(RESPONSE, "../managePublications")
 
+
 class MPIWGProject_relatedProject(Folder):
     """publications object fuer project"""
 
@@ -237,10 +221,6 @@
         if (not link):
             pt = PageTemplateFile(os.path.join(package_home(globals()), 'zpt', 'edit_relatedProjectForm.zpt')).__of__(self)
             return pt()
-
-       
-       
-      
         
         # hole die id des projektes
         splitted = link.split("/")
@@ -254,10 +234,6 @@
         
         if object == None:
             self.redirect(RESPONSE, 'errorRelatedProjects?link=' + link)
-        
-      
-
-        
        
         self.orginallink = link[0:]
         self.objid = objid[0:]
@@ -270,6 +246,7 @@
         if RESPONSE:
             self.redirect(RESPONSE, "../manageRelatedProjects")
 
+
 class MPIWGProject_image(Image):
     """Images for Projects"""
 
@@ -329,6 +306,8 @@
     editForm = PageTemplateFile('zpt/project/edit_description', globals())
     edit_template = PageTemplateFile('zpt/project/edit_template', globals())
     project_template = PageTemplateFile('zpt/project/project_template', globals())
+    # TODO: this should go away
+    extendedBibliography = PageTemplateFile('zpt/project/extendedBibliography_template', globals())
 
     # TODO: compat
     edit_MPIWGProject_main = edit_template
@@ -434,23 +413,8 @@
         
         return ret;
     
-    def hasRelatedDigitalSources(self):
-        """test ob es digital sources gibt"""
-        
-        
-        ret = (self.getContent('xdata_11').lstrip().rstrip() == '')
-            
-      
-      
-        return not ret;
-            
-        
-    
-    
     def copyImageToMargin(self, RESPONSE=None):  
         """copy inline images to marginal images"""
-        
-        
         # getImages from WEB_project_description
         description = self.getContent('WEB_project_description')
         
@@ -480,12 +444,10 @@
                     tmp = splitted[1].split("</p>")
                     imageCaptions.append(tmp[0].encode('utf-8'))
 
-
                 else:
                     # keine caption
 
                     imageCaptions.append("")
-  
      
         # eintragen:
         for imageURL in imageURLs:
@@ -513,8 +475,8 @@
             obj.update_data(data)
         
         if RESPONSE:
-        
             self.redirect(RESPONSE, 'manageImages')
+
             
     def manageImages(self, imageName=None, op=None):
         """managage images"""
@@ -606,7 +568,6 @@
         """erzeuge erweiterte publications liste"""
         pl = BibliographyManager("publicationList", "", "institutsbiblio", self.connection_id)
         self._setObject("publicationList", pl)
-        
     
         zt = ZopePageTemplate('index.html')
         pl._setObject('index.html', zt)
@@ -614,12 +575,11 @@
                                               'zpt/showExtendedProjectBibliography.zpt')
         text = open(default_content_fn).read()
         zt.pt_edit(text, 'text/html')
-
     
         if RESPONSE:
             self.redirect(RESPONSE, "managePublications")
 
-            
+
     def getPublications(self):
         """get all Publications"""
         def sort_images(x, y):
@@ -727,7 +687,6 @@
             self.manage_delObjects([id])
             self.ZCacheable_invalidate()
             if RESPONSE:
-        
                 self.redirect(RESPONSE, 'managePublications')
               
     def deleteRelatedProject(self, id, RESPONSE=None):
@@ -735,7 +694,6 @@
             self.manage_delObjects([id])
             self.ZCacheable_invalidate()
             if RESPONSE:
-        
                 self.redirect(RESPONSE, 'manageRelatedProjects')
 
 
@@ -758,6 +716,20 @@
         else:
             return t
     
+    
+    def getLabel(self):
+        """returns label (or title) of this project"""
+        l = getattr(self, 'xdata_07', None)
+        if isinstance(l, list):
+            # compat with old lists
+            l = l[0]
+            
+        if l:
+            return l
+        else:
+            return self.getProjectTitle()
+
+    
     def getResponsibleScientists(self):
         """returns the responsible scientists as string"""
         t = getattr(self, 'xdata_01', None)
@@ -797,6 +769,26 @@
         self.responsibleScientistsList = scientistsList
         
               
+    def getInvolvedScholars(self):
+        """returns the other involved scholars"""
+        t = getattr(self, 'xdata_08', None)
+        if isinstance(t, list):
+            # compat with old lists
+            return t[0]
+        else:
+            return t
+
+        
+    def getCooperationPartners(self):
+        """returns the cooperation partners"""
+        t = getattr(self, 'xdata_12', None)
+        if isinstance(t, list):
+            # compat with old lists
+            return t[0]
+        else:
+            return t
+        
+              
     def getUrl(self, baseUrl=None):
         """returns URL to this Project"""
         if baseUrl is None:
@@ -829,6 +821,82 @@
         items.sort(key=lambda x:int(getattr(x, 'place', 0)))
         return items          
 
+
+    def getDepartment(self):
+        """returns the department of this project"""
+        num = self.getNumber()
+        pp = num.find('.')
+        if pp > 0:
+            num = num[:pp]
+            
+        return self.getMPIWGRoot().getDepartment(projectNumber=num)
+
+
+    def getDepartmentId(self):
+        """returns the id of the department of this project"""
+        dep = self.getDepartment()
+        if dep is not None:
+            return dep.getId()
+        
+        return None
+
+
+    def getDescription(self, filter=False):
+        """returns the project description"""
+        t = getattr(self, 'WEB_project_description', None)
+        if isinstance(t, list):
+            # compat with old lists
+            return t[0]
+        else:
+            return t
+        
+        
+    def getSuperProjects(self):
+        """returns a list of ancestor projects to the root"""
+        tree = self.getProjectTree()
+        return tree.getAncestorsOf(self.getNumber())
+    
+
+    def getSubProjects(self, active=1):
+        """returns a list of child projects"""
+        tree = self.getProjectTree()
+        return [p for p in tree.getChildrenOf(self.getNumber()) if p.checkActive(active)]
+    
+              
+    def getRelatedProjects(self):
+        """returns the list of related projects"""
+        items = self.objectValues(spec='MPIWGProject_relatedProject')
+        # sort by place
+        items.sort(key=lambda x:int(getattr(x, 'place', 0)))
+        return items          
+        
+
+    def getRelatedPublications(self):
+        """returns the list of related publications"""
+        items = self.objectValues(spec='MPIWGProject_publication')
+        # sort by place
+        items.sort(key=lambda x:int(getattr(x, 'place', 0)))
+        return items          
+        
+    
+    def getRelatedDigitalSources(self):
+        """returns the related digital sources"""
+        t = getattr(self, 'xdata_11', None)
+        if isinstance(t, list):
+            # compat with old lists
+            return t[0]
+        else:
+            return t
+        
+    def getFundingInstitutions(self):
+        """returns the funding institutions"""
+        t = getattr(self, 'xdata_13', None)
+        if isinstance(t, list):
+            # compat with old lists
+            return t[0]
+        else:
+            return t
+
               
     def getImages(self):
         """get all Images"""
@@ -871,7 +939,6 @@
  
     def hasChildren(self, date=None, onlyActive=1, onlyArchived=1):
         """check if project has children"""
-        
         ct = self.getContexts(childs=self.getContent('xdata_05'),
                                  depth=1, date=date, onlyActive=onlyActive)
         
@@ -957,8 +1024,6 @@
     def isActual(self):
         """gibt 1 zurueck wenn aktuell, 0 sonst"""
         actualTime = time.localtime()
-        
-        
         # print getattr(self,'archiveTime',actualTime)
         if getattr(self, 'archiveTime', actualTime) < actualTime:
             return 0
@@ -1005,43 +1070,8 @@
             self.redirect(RESPONSE, 'manage_main')
 
    
-    def crossLinker(self):
-        """experimental crosslinker"""
-        splitted = self.WEB_project_description[0].split()
-        new = []
-        for split in splitted:
-            try:
-                found = self.DescriptionCatalog({'fulltext':split})
-          
-                if len(found) > 1:
-             
-                    new.append("<a href=%s>%s</a>" % (split, split))
-                else:
-                    new.append(split)
-            except:
-                new.append(split)
-        return " ".join(new)
-            
-            
-
-
-    def generateTemplate(self, RESPONSE=None):
-        """Erzeuge Template fuer defined fields not_used"""
-
-        id = "index_html"
-        title = id
-        if self._getOb('index_html'):
-            self._delObject('index_html')
-
-        
-        newObj = ZopePageTemplate(id, 'TEXT')
-        self._setObject(id, newObj)
-        # self.manage_addPageTemplate(id,title)
-        if RESPONSE is not None:
-            self.redirect(RESPONSE, 'manage_main')
-            
     def isActiveProject(self):
-        """check if the project is still active, default is true, set to false is the project is accomplished"""
+        """check if the project is still active, default is true."""
         return getattr(self, 'isActiveFlag', True)
  
     def checkActive(self, active):
@@ -1102,19 +1132,10 @@
     def getCompletedAt(self):
         """gibt das transformierte Datum zurueck, an dem das Projekt beendet wurde."""
         date = getattr(self, 'completedAt', '')
-      
         if date:
             return self.reTransformDate(date);
         else:
             return ""
-            # test ob parent abgeschlossen ist
-            try:  # TODO: ersetzte try except durch vernuenftige abfrage  
-                ct = self.getContexts(parents=self.getContent('xdata_05'), depth=1)
-                if (len(ct) > 0):  # is there are parent
-                        return ct[0][0].getCompletedAt()
-                return '';
-            except:
-                return '';
         
     def getStartedAt(self):
         """gibt das transformierte Datum zurueck, an dem Projekt begonnen wurde."""
@@ -1337,7 +1358,6 @@
             
     def getDefinedFields(self):
         """show all defined fields"""
-        
         return definedFields
 
     def getAttribute(self, field):
@@ -1496,7 +1516,7 @@
         else:
             return style    
 
-    def getLabel(self):
+    def getLabel_old(self):
         """returns label (or title) of this project"""
         l = self.getContent('xdata_07')
         if l:
@@ -1537,7 +1557,6 @@
 
     def getRootProject(self):
         """returns the root (=top level) project of the current project"""
-        
         ct = self.getContexts(parents=self.getContent('xdata_05'))
         if len(ct) > 0:
             return ct[-1][0]
@@ -1748,6 +1767,7 @@
             checkedScientists[names[nr]] = {'name' : name, 'key' : key, 'username' : username}
              
         self.setResponsibleScientistsList(checkedScientists)
+        self.updateProjectMembers()
         
         if fromEdit and (RESPONSE is not None):
             return self.editBasic()
@@ -1861,29 +1881,6 @@
         if len(memberlist) == 0:
             return
          
-        # update old format responsibleScientistsList
-        if isinstance(memberlist[0], tuple):
-            logging.debug("updateAllProjectMembers: updating memberlist for project %s" % self)
-            newScientists = {}
-            for m in memberlist:
-                name = m[0]
-                key = m[1] 
-                username = None
-                if key:
-                    if isinstance(key, list):
-                        key = key[0]
-                        
-                    # get username from db
-                    member = self.executeZSQL("select * from personal_www where lower(key) = %s", [key.lower()])
-                    if len(member) > 0:
-                        username = re.sub('@mpiwg-berlin\.mpg\.de', '', member[0].e_mail)
-                        
-                newScientists[name] = {'name': name, 'key' : key, 'username' : username}
-                
-            # set and re-read new list
-            self.setResponsibleScientistsList(newScientists)
-            memberlist = self.getResponsibleScientistsList()
-        
         # fill projects_members table
         self.executeZSQL("delete from projects_members where project_number = %s", [pNum])
         for m in memberlist:
@@ -1970,6 +1967,15 @@
         # return filtered list
         return [p for p in pl if (p.checkActive(active) and p.checkArchived(archived))]     
     
+
+    def getProject(self, projectNumber=None):
+        """returns the matching project"""
+        tree = self.getProjectTree()
+        if projectNumber is not None:
+            return tree.get(projectNumber)
+        
+        return None
+
     
     def getProjectsOfMember(self, key, active=1, archived=1):
         """returns a list of all projects of a member.
@@ -2010,6 +2016,55 @@
 
         return "updated %s projects!" % cnt
 
+    security.declareProtected('View management screens', 'updateAllProjects')
+    def updateAllProjects(self, updateResponsibleScientistsList=False):
+        """patches all current projects for old problems"""
+        cnt = 0
+        # go through all projects
+        for project in self.objectValues(spec='MPIWGProject'):
+            cnt += 1
+            #
+            # hasRelatedPublicationsOldVersion
+            #
+            if project.hasRelatedPublicationsOldVersion():
+                logging.debug("updateAllProjects(%s): update relatedPublicationsOldVersion!"%project.getId())
+                project.copyPublicationsToList()
+                                
+            #
+            # old format responsibleScientistsList
+            #
+            memberlist = project.getResponsibleScientistsList()
+            if len(memberlist) > 0 and isinstance(memberlist[0], tuple):
+                logging.debug("updateAllProjects(%s): updating memberlist for project %s" % project.getId())
+                newScientists = {}
+                for m in memberlist:
+                    name = m[0]
+                    key = m[1] 
+                    username = None
+                    if key:
+                        if isinstance(key, list):
+                            key = key[0]
+                            
+                        # get username from db
+                        member = self.executeZSQL("select * from personal_www where lower(key) = %s", [key.lower()])
+                        if len(member) > 0:
+                            username = re.sub('@mpiwg-berlin\.mpg\.de', '', member[0].e_mail)
+                            
+                    newScientists[name] = {'name': name, 'key' : key, 'username' : username}
+                    
+                # set new list
+                project.setResponsibleScientistsList(newScientists)
+
+            #
+            # remove old attributes
+            #
+            if hasattr(project, 'definedFields'):
+                logging.debug("updateAllProjects(%s): has definedFields!"%project.getId())
+                delattr(project, 'definedFields')
+                
+        return "updated %s projects!" % cnt
+                
+
         
 def manage_addMPIWGProjectFolderForm(self):
     """form for adding a MPIWGProjectFolder"""
--- a/MPIWGRoot.py	Fri Apr 26 19:09:50 2013 +0200
+++ b/MPIWGRoot.py	Fri Apr 26 20:31:21 2013 +0200
@@ -273,6 +273,19 @@
         items.sort(key=lambda x:int(x.weight))
         return items
 
+    def getDepartment(self, projectNumber=None):
+        """returns a Department object"""
+        dir = getattr(self, 'departments', None)
+        if dir is None:
+            return None
+
+        if projectNumber is not None:
+            for dep in dir.objectValues(spec='MPIWGDepartment'):
+                if dep.getProjectNumber() == projectNumber:
+                    return dep
+                
+        return None
+
     def getProjectFolder(self):
         """returns the MPIWGProjectFolder"""
         dir = getattr(self, 'projects', None)
@@ -447,18 +460,13 @@
         pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeMPIWGRootForm')).__of__(self)
         return pt()
 
-    def changeMPIWGRoot(self,title,connection_id,coneServiceURL,harvestPort,harvestServer,lang=None,autocommit=None,RESPONSE=None):
+    def changeMPIWGRoot(self,title,connection_id,coneServiceURL,lang=None,autocommit=None,RESPONSE=None):
         """change"""
         self.title=title
         self.connection_id=connection_id
         #self.disciplineList=disciplineList
         #self.themesList=themesList
         self.coneServiceURL=coneServiceURL
-        self.harvestServer=harvestServer
-        try:
-            self.harvestPort=int(harvestPort)
-        except:
-            logging.error("couldn't change port!: no number:"+harvestPort)
         
         if lang is not None:
             self.lang = lang
--- a/zpt/changeMPIWGRootForm.zpt	Fri Apr 26 19:09:50 2013 +0200
+++ b/zpt/changeMPIWGRootForm.zpt	Fri Apr 26 20:31:21 2013 +0200
@@ -19,21 +19,6 @@
 <p>Cone Service URL:<br/>
 <input size="100" tal:attributes="value python:getattr(here,'coneServiceURL','http://virtuoso.mpiwg-berlin.mpg.de:8080/MetaDataManagerRestlet/cone/')" name="coneServiceURL"/>
 </p>
-<p>Harvester ZEO server:<br/>
-<input tal:attributes="value python:here.getHarvestCacheServer()" name="harvestServer"/>
-</p>
-<p>Harvester ZEO server port:<br/>
-<input tal:attributes="value python:here.getHarvestCachePort()" name="harvestPort"/>
-</p>
-<!--
-<p>Discipline list (seperated by CR)<br>
-<textarea name="disciplineList" cols=50 rows=20  tal:content="python:getattr(here,'disciplineList','')" ></textarea>
-</p>
-<p>Themes List (seperated by CR)<br>
-<textarea name="themesList" cols=50 rows=20 tal:content="python:getattr(here,'themesList','')"></textarea>
-</p>
--->
-
 
 <p>
 <div class="form-element">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/project/extendedBibliography_template.zpt	Fri Apr 26 20:31:21 2013 +0200
@@ -0,0 +1,86 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html metal:define-macro="page">
+<metal:x metal:use-macro="here/main_template/macros/page">
+  <head>
+<tal:block metal:fill-slot="title">
+  <title tal:content="string:${here/getNumber} ${here/getProjectTitle}-Bibliography" />
+</tal:block>
+<tal:block metal:fill-slot="head"
+  tal:define="global proBaseUrl string:$root/${secmap/research}/projects;
+              global dept here/getDepartmentId;" />
+  </head>
+  <body>
+
+    <!-- middle column -->
+    <div class="center" metal:fill-slot="center">
+      <tal:block tal:replace="structure here/versionHeader" />
+      <tal:x tal:define="started here/getStartedAt" tal:condition="here/isArchivedProject">
+        <p>
+          (<span tal:condition="started" tal:content="string:$started-" /><span tal:condition="not:started">Completed:</span> <span
+            tal:content="here/getCompletedAt" />)
+        </p>
+      </tal:x>
+
+      <h1 tal:content="here/getProjectTitle">History of Scientific Objectivity, 18th-19th Cs</h1>
+      <p class="maintext_authors">
+        <tal:block tal:repeat="person here/getResponsibleScientistsList">
+          <a tal:omit-tag="python:not (person['username'] and here.isActiveMember(person['key']))"
+            tal:attributes="href string:$root/${secmap/staff}/members/${person/username}" tal:content="person/name"> Name of
+            responsible person</a>
+          <tal:block tal:condition="not:repeat/person/end">, </tal:block>
+        </tal:block>
+      </p>
+
+      <p class="maintext_more" tal:define="others here/getInvolvedScholars" tal:condition="others">
+        Other involved scholars: <span tal:content="structure others">Scholars </span>
+      </p>
+      <p class="maintext_more" tal:define="partners here/getCooperationPartners" tal:condition="partners">
+        Cooperation Partners: <span tal:content="structure partners">Partners</span>
+      </p>
+
+      <h2>Extended Bibliography</h2>
+
+      <tal:block
+        tal:define="
+             wgb python:here.getPublicationsOfTypes('workingGroupBook');
+             books python:here.getPublicationsOfTypes('book');
+             edited_books python:here.getPublicationsOfTypes('edited book');
+             articles python:here.getPublicationsOfTypes(['book','edited book'],neg=True);">
+
+        <tal:block tal:condition="wgb">
+          <h3>Working Group Books</h3>
+          <ul class="publicationlist">
+            <li tal:repeat="found3 wgb"><span tal:replace="structure python:here.decode(here.formatBibliography(found3))" /></li>
+          </ul>
+        </tal:block>
+        <tal:block tal:condition="books">
+          <h3>Books</h3>
+          <ul class="publicationlist">
+            <li tal:repeat="found3 books"><span tal:replace="structure python:here.decode(here.formatBibliography(found3))" />
+            </li>
+          </ul>
+        </tal:block>
+
+        <tal:block tal:condition="edited_books">
+          <h3>Edited Books</h3>
+          <ul class="publicationlist">
+            <li tal:repeat="found3 edited_books"><span
+              tal:replace="structure python:here.decode(here.formatBibliography(found3))" /></li>
+          </ul>
+        </tal:block>
+
+        <tal:block tal:condition="articles">
+          <h3>Articles and Chapters</h3>
+          <ul class="publicationlist">
+            <li tal:repeat="found3 articles"><span tal:replace="structure python:here.decode(here.formatBibliography(found3))" />
+            </li>
+          </ul>
+        </tal:block>
+      </tal:block>
+
+    </div>
+
+  </body>
+</metal:x>
+</html>
\ No newline at end of file
--- a/zpt/project/project_template.zpt	Fri Apr 26 19:09:50 2013 +0200
+++ b/zpt/project/project_template.zpt	Fri Apr 26 20:31:21 2013 +0200
@@ -4,24 +4,22 @@
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <tal:block metal:fill-slot="title">
-  <title tal:content="python:here.getContent('xdata_05')+'   '+here.getContent('WEB_title')" />
+  <title tal:content="string:${here/getNumber} ${here/getProjectTitle}" />
 </tal:block>
 <tal:block metal:fill-slot="head"
-  tal:define="global marginImages python:here.sortedByPlace('MPIWGProject_image');
-                           global dept python:here.getRootProject().getId();" />
+  tal:define="global proBaseUrl string:$root/${secmap/research}/projects;
+              global images here/getImageList;
+              global dept here/getDepartmentId;" />
 </head>
 <body>
 
   <!-- middle column -->
   <div class="center" metal:fill-slot="center">
     <tal:block tal:replace="structure here/versionHeader" />
-    <tal:x tal:condition="here/isArchivedProject">
+    <tal:x tal:define="started here/getStartedAt" tal:condition="here/isArchivedProject">
       <p>
-        (
-        <tal:x tal:condition="python:here.getStartedAt()!=''">
-          <span tal:content="python:here.getStartedAt()" />-</tal:x>
-        <tal:x tal:condition="not:python:here.getStartedAt()!=''">Completed:</tal:x>
-        <span tal:content="python:here.getCompletedAt()" />)
+        (<span tal:condition="started" tal:content="string:$started-"/><span tal:condition="not:started">Completed:</span>
+        <span tal:content="here/getCompletedAt"/>)
       </p>
     </tal:x>
 
@@ -34,125 +32,93 @@
       </tal:block>
     </p>
 
-    <p class="maintext_more" tal:condition="not:python:here.getContent('xdata_08')==''">
-      Other involved scholars: <span tal:content="structure python:here.getContent('xdata_08')">Scholars </span>
+    <p class="maintext_more" tal:define="others here/getInvolvedScholars" tal:condition="others">
+      Other involved scholars: <span tal:content="structure others">Scholars </span>
     </p>
-    <p class="maintext_more" tal:condition="not:python:here.getContent('xdata_12')==''">
-      Cooperation Partners: <span tal:content="structure python:here.getContent('xdata_12')">Partners</span>
+    <p class="maintext_more" tal:define="partners here/getCooperationPartners" tal:condition="partners">
+      Cooperation Partners: <span tal:content="structure partners">Partners</span>
     </p>
 
     <!-- inline image -->
-    <div class="pic_inline_container" tal:condition="marginImages">
-      <tal:block tal:repeat="marginImage python:marginImages">
+    <div class="pic_inline_container" tal:condition="images">
+      <tal:block tal:repeat="image python:images">
         <div class="pic_inline">
-          <a tal:condition="python:marginImage[1].width"
-            tal:attributes="href python:here.REQUEST['URL1']+'/'+marginImage[1].getId()+'/showImage'" target="image"> <img
-            tal:replace="structure python:marginImage[1].tag(scale=min(220.0/marginImage[1].width,1), border='0')" />
-          </a>
-          <pre tal:condition="not:python:marginImage[1].width">empty image</pre>
+          <a tal:condition="image/width"
+            tal:attributes="href python:request['URL1']+'/'+image.getId()+'/showImage'" target="image"><img width="220"
+            tal:attributes="src image/absolute_url" alt=""/><!--  <img tal:replace="structure python:image.tag(scale=min(220.0/image.width,1), border='0')" /> 
+            --></a>
+          <pre tal:condition="not:image/width">empty image</pre>
         </div>
-        <div class="caption_inline" tal:content="structure python:marginImage[1].caption">J.-A.-D. Ingres: Mme Moitessier,
-          1856. Oel/Lw. 120 x 92,1 cm. London, National Gallery.</div>
+        <div class="caption_inline" tal:content="structure image/caption">
+          J.-A.-D. Ingres: Mme Moitessier, 1856. Oel/Lw. 120 x 92,1 cm. London, National Gallery.
+        </div>
       </tal:block>
     </div>
     <!-- inline image -->
 
-    <div tal:content="structure python:here.getContent('WEB_project_description',filter='yes')">Project description</div>
+    <div tal:content="structure python:here.getDescription()">Project description</div>
 
   </div>
 
   <!-- right column -->
   <div class="sidebar" metal:fill-slot="sidebar">
 
+    <!-- this project is part of -->
     <div class="sideblock"
-      tal:define="contexts python:here.getContexts(parents=here.getContent('xdata_05'),depth=1,date=here.REQUEST.get('date',None))"
-      tal:condition="contexts">
-      <!-- this project is part of -->
-
+      tal:define="parents here/getSuperProjects;" tal:condition="parents">
       <div class="project parent">
         Part of:
-        <tal:block tal:repeat="context contexts">
-          <tal:x tal:condition="not:here/isArchivedProject">
-            <a tal:content="python:context[0].getContent('WEB_title')"
-              tal:attributes="href python:here.generateUrlProject(context[0].absolute_url(),project='yes')+'/index.html'" />
-          </tal:x>
-          <tal:x tal:condition="here/isArchivedProject">
-            <a tal:content="python:context[0].getContent('WEB_title')"
-              tal:attributes="href python:here.generateUrlProject(context[0].absolute_url(),project='yes')+'/index.html?showArchive=yes'" />
-          </tal:x>
-        </tal:block>
+        <a tal:define="parent python:parents[-1]" tal:content="parent/getProjectTitle"
+           tal:attributes="href python:parent.getUrl(baseUrl=proBaseUrl)+test(here.isArchivedProject(),'?showArchive=yes','')" />
       </div>
       <!-- end parent -->
     </div>
     <!-- sideblock -->
 
-    <tal:block tal:define="projects python:here.sortedByPlace('MPIWGProject_relatedProject');">
-      <div class="sideblock" tal:condition="python:len(projects)>0">
-        <h2>Related Projects</h2>
-        <div class="item" tal:repeat="project python:projects">
-          <a tal:attributes="href
-            python:root+'/'+secmap['research']+'/projects/'+project[1].objid"
-            tal:content="python:project[1].projectWEB_title" />
-        </div>
-        <!-- end item -->
+    <!-- related projects -->
+    <div class="sideblock" tal:define="projects here/getRelatedProjects" tal:condition="projects">
+      <h2>Related Projects</h2>
+      <div class="item" tal:repeat="project python:projects">
+        <a tal:attributes="href
+          python:root+'/'+secmap['research']+'/projects/'+project[1].objid"
+          tal:content="python:project[1].projectWEB_title" />
       </div>
-      <!-- sideblock -->
-
-    </tal:block>
+      <!-- end item -->
+    </div>
+    <!-- sideblock -->
 
-    <!-- <\!-- related publications -\-> -->
-
-    <tal:block tal:define="publications python:here.sortedByPlace('MPIWGProject_publication');">
-      <div class="sideblock" tal:condition="python:here.hasRelatedPublicationsOldVersion()">
+    <!-- related publications -->
+    <tal:block tal:define="publications here/getRelatedPublications;">
+      <div class="sideblock" tal:condition="publications">
         <h2>Related Publications</h2>
-        <div class="item" tal:condition="python:getattr(here,'WEB_related_pub_copied',False)"
-          tal:define="pub python:here.getContent('WEB_related_pub')" tal:content="structure pub">
-          "Die Kultur der wissenschaftlichen Objektivit&auml;t," in: Michael Hagner, ed., Ansichten der Wissenschaftsgeschichte
-          (Frankfurt am Main: Fischer Taschenbuchverlag GmbH, 2001): 137-158. <br /> (with Peter Galison), "The Image of
-          Objectivity," Representations no. 40 (Fall 1992): 81-128. Translated into German (2002) <br /> "Objectivity and the Escape
-          from Perspective," Social Studies of Science 22(1992): 597-618
-        </div>
-        <!-- end item -->
-      </div>
-      <!-- sideblock -->
-
-      <div class="sideblock" tal:condition="python:len(publications)>0">
-        <h2>Related Publications</h2>
-        <div class="item" tal:repeat="publication python:publications">
-          <tal:y condition="not:python:publication[1].hasLinkToBookPage(mode='cached')">
-            <tal:x condition="python:hasattr(publication[1],'publicationImage1')">
-              <a target="_blank" tal:attributes="href  python:publication[1].publicationImage1.absolute_url()"> <img width="150"
-                tal:attributes="src python:publication[1].publicationImage1.absolute_url()" />
+        <div class="item" tal:repeat="publication publications">
+          <tal:y condition="not:python:publication.hasLinkToBookPage(mode='cached')">
+            <tal:x condition="python:hasattr(publication,'publicationImage1')">
+              <a target="_blank" tal:attributes="href  python:publication.publicationImage1.absolute_url()"> <img width="150"
+                tal:attributes="src python:publication.publicationImage1.absolute_url()" />
               </a>
-              <a tal:condition="python:hasattr(publication[1],'publicationImage2')" target="_blank"
-                tal:attributes="href python:publication[1].publicationImage2.absolute_url()"> <img width="150"
-                tal:condition="python:hasattr(publication[1],'publicationImage2')"
-                tal:attributes="src python:publication[1].publicationImage2.absolute_url()" />
+              <a tal:condition="python:hasattr(publication,'publicationImage2')" target="_blank"
+                tal:attributes="href python:publication.publicationImage2.absolute_url()"> <img width="150"
+                tal:condition="python:hasattr(publication,'publicationImage2')"
+                tal:attributes="src python:publication.publicationImage2.absolute_url()" />
               </a>
               <br />
             </tal:x>
           </tal:y>
-          <tal:y condition="python:publication[1].hasLinkToBookPage(mode='cached')"
-            tal:define="urls python:publication[1].getImageUrls(mode='cached')">
+          <tal:y condition="python:publication.hasLinkToBookPage(mode='cached')"
+            tal:define="urls python:publication.getImageUrls(mode='cached')">
             <tal:x condition="python:len(urls)>0">
-              <a target="_blank" tal:attributes="href python:urls[0]"> <img width="150" tal:attributes="src python:urls[0]" />
-              </a>
-              <a tal:condition="python:len(urls)>1" target="_blank" tal:attributes="href  python:urls[1]"> <img width="150"
-                tal:attributes="src python:urls[1]" />
-              </a>
+              <a target="_blank" tal:attributes="href python:urls[0]"><img width="150" tal:attributes="src python:urls[0]" /></a>
+              <a tal:condition="python:len(urls)>1" target="_blank" tal:attributes="href python:urls[1]"><img width="150"
+                tal:attributes="src python:urls[1]" /></a>
               <br />
             </tal:x>
           </tal:y>
-          <tal:y condition="python:getattr(publication[1],'link','')==''">
-            <tal:x tal:content="structure python:publication[1].text" />
-            <br />
-          </tal:y>
-          <tal:y condition="not:python:getattr(publication[1],'link','')==''">
-            <a tal:content="structure python:publication[1].text" tal:attributes="href python:getattr(publication[1],'link','')" />
-            <br />
-          </tal:y>
-          <tal:x tal:condition="python:hasattr(publication[1],'description')"
-            tal:content="structure python:publication[1].description" />
+          <a tal:define="link publication/link | nothing;" tal:omit-tag="not:link" tal:content="structure python:publication.text" 
+             tal:attributes="href link"/>
+          <br />
+          <tal:x tal:condition="python:hasattr(publication,'description')"
+            tal:content="structure python:publication.description" />
         </div>
         <!-- end item -->
       </div>
@@ -168,57 +134,50 @@
     <!-- related publications -->
 
     <!-- projects covered -->
-
     <div class="sideblock"
-      tal:define="showArchive python:here.REQUEST.get('showArchive','no')=='yes';
-               contexts python:here.getContexts(childs=here.getContent('xdata_05'),depth=1,date=here.REQUEST.get('date',None))"
-      tal:condition="contexts">
+         tal:define="showArchive python:(request.get('showArchive','no')=='yes');
+                     children here/getSubProjects;"
+         tal:condition="children">
       <h2>
-        Projects <span class="proj_state"> <tal:x
-            tal:condition="not:python:(not(here.isArchivedProject() or showArchive) and here.hasChildren(onlyArchived=2))">
-            <a href="?">current</a>
-          </tal:x> <tal:x tal:condition="python:(not(here.isArchivedProject() or showArchive) and here.hasChildren(onlyArchived=2))">
-          current
-        </tal:x> &nbsp; <tal:x tal:condition="python:(not(here.isArchivedProject() or showArchive) and here.hasChildren(onlyArchived=2))">
-            <a href="?showArchive=yes">completed</a>
-          </tal:x> <tal:x tal:condition="not:python:(not(here.isArchivedProject() or showArchive) and here.hasChildren(onlyArchived=2))">
-          completed
-        </tal:x>
+        Projects 
+        <span class="proj_state">
+          <a href="?" tal:omit-tag="python:not (here.isArchivedProject() or showArchive)">current</a>
+          &nbsp; 
+          <a href="?showArchive=yes" tal:omit-tag="python:here.isArchivedProject() or showArchive">completed</a>
         </span>
       </h2>
-
-      <tal:y tal:repeat="context contexts">
-        <tal:x tal:condition="not:python:context[0].isArchivedProject() or  showArchive">
+      <tal:y tal:repeat="child children">
+        <tal:x tal:condition="python:not (child.isArchivedProject() or showArchive)">
           <div class="project">
-            <a tal:content="python:context[0].getContent('short_title')"
-              tal:attributes="href python:here.generateUrlProject(context[0].absolute_url(),project='yes')+'/index_html'" />
+            <a tal:content="child/getLabel"
+              tal:attributes="href python:child.getUrl(baseUrl=proBaseUrl)" />
           </div>
         </tal:x>
-        <tal:x tal:condition="python:context[0].isArchivedProject() and (here.isArchivedProject() or showArchive)">
-          <div class="project inactive">
-            <a tal:content="python:context[0].getContent('short_title')"
-              tal:attributes="href python:here.generateUrlProject(context[0].absolute_url(),project='yes')+'/index_html'" /> (
-            <tal:x tal:condition="python:context[0].getStartedAt()!=''">
-              <span tal:content="python:context[0].getStartedAt()" />-</tal:x>
-            <tal:x tal:condition="not:python:context[0].getStartedAt()!=''">Completed:</tal:x>
-            <span tal:content="python:context[0].getCompletedAt()" />)
+        <tal:x tal:condition="python:child.isArchivedProject() and (here.isArchivedProject() or showArchive)">
+          <div class="project inactive" tal:define="started child/getStartedAt">
+            <a tal:content="child/getLabel"
+              tal:attributes="href python:child.getUrl(baseUrl=proBaseUrl)" /> 
+            (<span tal:condition="started" tal:content="string:$started-"/><tal:x tal:condition="not:started">Completed: </tal:x><span tal:content="child/getCompletedAt"/>)
           </div>
         </tal:x>
       </tal:y>
     </div>
     <!-- projects covered -->
 
-
-    <div class="sideblock" tal:condition="python:here.hasRelatedDigitalSources()">
+    <!-- related digital sources -->
+    <div class="sideblock" tal:define="sources here/getRelatedDigitalSources" tal:condition="sources">
       <h2>Related digital sources</h2>
-      <div class="item" tal:content="structure python:here.getContent('xdata_11')">
-        Item 1 <br /> Item 2 <br /> Item 3 <br />
+      <div class="item" tal:content="structure sources">
+        digital sources
       </div>
     </div>
 
-    <div class="sideblock" tal:condition="not:python:here.getContent('xdata_13')==''">
+    <!-- funding institutions -->
+    <div class="sideblock" tal:define="funding here/getFundingInstitutions" tal:condition="funding">
       <h2>Funding Institutions</h2>
-      <div class="item" tal:content="structure python:here.getContent('xdata_13')">Funding</div>
+      <div class="item" tal:content="structure funding">
+        Funding
+      </div>
     </div>
     <!-- sideblock -->