diff MPIWGProjects.py @ 48:f59bdd5f4890

Merge with 5c6ad316e1ceef48e323907ab81dd50e7ef743b2
author dwinter
date Mon, 29 Apr 2013 16:02:24 +0200
parents 5c6ad316e1ce
children e40ff9829108 e718d9a72f19
line wrap: on
line diff
--- a/MPIWGProjects.py	Mon Apr 29 16:01:24 2013 +0200
+++ b/MPIWGProjects.py	Mon Apr 29 16:02:24 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:
@@ -824,10 +816,86 @@
               
     def getImageList(self):
         """returns the sorted list of images for this project"""
-        items = self.objectValues(spec='MPIWGProject_image')[:]
+        items = self.objectValues(spec='MPIWGProject_image')
+        # sort by place
+        return sorted(items, key=lambda x:int(getattr(x, 'place', 0)))
+
+
+    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):
@@ -864,6 +932,10 @@
                 self.manage_delObjects([id])
         except:
                 logging.error("ERROR MPIWG: %s %s" % sys.exc_info()[0:2])
+                
+        # invalidate thumbnail
+        self.projectThumb = None
+        
         if RESPONSE:
             self.redirect(RESPONSE, 'manageImages')
 
@@ -871,7 +943,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)
         
@@ -899,6 +970,9 @@
         obj.place = self.getLastImageNumber() + 1
         obj.id = filename
 
+        # invalidate thumbnail
+        self.projectThumb = None
+        
         if RESPONSE is not None:
             
             self.redirect(RESPONSE, 'manageImages')
@@ -921,7 +995,7 @@
             return cmp(x[1].archiveTime, y[1].archiveTime)
 
         if not date:
-            if self.isActual():
+            if self.isCurrentVersion():
                 return self
             else:
                 return None
@@ -954,16 +1028,12 @@
             return None
           
         
-    def isActual(self):
-        """gibt 1 zurueck wenn aktuell, 0 sonst"""
-        actualTime = time.localtime()
-        
+    def isCurrentVersion(self):
+        """Return if project is the current version."""
+        currentTime = time.localtime()
+        # print getattr(self,'archiveTime',currentTime)
+        return (getattr(self, 'archiveTime', currentTime) >= currentTime)
         
-        # print getattr(self,'archiveTime',actualTime)
-        if getattr(self, 'archiveTime', actualTime) < actualTime:
-            return 0
-        else:
-            return 1
         
     def copyObjectToArchive(self):
         """kopiere aktuelles objekt ins archiv"""
