Mercurial > hg > MPIWGWeb
changeset 86:ab836d3f96dc
styles for staff list.
author | casties |
---|---|
date | Tue, 14 May 2013 17:24:30 +0200 |
parents | 271cf05a8648 |
children | 77f2478ae971 |
files | MPIWGStaff.py MPIWGStaff_old.py css/mpiwg.css zpt/staff/member_index_html.zpt zpt/www/common_template.zpt |
diffstat | 5 files changed, 171 insertions(+), 1109 deletions(-) [+] |
line wrap: on
line diff
--- a/MPIWGStaff.py Tue May 14 10:36:48 2013 +0200 +++ b/MPIWGStaff.py Tue May 14 17:24:30 2013 +0200 @@ -1,1010 +1,39 @@ """This file contains the classes for the organization of the staff""" -# TODO: pruefe ob die id der einzelnen tabellen, wie id in publications noch benutzt werden -# TODO: pruefe ob die bibliographischen felder in publications noch benutzt werden -# TODO: wird username gebraucht? from zExceptions import Redirect from OFS.Folder import Folder from Products.PageTemplates.PageTemplateFile import PageTemplateFile -from Products.PageTemplates.PageTemplate import PageTemplate -from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate -from Products.ZCatalog.CatalogPathAwareness import CatalogAware -from Products.versionedFile.extVersionedFile import extVersionedFileFolder -from AccessControl import getSecurityManager -from Products.ZSQLExtend.ZSQLExtend import ZSQLExtendFolder - -from Products.ZDBInterface.ZDBInterfaceFolder import ZDBInterfaceFolder from AccessControl import ClassSecurityInfo from App.class_init import InitializeClass from Products.ExtFile.ExtFile import * +from Globals import package_home +from Products.PythonScripts.standard import sql_quote +from Products.ExtFile import ExtFile import os import logging import email -from Globals import package_home -from Products.PythonScripts.standard import sql_quote -from types import * -import time -import logging import re -from OFS.Cache import Cacheable -import urllib2 -import transaction + +from Products.ZDBInterface.ZDBInterfaceFolder import ZDBInterfaceFolder from SrvTxtUtils import getHttpData, getAt, getInt, unicodify, utf8ify -import bibliography - -from MPIWGHelper import * -#ersetzt logging -def logger(txt,method,txt2): - """logging""" - logging.info(txt+ txt2) - -departmentList="Renn\nRheinberger\nDaston\nKlein\nSibum\nIT\nInstitut\nBibliothek" -coneService="http://127.0.0.1:8280/MetaDataManagerRestlet/cone/" # kann in MPIWGRoot konfiguriert werden. - - - -def createNewDBEntry(self,publish_the_data,key,name,vorname,titles_new,position,e_mail,e_mail_p,date_from,date_to,abteilung,heimat_inst,funded_by="",e_mail2="",txt="",txt_p="no",stay_at_mpiwg="",group="",web_object_created="no",current_work=""): - """lege person in der datenbank an""" - - if date_to=="": # wenn date_to leer - date_to="date_none" - - if date_from=="": # wenn date_fromleer - date_from="date_none" - msg="" - #test ob id schon existiert - if self.ZSQLQuery("select key from personal_www where key='%s'"%id): - return False,"ERROR:key%s already exists"%key - - #eintragen - columnlist="""publish_the_data,key,last_name,first_name,titles_new,status,e_mail,e_mail_p,date_from,date_to,department,home_inst,funded_by,e_mail2,date_stay_at_mpiwg,web_object_created,"group",current_work,current_work_p """ - insertTuple=(publish_the_data,key,name,vorname,titles_new,position,e_mail,e_mail_p,date_from,date_to,abteilung,heimat_inst,funded_by,e_mail2,stay_at_mpiwg,web_object_created,group,current_work,"yes") - - insert=[] - for element in insertTuple: - if element=="date_none": # date_none eintrag wird zu null uebersetzt - insert.append('null') - else: - insert.append("%s"%self.ZSQLQuote(element)) - - insertStr=",".join(insert) - queryStr="INSERT INTO personal_www (%s) VALUES (%s)"%(columnlist,insertStr) - self.ZSQLQuery("SET DATESTYLE TO 'German'") - self.ZSQLQuery(queryStr) - logging.info("QQQQ %s:"%queryStr) - #currentwork - #if not (current_work==""): - # queryStr="INSERT INTO current_work (key_main,current,publish) VALUES ('%s',%s,'%s')"%(key,self.ZSQLQuote(current_work),"yes") - - # self.ZSQLQuery(queryStr) - - return True,msg - - -class MPIWGStaff(CatalogAware,ZSQLExtendFolder,Cacheable): - """Staff""" - - meta_type="MPIWGStaff" - default_catalog='MembersCatalog' - departmentList=departmentList - #_v_cone=None; - security=ClassSecurityInfo() - - manage_options = Folder.manage_options+( - {'label':'Edit','action':'changeMPIWGStaffForm'}, - {'label':'Change Publications Special','action':'changePublications_specialForm'}, - ) + Cacheable.manage_options - - __manager_id = "ramCache" - def __init__(self,id, lastName,firstName,key): - """init""" - self.id=id - self.title=key - self.lastName=lastName - self.firstName=firstName - self.key=key - - # compat TODO: remove this - def getat(self, array, idx, default=None): - """returns always an int (0 in case of problems)""" - return getAt(array, idx, default) - - # compat TODO: remove this - def decode(self, s): - """TODO: remove this""" - return unicodify(s) - - def redirect(self,RESPONSE,url): - """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen""" - - timeStamp=time.time() - - if url.find("?")>-1: #giebt es schon parameter - addStr="&time=%s" - else: - addStr="?time=%s" - - RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT') - logging.error(email.Utils.formatdate()+' GMT') - RESPONSE.redirect(url+addStr%timeStamp) - - def getKeyUTF8(self): - """get db_key utf8""" - logging.debug("KEY - MPIWGStaff 1:"+self.getKey()) - logging.debug("KEY - MPIWGStaff 2 :"+utf8ify(self.getKey())) - - return utf8ify(self.getKey()) - - def setKey(self,key): - """set key""" - self.key=key - - def rmKey(self): - """rm""" - self.key=None - return "" - - def getKey(self): - """get database key""" - - - if getattr(self,'key',None): - logging.debug("KEY - MPIWGStaff 4:"+self.key) - #logging.error("SAVED KEY:%s"%self.key) - return unicodify(self.key.lower()) - #return self.key.lower() - - #fuer alt faelle ohne key - #logging.error("NEW KEY:%s"%(self.firstName+'_'+self.lastName).lower().replace(' ','')) - return (self.firstName+'_'+self.lastName).lower().replace(' ','') - - def getConnectionObj(self): - """returns connection id (from root)""" - try: - root = self.getMPIWGRoot() - return root.getConnectionObj() - except: - return self.en.getConnectionObj() - - def isPublished(self): - """gib publications status aus der datenbank aus""" - key=self.getKey() - query="select count(publish_the_data) from personal_www where lower(key)='%s' and publish_the_data='yes'"%key - - res = self.ZSQLQuery(query) - - if res and res[0].count>0: - return True - else: - return False - - - - def updateDBEntry(self,publish_the_data,date_from,date_to,DBid=None,stay_at_mpiwg="",position="",abteilung=""): - """zpddatedb""" - if not DBid: - DBid=self.getDBId() - - - self.ZSQLQuery("SET DATESTYLE TO 'German'") - - test=self.ZSQLQuery("select id from personal_www where id='%s' "%DBid) +import MPIWGHelper - - if test and (len(test)>0): #dataset exists - logger("MPIWG Web",logging.INFO,'UPDATE: _table="personal_www",_identify="id=%s"'%DBid+',publish_the_data=%s'%publish_the_data+',date_from=%s'%date_from+',date_to=%s'%date_to+',stay_at_mpiwg=%s'%stay_at_mpiwg+',position=%s'%position) - self.ZSQLChange(_table="personal_www",_identify="id=%s"%DBid,publish_the_data=publish_the_data, - date_from=date_from, - date_to=date_to,stay_at_mpiwg=stay_at_mpiwg,position=position,abteilung=abteilung) - return True - else: - return False - - def getPublicationSelectionMode(self): - """get publication selection mode, default 'priority'""" - return getattr(self,'publicationSelectionMode','priority') - - def changePublicationSelectionMode(self,publicationSelectionMode,RESPONSE=None): - """change PublicationSelectionMode""" - - self.publicationSelectionMode=publicationSelectionMode - self.ZCacheable_invalidate() - if RESPONSE: - self.redirect(RESPONSE,"editPublications") - - - def downloadCV(self,RESPONSE): - """download cv file""" - ob=self._getOb("downloadableFiles")._getOb("cv.pdf") - - RESPONSE.redirect(ob.absolute_url()+"/download") - - def getLastUpdateCV(self): - """getDate of Last Update""" - try: - ob=self._getOb("downloadableFiles")._getOb("cv.pdf") - return ob.getLastChangeDate() - except: - return "No file yet!" - def getLastUpdatePublications(self): - """getDate of Last Update""" - try: - ob=self._getOb("downloadableFiles")._getOb("publications.pdf") - return ob.getLastChangeDate() - except: - return "No file yet!" - def downloadPublications(self,RESPONSE): - """download publications""" - ob=self._getOb("downloadableFiles")._getOb("publications.pdf") - - RESPONSE.redirect(ob.absolute_url()+"/download") - - def changeDownloads(self,cv_pdf=None,cv_publish=None,publications_pdf=None,publications_publish=None,RESPONSE=None): - """"change the downloadable files""" - self.ZCacheable_invalidate() - if not hasattr(self,'downloadableFiles'): - - extFolder = extVersionedFileFolder() - extFolder.id = "downloadableFiles" - self._setObject(extFolder.id,extFolder) - - ob = self._getOb("downloadableFiles") - - if cv_publish: - self.cv_publish=cv_publish - - if publications_publish: - self.publications_publish=publications_publish - - if cv_pdf: - if not hasattr(ob,"cv.pdf"): - ob.addFile("",cv_pdf,newName="cv.pdf") - - else: - cvFile = getattr(ob,"cv.pdf") - cvFile.addContentObject("","",file=cv_pdf) - - if publications_pdf: - if not hasattr(ob,"publications.pdf"): - ob.addFile("",cv_pdf,newName="publications.pdf") - - else: - cvFile = getattr(ob,"publications.pdf") - cvFile.addContentObject("","",file=publications_pdf) - - if RESPONSE: - self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER']) - - - def getPublishImage(self): - """publish the image??, default no""" - return getattr(self,'publishImage','no') - - def updateImage(self,publishImage,file=None,rename=None,RESPONSE=None): - """update image""" - - if file and not(file.filename==""): - if self.getImageObj(): - self.getImageObj().updateImage(file,_rename=None,RESPONSE=None) - else: - # create new image object - xp = file.filename.rfind('.') - if xp > 0: - ext = file.filename[xp:] - #fn = self.getId()+ext - fn = self.getId() - logger("MPWIG STAFF", logging.INFO, "new filename: %s"%fn) - self.getImageFolder().addImage2(file,fileName=fn) - else: - logger("MPWIG STAFF", logging.ERROR, "uploaded filename %s has no extension!"%file.filename) - - self.publishImage=publishImage - - if RESPONSE: - self.redirect(RESPONSE,"edit") - - def getImageFolder(self): - """getImageFolder""" - #TODO: make place of staff image folder configurable - - try: - return self.getPhysicalRoot().www_neu.images.staff_images - except: - logger("MPWIG STAFF", logging.ERROR, "image folder not found: has to be add /www_neu/staff_images") - return None - - def getImageObj(self): - """getImage""" - imageFolder=self.getImageFolder() - - if not imageFolder: return None - - image=getattr(imageFolder,self.getId(),None) - - if not image: - for suffix in ['jpg','tif']: - - image=getattr(imageFolder,self.getId()+"."+suffix,None) - if image: - break - return image - - def getImageUrl(self): - """getImageUrl""" - image=self.getImageObj() - if not image: - return None - else: - return self.getImageObj().absolute_url()+"/image" - - def PrincipiaSearchSource(self): - """Return cataloguable key for ourselves.""" - return str(self) +# +# compatibility +# TODO: should be removed when done +import MPIWGStaff_old - def getPersonID(self): - """gibt den ID fuer die Person zurueck" - im Moment ist personID = id, i.e. e-mail - """ - return self.id - - def getConeUrl(self): - """gibt coneURL zurueck""" - - self.coneService=getattr(self, "coneServiceURL",coneService) - logging.debug("coneservice:"+self.coneService) - - if getattr(self,'_v_cone',None)==None: - try: - - self._v_cone=getHttpData(self.coneService+self.getPersonID()) - #cone = urllib2.urlopen(self.coneService+self.getPersonID()) - #self._v_cone=cone.read() - if self._v_cone==None: - self._v_cone="" - except: - self._v_cone="" - return "" - - return self._v_cone - - - - - def harvest_page_old(self,context=None): - """geharvestete seite = verschlankte version von members_main""" - #pt = getTemplate(self, "harvest_members_main") - - if not self.isPublished(): - return "" - if not context: - context=self - - - ext=getattr(self,"harvest_members_main",None) - if ext: - return getattr(self,ext.getId())() - - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','harvest_members_main')).__of__(context) - - - return pt() - - def harvest_page(self,mode="normal"): - """harvest""" - logging.debug("AAAAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") - if not self.isPublished(): - return - st = getattr(self.en.staff.members,self.getId()).index_html(mode) - - templates = self.en.getHarvestCache() - #templates = getattr(self,'getHarvestCache',self.en.getHarvestCache)() - rendered = st - templates[self.absolute_url()]=rendered - transaction.commit() - return rendered - - - - def index_html(self,mode="normal"): - """show homepage""" - - bound_names={} - request = self.REQUEST - if request is not None: - response = request.response - if not response.headers.has_key('content-type'): - response.setHeader('content-type', 'text/html') - - security = getSecurityManager() - bound_names['user'] = security.getUser() - - # Retrieve the value from the cache. - keyset = None - if self.ZCacheable_isCachingEnabled(): - - # Prepare a cache key. - keyset = {'here': self} - - result = self.ZCacheable_get(keywords=keyset) - - if result is not None: - # Got a cached value. - return result - - # look for individual page - if self.hasObject("index.html"): - pt = getattr(self, "index.html") - # else use template - else: - if mode=="slim": - pt = getTemplate(self, "members_main_slim") - else: - pt = getTemplate(self, "members_main") - # Execute the template in a new security context. - security.addContext(self) - - try: - result = pt.pt_render(extra_context=bound_names) - if keyset is not None: - # Store the result in the cache. - self.ZCacheable_set(result, keywords=keyset) - - return result - finally: - security.removeContext(self) - - - - def changePublications_specialForm(self): - """Priority publications manual field""" - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changePublications_special.zpt')).__of__(self) - return pt() - - def changePublications_special(self,usePublicationsSpecial=None,specialPublicationsField=None,RESPONSE=None): - """change publications special params""" - self.ZCacheable_invalidate() - if usePublicationsSpecial: - self.usePublicationsSpecial=True - - else: - self.usePublicationsSpecial=False - - self.specialPublicationsField=specialPublicationsField[0:] - - if RESPONSE is not None: - self.redirect(RESPONSE,'manage_main') - - - def publications_full(self): - """show publication""" - pt=getTemplate(self, "publications_full_main") - return pt() - - def talks_full(self): - """show talks""" - pt=getTemplate(self, 'talks_full_main') - return pt() - - def teaching_full(self): - """show talks""" - pt=getTemplate(self, 'teaching_full_main') - return pt() - - def changeMPIWGStaffForm(self): - """change form""" - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGStaff.zpt')).__of__(self) - return pt() +createNewDBEntry = MPIWGStaff_old.createNewDBEntry - security.declareProtected('View management screens','changeMPIWGStaff') - def changeMPIWGStaff(self,lastName,firstName,key=None,RESPONSE=None): - """change it""" - self.ZCacheable_invalidate() - self.title="%s, %s"%(lastName,firstName) - self.lastName=lastName - self.firstName=firstName - if key: - self.key = key - - - if RESPONSE is not None: - self.redirect(RESPONSE,'manage_main') - - security.declareProtected('View management screens','edit') - def edit(self): - """Edit the pages""" - #TODO: zusammenspiel mit apache, redirect auf 18080 rausnehmen bzw. zumindest verallgemeinern - #if self.REQUEST['SERVER_URL']=="http://www.mpiwg-berlin.mpg.de": - # redURL="http://xserve04.mpiwg-berlin.mpg.de:18080/www_neu/de/mitarbeiter/members/%s/edit"%self.getId() - # - # self.REQUEST.RESPONSE.redirect(redURL) - - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMPIWGStaff.zpt')).__of__(self) - - - logging.debug("XX:"+email.Utils.formatdate().split("-")[0]+'GMT') - return pt() - - mainEditFile=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMPIWGStaff_main.zpt')) - addPublicationsBib=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addPublicationsBib.zpt')) - - def getPathStyle(self, path, selected, style=""): - """returns a string with the given style + 'sel' if path == selected.""" - - if path == selected: - return style + 'sel' - else: - return style - - - def getLabel(self): - """returns a label for this object""" - return self.title - - def getBreadcrumbs(self): - """return list of breadcrumbs from here to the root""" - crumbs = [] - # skip direct parent Folder /members/ - parent = self.aq_parent.aq_parent - # get parents breadcrumbs - logging.debug("getbreadcrumbs-: title=%s self=%s parent=%s"%(self.title, repr(self), repr(parent))) - if hasattr(parent, 'getBreadcrumbs'): - logging.debug("getbreadcrumbs: recurse to %s"%parent) - crumbs = parent.getBreadcrumbs() - - # try to get acquisition URL from parent - if hasattr(parent, 'absolute_url'): - baseUrl = "%s/%s/"%(parent.absolute_url(), 'members') - else: - baseUrl = "/en/staff/members/" - - # add this - crumbs.append((self.getLabel(), baseUrl+self.getId(), self)) - - return crumbs - - - def changeCurrentWork(self,current_work,key,publish="yes",RESPONSE=None): - """change current work""" - - query="UPDATE personal_www SET current_work =%s WHERE key='%s'" - - self.ZSQLQuery(query%(self.ZSQLQuote(current_work),key)) - - query="UPDATE personal_www SET current_work_p =%s WHERE key='%s'" - - self.ZSQLQuery(query%(self.ZSQLQuote(publish),key)) - self.ZCacheable_invalidate() - if RESPONSE: - self.redirect(RESPONSE,"edit") - - security.declareProtected('View management screens','changeResearch') - def changeResearch(self,noredirect=None,RESPONSE=None): - """change the research entries""" - self.ZCacheable_invalidate() - newEntries={} - key_main=self.REQUEST.form['key_main'] - - mainfieldL=self.REQUEST.form['main_fields'].split(",") - mainfield={} - for x in mainfieldL: - tmp=x.split('__') - mainfield[tmp[0]]=tmp[1] - for field in self.REQUEST.form.keys(): - splittedField=field.split("__") - if len(splittedField)<3: - pass #kein datenbank eintrag - - elif splittedField[2]=='new': # store new entries - if not newEntries.has_key(splittedField[0]): - newEntries[splittedField[0]]={} - - newEntries[splittedField[0]][splittedField[1]]=self.REQUEST.form[field] - - else: - query="UPDATE %s "%splittedField[0] - query+="SET %s = '%s' "%(splittedField[1],sql_quote(self.REQUEST.form[field])) - query+="WHERE oid = '%s' "%sql_quote(splittedField[2]) - - self.ZSQLQuery(query) - - - #new entries - for newEntry in newEntries.keys(): - query="INSERT INTO %s "%newEntry - keys=['key_main'] - values=["'"+sql_quote(key_main)+"'"] - for key in newEntries[newEntry].keys(): - keys.append(key) - values.append("'"+sql_quote(newEntries[newEntry][key])+"'") - - - keystring=",".join(keys) - - valuestring=",".join(values) - - query+=" (%s) "%keystring - query+="VALUES (%s)"%valuestring - if not (newEntries[newEntry][mainfield[newEntry]].lstrip().rstrip()==""): - self.ZSQLQuery(query) - - if not noredirect: - self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER']) - - security.declareProtected('View management screens','editCV') - def editCV(self,cv=None,oid=None,RESPONSE=None): - """edit Cv""" - - if (not oid): - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editCV.zpt')).__of__(self) - return pt() - - query="UPDATE personal_www SET cv =%s WHERE oid='%s'" - self.ZCacheable_invalidate() - self.ZSQLQuery(query%(self.ZSQLQuote(cv),oid)) - - if RESPONSE: - self.redirect(RESPONSE,"editCV") - - - def getProfile(self): - """get the profile""" - self.REQUEST.RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT') - - founds=self.ZSQLInlineSearchU(_table='personal_www',key=self.getKeyUTF8()) - html="""<html><body>%s</body></html>""" - if founds.profile and founds.profile != "": - - return html%founds.profile - else: - - return html%self.generateProfileForPerson(founds) - - def editProfile(self,oid=None,RESPONSE=None, kupu=None, preview=None): - """edit Profile, new entry replaces CD, current work and research interests""" - - if (not oid): - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editProfile.zpt')).__of__(self) - return pt() - - self.ZCacheable_invalidate() - - - if preview: - pass - #TODO: not supported yet - #kupu=preview - # find content of body tags - - start=kupu.find("<body>") - end=kupu.find("</body>") - - newcontent= kupu[start+6:end] - - - - - if preview: - #TODO: not supported yet - if RESPONSE: - self.redirect(RESPONSE,"editProfile") - - #return self.preview(newcontent) - - query="UPDATE personal_www SET profile=%s WHERE oid='%s'" - self.ZSQLQuery(query%(self.ZSQLQuote(newcontent),oid)) - logging.error("PROFILE:"+query%(self.ZSQLQuote(newcontent),oid)) - if RESPONSE: - self.redirect(RESPONSE,"editProfile") - - - - def generateProfileForPerson(self,person): - """erzeugt ein automatisches Profil aus den alten Eintraegen CV, Current work, und research interests""" - - ret="" - #founds=self.ZSQLInlineSearch(_table='research_interest',key_main=person.getKeyUTF8()) - founds=self.ZSQLInlineSearch(_table='research_interest',key_main=person.key) - if founds: - ret="<p class=\"bio_section_header\">Research interests: </p><br/>" - for found in self.sortPriority(founds): - ret+=found.interest+"<br/>" - - - if (person.current_work) and (not person.current_work==""): - ret+="<p class=\"bio_section_header\">Current work: </p><br/>" - - ret+=person.current_work+"<br/>" - if (person.cv) and (not person.cv==""): - ret+="<p class=\"bio_section_header\">Curriculum Vitae: </p><br/>" - ret+=self.formatAscii(person.cv) - - return ret - security.declareProtected('View management screens','editDownloads') - def editDownloads(self): - """editiere die Downloads von der Webseite""" - - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editDownloads.zpt')).__of__(self) - return pt() - - security.declareProtected('View management screens','editAdditionalLinks.zpt') - def editAdditionalLinks(self): - """editiere die Downloads von der Webseite""" - - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editAdditionalLinks.zpt')).__of__(self) - return pt() - +class MPIWGStaff(MPIWGStaff_old.MPIWGStaff): + """Staff""" + pass - security.declareProtected('View management screens','editAwards') - def editAwards(self,awards=None,oid=None,RESPONSE=None): - """edit a awards""" - - if (not oid): - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editAwards.zpt')).__of__(self) - return pt() - self.ZCacheable_invalidate() - query="UPDATE personal_www SET awards =%s WHERE oid='%s'" - - self.ZSQLQuery(query%(self.ZSQLQuote(awards),oid)) - - - if RESPONSE: - self.redirect(RESPONSE,"editAwards") - - security.declareProtected('View management screens','editTalks') - def editTalks(self): - """edit talks""" - - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editTalks.zpt')).__of__(self) - return pt() - - security.declareProtected('View management screens','editTeaching') - def editTeaching(self): - """edit Teaching""" - - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editTeaching.zpt')).__of__(self) - return pt() - - def getDocTypes(self): - finds = self.ZopeFind(self.metadata.main.meta.bib,obj_metatypes=["OSAS_MetadataMapping__neu"]) - - list= [x[0] for x in finds] - return "\n".join(list) - - security.declareProtected('View management screens','editMainData') - def editMainData(self,REQUEST=None,RESPONSE=None): - """edit main data""" - self.ZCacheable_invalidate() - argv=REQUEST.form - - if not argv.has_key('last_name'): - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMainData.zpt')).__of__(self) - return pt() - else: - self.ZSQLChange(argv,_table="personal_www",_identify="lower(key)=%s"%utf8ify(self.getKey().lower()),USE_FORM="yes") - # aendere auch dien enstsprechen infos in der instance - self.changeMPIWGStaff(argv['last_name'],argv['first_name']); - - - - self.reindex_object() - - - - if RESPONSE: - self.redirect(RESPONSE,"editMainData") - - security.declareProtected('View management screens','newBibliogrpaphy') - def newBibliography(self,_docType=None, _addEntry=None,RESPONSE=None,**argv): - - """add an entry to the bibliography""" - if not _docType: #kein docType - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','newBibliographyEntryDocType.zpt')).__of__(self) - return pt() - elif _docType and not _addEntry: #doctype aber keine daten - self.REQUEST['_docType']=_docType - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','newBibliographyEntry.zpt')).__of__(self) - return pt() - else: #doctype und daten - try: - newId=self.ZSQLSimpleSearch("select nextval('id_raw')")[0].nextval - except:#id_raw existiert nich, dann neu erzeugen - - self.createOrUpdateId_raw() - newId=self.ZSQLSimpleSearch("select nextval('id_raw')")[0].nextval - - bookId="b%06i" % newId - - self.ZSQLAdd(argv,_table="bibliography",reference_type=_docType,id=bookId) - - self.ZSQLAdd(_useRequest=False,_table="publications",id_gen_bib=bookId,key_main=self.getDBId(),publish='yes') - self.updatePublicationDB(personId=self.getDBId()) - - - if RESPONSE: - self.redirect(RESPONSE,"editPublications") - - return True - - security.declareProtected('View management screens','editImage') - def editImage(self): - """edit images""" - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editImageStaff.zpt')).__of__(self) - return pt() - - security.declareProtected('View management screens','editBibliography') - def editBibliography(self): - """edit the bibliography""" - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editBibliographyEntry.zpt')).__of__(self) - return pt() - - - security.declareProtected('View management screens','editPublications') - def editPublications(self): - """edit the bibliographie""" - - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editPublications.zpt')).__of__(self) - return pt() - - def changeSortingMode(self,sortingMode,RESPONSE=None,REQUEST=None): - """change sorting mode""" - self.ZCacheable_invalidate() - self.sortingMode=sortingMode - - if RESPONSE and REQUEST: - self.redirect(RESPONSE,REQUEST['HTTP_REFERER']) - - return True - - def getSortingMode(self): - """get sorting mode""" - mode=getattr(self,'sortingMode','priority') - if mode=="year": - return "year DESC" - else: - return mode - - def integer(self,value): - try: - return int(value) - except: - return 0 - - security.declareProtected('View management screens','changePublications') - def changePublications(self,RESPONSE=None): - """change the publication list""" - self.changeResearch(noredirect=True) - self.ZCacheable_invalidate() - #self.updatePublicationDB(personId=self.getDBId()) - self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER']) - - - - security.declareProtected('View management screens','addPublications') - def addPublications(self,submit=None,REQUEST=None,noredirect=None,RESPONSE=None): - """add publications""" - - #setzte flag ob aufruf aus suchformular - - if REQUEST.get("QUERY_STRING",None) and (not submit): - self.REQUEST.set('fromSearch','1') - else: - self.REQUEST.set('fromSearch','0') - - if not submit or (not (submit == "add")): - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addPublications.zpt')).__of__(self) - return pt() - - #new entries - entries = REQUEST.form.get('addEntries',None) - if not (type(entries) is ListType): - entries=[entries] - - - for bibId in entries: - query="INSERT INTO %s " % "publications" - query+="(key_main,id_institutsbibliographie,publish) " - query+="VALUES ('%s','%s','yes')" %(sql_quote(self.getKey()),sql_quote(bibId)) - - #self.ZSQLAdd(_table="publications",id_institutsbibliographie=bibId,id_main=self.getDBId(),publish='yes') - self.ZSQLQuery(query) - - self.updatePublicationDB(personId=self.getKey()) - - if not noredirect: - - self.redirect(RESPONSE,"./editPublications") - - return True - - - def getDBId(self): - """get id from the personal database""" - - #in der neuen version ist definitions gemaess der key der Datenbank gleich dem key im Object. - # TODO: remove all occurences of getDBId and replaces it by getKey - return self.getKey() - - formatBiblHelp=bibliography.formatBiblHelp - - def sortBibliography(self,list,sortingMode=None,max=None): - if not sortingMode: - sortingMode=self.getSortingMode() - - if sortingMode == "year": - l= self.sortYear(list) - else: - l=self.sortPriority(list) - - if max: - return l[0:min(len(l),max)] - else: - return l - - def sortPriority(self,list): - def sort(x,y): - try: - xInt=int(x.priority) - except: - xInt=0 - try: - yInt=int(y.priority) - except: - yInt=0 - - return cmp(xInt,yInt) - - if not list: - return [] - tmp=[x for x in list] - tmp.sort(sort) - - return tmp - - def sortYear(self,list): - #TODO: sort TO APPEAR and TO BE PUBLISHED etc... - - def sort(x,y): - try: - xInt=int(x.year) - except: - xInt=0 - try: - yInt=int(y.year) - except: - yInt=0 - - return cmp(yInt,xInt) - - - tmp=[x for x in list] - - tmp.sort(sort) - return tmp - - def deleteField(self,table,oid,RESPONSE=None): - """delete entry""" - query="DELETE FROM %s WHERE oid = '%s'"%(table,oid) - - self.ZSQLQuery(query) - self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER']) - - -def manage_addMPIWGStaffForm(self): - """form for adding the project""" - pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMPIWGStaffForm.zpt')).__of__(self) - return pt() - -def manage_addMPIWGStaff(self,id,lastName,firstName,RESPONSE=None): - """add it""" - newObj=MPIWGStaff(id,lastName,firstName) - - self._setObject(id,newObj) - - if RESPONSE is not None: - self.redirect(RESPONSE,'manage_main') +manage_addMPIWGStaffForm = MPIWGStaff_old.manage_addMPIWGStaffForm +manage_addMPIWGStaff = MPIWGStaff_old.manage_addMPIWGStaff @@ -1035,7 +64,7 @@ id = stack[-1] logging.debug(id) - member = self.getMember(id) + member = self.getMember(username=id) if member is not None: member = member.__of__(self) request.set('MPIWGStaffMember', member) @@ -1062,11 +91,9 @@ member = REQUEST.get('MPIWGStaffMember', None) mode = REQUEST.get('MPIWGStaffMode', None) if member is not None: - if mode is not None: return member.execute(mode,REQUEST); - logging.debug("member: key=%s"%(member.getKey())) pt = None try: @@ -1091,13 +118,13 @@ email = '%s@mpiwg-berlin.mpg.de'%username content = self.executeZSQL("select * from personal_www where e_mail = %s", [email]) if len(content) > 0: - member = MPIWGStaffMember(self, dbresult=content) + member = MPIWGStaffMember(self, dbresult=content[0]) elif key is not None: # TODO: sometimes key is lowercased (e.g. responsibleScientistsList), we should fix the data content = self.executeZSQL("select * from personal_www where lower(key) = %s", [key.lower()]) if len(content) > 0: - member = MPIWGStaffMember(self, dbresult=content) + member = MPIWGStaffMember(self, dbresult=content[0]) return member @@ -1108,6 +135,32 @@ return len(res) > 0 + def getMemberList(self, sortBy='last_name', onlyCurrent=False, limit=0): + """Return the list of members. + + Returns a list of MPIWGStaffMember objects. + """ + members = [] + query = "select * from personal_www_list where publish_the_data = 'yes' and is_scholar='yes'" + + if onlyCurrent: + query += " and date_from < CURRENT_DATE" + + if sortBy == 'last_name': + query += " order by lower(last_name)" + elif sortBy == 'date_from': + query += " order by date_from DESC" + + if limit > 0: + query += " limit %s"%int(limit) + + result = self.executeZSQL(query) + for res in result: + members.append(MPIWGStaffMember(self, dbresult=res)) + + return members + + def sortPriority(self,list): def sort(x,y): try: @@ -1128,6 +181,7 @@ return tmp + def getPublicationsFromPubman(self,coneId="renn",limit=None,publicationType=None): logging.debug("coneID:%s"%coneId) @@ -1175,9 +229,9 @@ def __init__(self, folder, dbresult): - """constructor: takes parent MPIWGStaffFolder and content""" + """constructor: takes parent MPIWGStaffFolder and content (DB row)""" self.folder = folder - self.content = dbresult[0] + self.content = dbresult def isValid(self): """returns if this member exists""" @@ -1196,9 +250,11 @@ id = re.sub('@mpiwg-berlin\.mpg\.de', '', self.content.e_mail) return id + getId = getUsername + def getConeId(self): """return cone ID""" - results= self.folder.executeZSQL("SELECT coneid FROM keys WHERE key_main = %s",[self.content.key]) + results= self.folder.executeZSQL("SELECT coneid FROM keys WHERE key_main = %s",[self.content.key]) for res in results: return res.coneid return None @@ -1244,36 +300,18 @@ else: return "NOT FOUND" + + getUrl = MPIWGHelper.getUrl - def getProfile(self,REQUEST): - """get the profile""" - self.REQUEST.RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT') - - - html="""<html><body>%s</body></html>""" - if self.content.profile and self.content.profile != "": - - return html%self.content.profile - else: - - return html%"" - - - - - def getTalks(self): - return self.folder.executeZSQL("SELECT oid,* FROM talks WHERE key_main = %s",[self.content.key]) #return self.folder.ZSQLInlineSearch(_table='talks',key_main=self.content.key) def getTeaching(self): - return self.folder.executeZSQL("SELECT oid,* FROM teaching WHERE key_main = %s",[self.content.key]) - def getLastUpdateCV(self): """getDate of Last Update""" try: @@ -1283,6 +321,7 @@ return ob.bobobase_modification_time() except: return "No file yet!" + def getLastUpdatePublications(self): """getDate of Last Update""" @@ -1294,7 +333,6 @@ def downloadCV(self,REQUEST): - fname="%s_cv.pdf"%self.getUsername().encode('utf-8') logging.debug(fname) ob=self.folder._getOb("downloadableFiles")._getOb(fname) @@ -1433,7 +471,7 @@ return pt() - security.declareProtected('View management screens','editDownloads') + security.declareProtected('View management screens','editDownloads') def editDownloads(self,REQUEST): """editiere die Downloads von der Webseite""" @@ -1748,6 +786,20 @@ return self.executeZSQL(query,[self.getKey()]) + def getProfile(self,REQUEST): + """get the profile""" + self.REQUEST.RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT') + + + html="""<html><body>%s</body></html>""" + if self.content.profile and self.content.profile != "": + + return html%self.content.profile + else: + + return html%"" + + def generateProfileForPerson(self,REQUEST=None): """erzeugt ein automatisches Profil aus den alten Eintraegen CV, Current work, und research interests"""
--- a/MPIWGStaff_old.py Tue May 14 10:36:48 2013 +0200 +++ b/MPIWGStaff_old.py Tue May 14 17:24:30 2013 +0200 @@ -27,7 +27,9 @@ from OFS.Cache import Cacheable import urllib2 import transaction -import SrvTxtUtils + +from SrvTxtUtils import getHttpData, getAt, getInt, unicodify, utf8ify +import bibliography from MPIWGHelper import * #ersetzt logging @@ -76,6 +78,8 @@ # self.ZSQLQuery(queryStr) return True,msg + + class MPIWGStaff(CatalogAware,ZSQLExtendFolder,Cacheable): """Staff""" @@ -85,6 +89,30 @@ #_v_cone=None; security=ClassSecurityInfo() + manage_options = Folder.manage_options+( + {'label':'Edit','action':'changeMPIWGStaffForm'}, + {'label':'Change Publications Special','action':'changePublications_specialForm'}, + ) + Cacheable.manage_options + + __manager_id = "ramCache" + def __init__(self,id, lastName,firstName,key): + """init""" + self.id=id + self.title=key + self.lastName=lastName + self.firstName=firstName + self.key=key + + # compat TODO: remove this + def getat(self, array, idx, default=None): + """returns always an int (0 in case of problems)""" + return getAt(array, idx, default) + + # compat TODO: remove this + def decode(self, s): + """TODO: remove this""" + return unicodify(s) + def redirect(self,RESPONSE,url): """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen""" @@ -312,20 +340,6 @@ """Return cataloguable key for ourselves.""" return str(self) - manage_options = Folder.manage_options+( - {'label':'Edit','action':'changeMPIWGStaffForm'}, - {'label':'Change Publications Special','action':'changePublications_specialForm'}, - ) + Cacheable.manage_options - - __manager_id = "ramCache" - def __init__(self,id, lastName,firstName,key): - """init""" - self.id=id - self.title=key - self.lastName=lastName - self.firstName=firstName - self.key=key - def getPersonID(self): """gibt den ID fuer die Person zurueck" im Moment ist personID = id, i.e. e-mail @@ -633,7 +647,7 @@ def getProfile(self): """get the profile""" - self.REQUEST.RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT') + self.REQUEST.RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT') founds=self.ZSQLInlineSearchU(_table='personal_www',key=self.getKeyUTF8()) html="""<html><body>%s</body></html>""" @@ -909,18 +923,6 @@ # TODO: remove all occurences of getDBId and replaces it by getKey return self.getKey() -# search=self.ZSQLInlineSearch(_table='personal_www',key=self.getKey(),publish_the_data='yes') -# if search:#name existiert und published, dann nimm diesen falls es mehrereeventuell nich publizierte datensaetze gibt. -# return search[0].id -# else:#nicht publiziert dann nimm einen davon -# search2=self.ZSQLInlineSearch(_table='personal_www',username=self.getId()) -# if search2: -# return search2[0].id -# else: -# return None - - - formatBiblHelp=bibliography.formatBiblHelp def sortBibliography(self,list,sortingMode=None,max=None): @@ -997,8 +999,9 @@ self._setObject(id,newObj) - if RESPONSE is not None: self.redirect(RESPONSE,'manage_main') + +
--- a/css/mpiwg.css Tue May 14 10:36:48 2013 +0200 +++ b/css/mpiwg.css Tue May 14 17:24:30 2013 +0200 @@ -42,29 +42,22 @@ padding-left: 15px; } -a.pdf { - background: url(../images/pdf.gif) no-repeat; - padding-left: 15px; - /* padding-top:1px; */ -} - -a.audio { - background: url(../images/audio.png) center left no-repeat; - padding-left: 15px; -} - a.down { background: url(../images/down.png) center left no-repeat; padding-left: 15px; } -a.book { - background: url(../images/book.gif) no-repeat; - padding-left: 20px; - margin-left: -5px; - margin-top: -1px; +a.jumptop { + background: url(../images/jump_top.png) center left no-repeat; + padding-left: 15px; } +a.email { + background: url(../images/email.png) center left no-repeat; + padding-left: 23px; +} + +/* old blue mail link */ a.maillink { color: #3b4186 !important; } @@ -346,6 +339,12 @@ padding-left: 20px; } +div.main div.center { + /* make sure center does not collapse */ + min-width: 460px; +} + + /* * frontpage */ @@ -651,7 +650,8 @@ position: relative; } -div.box h2 { +div.box h2, +h2.line { /* h2 is title with line */ padding-bottom: 5px; border-bottom: 3px solid #dccbae; @@ -1035,6 +1035,7 @@ font-weight: bold; margin: 0; } + /* * sidebar */ @@ -1047,6 +1048,7 @@ } div.sideblock h2 { + position: relative; font-size: 12px; margin-top: 20px; padding-bottom: 5px; @@ -1074,9 +1076,6 @@ /* * project sidebars */ -div.sideblock h2 { - position: relative; -} div.sideblock h2 .proj_state { position: absolute; right: 0;
--- a/zpt/staff/member_index_html.zpt Tue May 14 10:36:48 2013 +0200 +++ b/zpt/staff/member_index_html.zpt Tue May 14 17:24:30 2013 +0200 @@ -34,8 +34,8 @@ </div> <!-- profile --> <div> - <tal:x tal:condition="python:not content.profile"> - <tal:y tal:replace="structure python:member.generateProfileForPerson()" /> + <tal:x tal:condition="not:content/profile"> + <tal:y tal:replace="structure member/generateProfileForPerson" /> </tal:x> <tal:x tal:condition="content/profile"> <h2>Profile</h2> @@ -43,32 +43,24 @@ </tal:x> </div> <!-- publications --> - <tal:block tal:define="publications python:here.ZDBInlineSearch(_table='publications',key_main=key,_op_key_main='eq',publish='yes')" + <tal:block + tal:define="publications python:here.ZDBInlineSearch(_table='publications',key_main=key,_op_key_main='eq',publish='yes',_op_publish='eq')" tal:condition="publications"> <h2>Selected publications</h2> - <!--<p tal:repeat="publication python:member.sortBibliography(publications,content.publications_sort,max=5)"> - <a tal:omit-tag="not:publication/link" tal:attributes="href publication/link" - tal:content="structure python:here.formatBibliography(here,publication)" /> - </p> - <p tal:condition="python:len(publications)>5"> - <a class="internal" tal:attributes="href string:$baseUrl/publications_full">more</a> - </p>--> - <p tal:repeat="publication python:member.getPublicationsFromPubman(limit=5)"> <a tal:attributes="href python:'http://pubman.mpiwg-berlin.mpg.de/pubman/faces/viewItemFullPage.jsp?itemId='+publication[0]" tal:content="structure python:publication[1]" /> </p> <p tal:condition="python:len(publications)>5"> - <a class="internal" tal:attributes="href string:$baseUrl/publicationsFull">more</a> + <a class="internal" tal:attributes="href string:$baseUrl/publicationsFull">More</a> </p> <p> - <a target="_blank" - tal:attributes="href python:member.getConeId()"> - See all publications (pubman)</a> - </p> + <a class="external" target="_blank" tal:attributes="href member/getConeId">See all publications (PubMan)</a> + </p> </tal:block> <!-- Talks --> - <tal:block tal:define="talks python:here.ZDBInlineSearch(_table='talks',key_main=key,_op_key_main='eq',_sort='priority',published='yes')" + <tal:block + tal:define="talks python:here.ZDBInlineSearch(_table='talks',key_main=key,_op_key_main='eq',_sort='priority',published='yes')" tal:condition="talks"> <h2>Talks and presentations</h2> <div class="namelist"> @@ -84,7 +76,7 @@ </tal:block> </div> <p tal:condition="python:len(talks)>5"> - <a tal:attributes="href string:$baseUrl/talks_full">more</a> + <a class="internal" tal:attributes="href string:$baseUrl/talks_full">More</a> </p> </tal:block> <!-- Teaching activities --> @@ -104,7 +96,7 @@ </div> </tal:block> <p tal:condition="python:len(teachings)>5"> - <a tal:attributes="href string:$baseUrl/teaching_full">more</a> + <a class="internal" tal:attributes="href string:$baseUrl/teaching_full">More</a> </p> </div> </tal:block> @@ -117,37 +109,30 @@ <div class="sideblock"> <h2>Contact</h2> <div class="item noline"> - Max Planck Institute for the History of Science - <br /> - Boltzmannstraße 22 - <br /> - 14195 Berlin - <br /> - Germany + Max Planck Institute for the History of Science <br /> Boltzmannstraße 22 <br /> 14195 Berlin <br /> Germany </div> <div class="item" tal:condition="python:content.telefon_p=='yes'"> - tel.:<span tal:content="content/telefon">[FMP-Field: telefon]</span> - <br /> + tel.: <span tal:content="content/telefon">[FMP-Field: telefon]</span> <br /> </div> <div class="item" tal:condition="python:content.fax_p=='yes'"> - fax:<span tal:content="content/fax">[FMP-Field: fax]</span> - <br /> + fax: <span tal:content="content/fax">[FMP-Field: fax]</span> <br /> </div> - <div class="item internal" tal:condition="python:content.e_mail_p=='yes'"> - <a class="maillink" tal:attributes="href string:mailto:${content/e_mail}" tal:content="content/e_mail">[FMP-Field: + <div class="item" tal:condition="python:content.e_mail_p=='yes'"> + <a class="email" tal:attributes="href string:mailto:${content/e_mail}" tal:content="content/e_mail">[FMP-Field: e_mail]</a> </div> - <div class="item external" tal:condition="python:content.e_mail2_p=='yes'"> - <a class="maillink" tal:attributes="href string:mailto:${content/e_mail2}" tal:content="content/e_mail2">[FMP-Field: + <div class="item" tal:condition="python:content.e_mail2_p=='yes'"> + <a class="email" tal:attributes="href string:mailto:${content/e_mail2}" tal:content="content/e_mail2">[FMP-Field: e_mail2]</a> (external) </div> </div> - <div class="sideblock" tal:define="projects python:here.getProjectFolder().getProjectsOfMember(key=key)" tal:condition="projects"> + <div class="sideblock" tal:define="projects python:here.getProjectFolder().getProjectsOfMember(key=key)" + tal:condition="projects"> <h2>Projects</h2> <div class="project" tal:repeat="project projects"> <a tal:attributes="href python:project.getUrl(baseUrl=root+'/'+secmap['research']+'/projects/')" - tal:content="project/getLabel" /> + tal:content="project/getLabel" /> </div> </div> @@ -157,15 +142,12 @@ <a target="_blank" href="downloadCV">Download Curriculum Vitae</a> </div> <div class="item download" tal:condition="python:getattr(here,'publications_publish','no')=='yes'"> - <a target="_blank" href="downloadPublications">Download Publication List</a> - <br /> + <a target="_blank" href="downloadPublications">Download Publication List</a> <br /> </div> - <div class="item internal"> - <a target="_blank" - tal:attributes="href python:member.getConeId()"> - See publications on pubman</a> + <div class="item external"> + <a target="_blank" tal:attributes="href python:member.getConeId()"> See publications on PubMan</a> </div> - <div class="item internal" + <div class="item external" tal:repeat="addLink python:here.ZDBInlineSearch(_table='additionallink',key_main=key,_op_key_main='eq',_sort='priority',published='yes')"> <a target="_blank" tal:content="addLink/title" tal:attributes="href addLink/link"> Daston on the History of Science (listen to CBC-Interview, Fall 2007)</a>
--- a/zpt/www/common_template.zpt Tue May 14 10:36:48 2013 +0200 +++ b/zpt/www/common_template.zpt Tue May 14 17:24:30 2013 +0200 @@ -55,5 +55,31 @@ </div> <!-- feature --> + + <!-- short person entry --> + <tr class="line" metal:define-macro="staff_member_row"> + <td> + <a tal:attributes="href python:member.getUrl(baseUrl=memBaseUrl)"> + <span tal:replace="member/content/first_name" /> + <b><span tal:replace="member/content/last_name" /></b> + </a> + <tal:block metal:define-slot="name_more"/> + </td> + <td><span tal:replace="python:here.replaceNotEmpty('%s ',member.content.titles_new)" /> (<span + tal:replace="python:here.replaceNotEmpty('%s, ',member.content.status)" /> <span + tal:replace="python:here.replaceNotEmpty('%s',member.content.date_stay_at_mpiwg)" /><span + tal:replace="python:here.replaceNotEmpty(', funded by the %s',member.content.funded_by)" />)<tal:x + condition="python:member.content.current_work_p=='yes'"> + <i tal:content="python:here.replaceNotEmpty(': %s',member.content.current_work)" /> + </tal:x> <tal:block tal:condition="python:member.content.e_mail_p=='yes'"> + <br /> + <a class="email" tal:attributes="href python:'mailto:'+member.content.e_mail" tal:content="member/content/e_mail">[FMP-field: + e_mail]</a> + </tal:block></td> + </tr> + <!-- /short person entry --> + + + </body> </html>