@@ -1005,43 +1075,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 +1137,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."""
@@ -1227,7 +1253,7 @@
         if not context:
             context = self
             
-        if self.isActiveProject() and self.isActual():
+        if self.isActiveProject() and self.isCurrentVersion():
              templates = self.en.getHarvestCache()
             
              ext = getattr(self, "harvest_main", None)
@@ -1337,7 +1363,6 @@
             
     def getDefinedFields(self):
         """show all defined fields"""
-        
         return definedFields
 
     def getAttribute(self, field):
@@ -1496,7 +1521,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 +1562,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]
@@ -1723,7 +1747,7 @@
         checkedScientists = {}
         names = {}
         keys = {}
-        for key in formdata.keys(): 
+        for key in formdata: 
             # gehe durch das Formular
             keyParts = key.split("_")
             if keyParts[0] == "responsibleScientist": 
@@ -1734,20 +1758,22 @@
                 elif keyParts[1] == "key":
                     keys[nr] = formdata[key]
          
-        for nr in names.keys():
+        for nr in names:
             name = names[nr]
             key = keys.get(nr, None)
             username = None
             if key:
                 # 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)
+                member = self.getMPIWGRoot().getStaffFolder().getMember(key=key)
+                if member is not None:
+                    username = member.getUsername()
                     
             # schreibe keys und namen in die Liste
             checkedScientists[names[nr]] = {'name' : name, 'key' : key, 'username' : username}
              
+        # update responsibleScientistsList
         self.setResponsibleScientistsList(checkedScientists)
+        self.updateProjectMembers()
         
         if fromEdit and (RESPONSE is not None):
             return self.editBasic()
@@ -1841,7 +1867,7 @@
             # create responsibleScientistsList automatically
             newScientists = {}
             names = p.identifyNames(p.getResponsibleScientists())
-            for name in names.keys():
+            for name in names:
                 logging.debug("updateAllProjectMembers: name=%s" % repr(name))
                 members = names[name]
                 if len(members) > 0:
@@ -1861,33 +1887,10 @@
         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:
-            memberKey = m.get('key')
+            memberKey = m.get('key', None)
             if not memberKey or not isinstance(memberKey, basestring):
                 logging.error("updateProjectMembers: not a valid member key: %s" % repr(memberKey))
                 continue
@@ -1934,12 +1937,12 @@
 
 
     def getProjectTree(self):
-        """returns the project hierarchy tree (and caches it).
+        """Return the project hierarchy tree (and cache it).
         
-        returns HashTree instance."""
+        Returns HashTree instance."""
         tree = self._v_projectTree 
         if tree is None:
-            tree = HashTree(keySeparator='.', keyFn=lambda x:getInt(x))
+            tree = HashTree(keySeparator='.', keyFn=getInt)
             for p in self.objectValues(spec='MPIWGProject'):
                 tree.add(p.getNumber(), p)
                 
@@ -1950,7 +1953,7 @@
     
     
     def getProjectsAsList(self, start, active=1, archived=1):
-        """returns flattened list of projects, starting from start.
+        """Return flattened list of projects, starting from start.
 
         active = 0 : all projects
         active = 1 : active projects
@@ -1970,9 +1973,18 @@
         # return filtered list
         return [p for p in pl if (p.checkActive(active) and p.checkArchived(archived))]     
     
+
+    def getProject(self, projectNumber=None):
+        """Return 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.
+        """Return a list of all projects of a member.
     
         @param key: member's key
         active = 0 : all projects
@@ -1989,15 +2001,17 @@
         # find projects in tree
         for r in res:
             p = tree.get(r.project_number)
+            # check if active
             if p is not None and p.checkActive(active) and p.checkArchived(archived):
                 projects.append(p)
             
+        projects.sort(key=lambda p:[int(n) for n in p.getNumber().split('.')])
         return projects        
         
         
     security.declareProtected('View management screens', 'updateAllProjectMembers')
     def updateAllProjectMembers(self, updateResponsibleScientistsList=False):
-        """re-creates responsibleScientistsLists and projects_members table from all current projects"""
+        """Re-create responsibleScientistsLists and projects_members table from all current projects."""
         # empty table
         self.executeZSQL('truncate table projects_members')
         cnt = 0
@@ -2010,6 +2024,66 @@
 
         return "updated %s projects!" % cnt
 
+
+    security.declareProtected('View management screens', 'updateAllProjects')
+    def updateAllProjects(self, updateResponsibleScientistsList=False):
+        """Patch all current projects for legacy problems."""
+        cnt = 0
+        # go through all projects
+        for (id, project) in self.ZopeFind(self, obj_metatypes=['MPIWGProject'], search_sub=1):
+            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" % 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.getMPIWGRoot().getStaffFolder().getMember(key=key)
+                        if member is not None:
+                            username = member.getUsername()
+                            
+                    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')
+                
+            #
+            # update extended bibliography
+            #
+            if hasattr(project, 'publicationList'):
+                logging.debug("updateAllProjects(%s): has publicationList!"%project.getId())
+                extpub = project.publicationList
+                if hasattr(extpub, 'connection_id'):
+                    logging.debug("updateAllProjects(%s): extended publication %s has connection_id=%s!"%(project.getId(),extpub.getId(),extpub.connection_id))
+            
+                
+        return "updated %s projects!" % cnt
+                
+
         
 def manage_addMPIWGProjectFolderForm(self):
     """form for adding a MPIWGProjectFolder"""