# -*- coding: utf-8 -*- ## ## ## This file is part of CDS Indico. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN. ## ## CDS Indico is free software; you can redistribute it and/or ## modify it under the terms of the GNU General Public License as ## published by the FreeSoftware Foundation; either version 2 of the ## License, or (at your option) any later version. ## ## CDS Indico is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with CDS Indico; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. # fossil classes from MaKaC.plugins.base import PluginsHolder from MaKaC.common.utils import formatDateTime from MaKaC.fossils.subcontribution import ISubContribParticipationFossil,\ ISubContributionFossil, ISubContributionWithSpeakersFossil from MaKaC.fossils.contribution import IContributionParticipationFossil,\ IContributionFossil, IContributionWithSpeakersFossil, IContributionParticipationMinimalFossil, \ IContributionWithSubContribsFossil,\ IContributionParticipationTTDisplayFossil, \ IContributionParticipationTTMgmtFossil from MaKaC.fossils.conference import IConferenceMinimalFossil, \ IConferenceEventInfoFossil, IConferenceFossil,\ ISessionFossil, ISessionSlotFossil, IMaterialMinimalFossil,\ IMaterialFossil, IConferenceParticipationFossil,\ IResourceMinimalFossil, ILinkMinimalFossil, ILocalFileMinimalFossil,\ IResourceFossil, ILinkFossil, ILocalFileFossil,\ ILocalFileExtendedFossil, IConferenceParticipationMinimalFossil,\ ICategoryFossil from MaKaC.common.fossilize import fossilizes, Fossilizable import re, os import tempfile import copy import stat from datetime import datetime, timedelta, time from MaKaC.contributionReviewing import ReviewManager from reviewing import ConferenceReview as ConferenceReview from pytz import timezone from pytz import all_timezones from persistent import Persistent from BTrees.OOBTree import OOBTree from BTrees.OIBTree import OIBTree,OISet,union import MaKaC import MaKaC.common.indexes as indexes from MaKaC.common.timezoneUtils import nowutc, maxDatetime import MaKaC.fileRepository as fileRepository from MaKaC.schedule import ConferenceSchedule, SessionSchedule,SlotSchedule,\ PosterSlotSchedule, SlotSchTypeFactory, ContribSchEntry, \ LinkedTimeSchEntry, BreakTimeSchEntry import MaKaC.review as review from MaKaC.common import Config, DBMgr, utils from MaKaC.common.Counter import Counter from MaKaC.common.ObjectHolders import ObjectHolder from MaKaC.common.Locators import Locator from MaKaC.accessControl import AccessController, AdminList from MaKaC.common.timerExec import HelperTaskList, Alarm from MaKaC.errors import MaKaCError, TimingError, ParentTimingError, EntryTimingError from MaKaC import registration,epayment from MaKaC.evaluation import Evaluation from MaKaC.trashCan import TrashCanManager from MaKaC.user import AvatarHolder from MaKaC.common import pendingQueues from MaKaC.common.info import HelperMaKaCInfo from MaKaC.participant import Participation from MaKaC.common.log import LogHandler import MaKaC.task as task import MaKaC.common.info as info from MaKaC.badge import BadgeTemplateManager from MaKaC.poster import PosterTemplateManager from MaKaC.common.cache import CategoryCache, EventCache from MaKaC.common import mail from MaKaC.common.utils import getHierarchicalId from MaKaC.i18n import _ from MaKaC.common.PickleJar import Updates from MaKaC.common.PickleJar import if_else from MaKaC.webinterface import urlHandlers from MaKaC.common.logger import Logger from MaKaC.common.contextManager import ContextManager from sets import Set class CommonObjectBase(object): """This class is for holding commonly used methods that are used by several classes. It is inherited by the following classes: Category Conference Session Contribution Subcontribution Material Resource """ def getRecursiveAllowedToAccessList(self): """Returns a set of Avatar resp. CERNGroup objects for those people resp. e-groups allowed to access this category as well as all parent objects. """ # Initialize set of avatars/groups: this will hold those people/groups explicitly # allowed to access this object av_set = set() # Get the AccessProtectionLevel for this apl = self.getAccessProtectionLevel() # If this category is "absolutely public", then return an empty set if apl == -1: pass # If this category is protected "all by itself", then get the list of # people/groups allowed to access it, and ignore all owners' permissions. elif apl == 1: al = self.getAllowedToAccessList() if al is not None: for av in al: av_set.add(av) # If access settings are inherited from its owners, look at those. elif apl == 0: # If event is protected, then get list of people/groups allowed to access, # and add that to the set of avatars. # NOTE: I'm not sure this ever happens, i.e. an event having protection # level 0 and also having its own access list, but it doesn't hurt anything # to leave this in for now. al = self.getAllowedToAccessList() if al is not None: for av in al: av_set.add(av) # Add list of avatars/groups allowed to access parents objects. owner = self.getOwner() if owner is not None: owner_al = owner.getRecursiveAllowedToAccessList() if owner_al is not None: for av in owner_al: av_set.add(av) # return set containing whatever avatars/groups we may have collected return av_set class CategoryManager( ObjectHolder ): idxName = "categories" counterName = "CATEGORY" def add(self, category): ObjectHolder.add(self, category) # Add category to the name index nameIdx = indexes.IndexesHolder().getIndex('categoryName') nameIdx.index(category.getId(), category.getTitle().decode('utf-8')) def remove(self, category): ObjectHolder.remove(self, category) # remove category from the name index nameIdx = indexes.IndexesHolder().getIndex('categoryName') nameIdx.unindex(category.getId()) def _newId( self ): """ returns a new id for the category the id must not already exist in the collection """ id = ObjectHolder._newId( self ) while self.hasKey(id): id = ObjectHolder._newId( self ) return id def getRoot( self ): root = DBMgr.getInstance().getDBConnection().root() if not root.has_key("rootCategory"): r = Category() r.setName( _("Home")) self.add( r ) root["rootCategory"] = r return root["rootCategory"] def getDefaultConference( self ): dconf = HelperMaKaCInfo.getMaKaCInfoInstance().getDefaultConference() if dconf == None: return HelperMaKaCInfo.getMaKaCInfoInstance().setDefaultConference(DefaultConference()) else: return dconf class Category(Persistent, CommonObjectBase, Fossilizable): fossilizes(ICategoryFossil) def __init__( self ): self.id = "" self.name = "" self.description = "" self.subcategories = {} self.materials = {} self.conferences = {} self._numConferences = 0 self.owner = None self._defaultStyle = { "simple_event":"","meeting":"" } self._order = 0 self.__ac = AccessController() self.__confCreationRestricted = 1 self.__confCreators = [] self._visibility = 999 self._statistics = {"events":None,"contributions":None,"resources":None,\ "updated":None} self._icon=None self.materials = {} #self._materials = {} #self.material ={} self._tasksAllowed = False self._tasks = {} self._taskIdGenerator = 0 self._tasksPublic = True self._tasksCommentPublic = True self._tasksManagers = [] self._tasksCommentators = [] self._taskAccessList = [] self._timezone = "" self.__materialGenerator = Counter() self._notifyCreationList = "" def getAccessController(self): return self.__ac def updateFullyPublic( self ): pass def getNotifyCreationList( self ): """ self._notifyCreationList is a string containing the list of email addresses to send an email to when a new event is created""" try: return self._notifyCreationList except: self._notifyCreationList = "" return self._notifyCreationList def setNotifyCreationList( self, value ): self._notifyCreationList = value def getUniqueId( self ): return "cat%s" % self.getId() def setPaper( self, newPaper ): if self.getPaper() != None: raise MaKaCError( _("The paper for this conference has already been set"), _("Conference")) self.paper=newPaper self.paper.setOwner( self ) self.notifyModification() def cleanCache( self ): """ delete cache files of this category and its fathers usually used when an object in the category has changed """ minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance() if minfo.isCacheActive(): for id in self.getCategoryPath(): cache = CategoryCache({"categId":id}) cache.cleanCache() def clearCache( self ): """ delete cache file of this category. usually used for admin purposes """ cache = CategoryCache({"categId":self.getId()}) cache.cleanCache() def clearConferenceCaches( self ): """ delete cache files of all conferences in the category usually used for admin purposes """ for conf in self.getConferenceList(): conf.cleanCache() def removePaper( self ): if self.paper is None: return self.paper.delete() self.paper.setOwner(None) self.paper = None self.notifyModification() def recoverPaper(self, p): self.setPaper(p) p.recover() def getPaper( self ): try: if self.paper: pass except AttributeError: self.paper = None return self.paper def setSlides( self, newSlides ): if self.getSlides() != None: raise MaKaCError( _("The slides for this conference have already been set"), _("Conference")) self.slides=newSlides self.slides.setOwner( self ) self.notifyModification() def removeSlides( self ): if self.slides is None: return self.slides.delete() self.slides.setOwner( None ) self.slides= None self.notifyModification() def recoverSlides(self, s): self.setSlides(s) s.recover() def getSlides( self ): try: if self.slides: pass except AttributeError: self.slides = None return self.slides def setVideo( self, newVideo ): if self.getVideo() != None: raise MaKaCError( _("The video for this conference has already been set"), _("Conference")) self.video=newVideo self.video.setOwner( self ) self.notifyModification() def removeVideo( self ): if self.getVideo() is None: return self.video.delete() self.video.setOwner(None) self.video = None self.notifyModification() def recoverVideo(self, v): self.setVideo(v) v.recover() def getVideo( self ): try: if self.video: pass except AttributeError: self.video = None return self.video def setPoster( self, newPoster ): if self.getPoster() != None: raise MaKaCError( _("the poster for this conference has already been set"), _("Conference")) self.poster=newPoster self.poster.setOwner( self ) self.notifyModification() def removePoster( self ): if self.getPoster() is None: return self.poster.delete() self.poster.setOwner(None) self.poster = None self.notifyModification() def recoverPoster(self, p): self.setPoster(p) p.recover() def getPoster( self ): try: if self.poster: pass except AttributeError: self.poster = None return self.poster def setMinutes( self, newMinutes ): if self.getMinutes() != None: raise MaKaCError( _("The Minutes for this conference has already been set")) self.minutes=newMinutes self.minutes.setOwner( self ) self.notifyModification() def createMinutes( self ): if self.getMinutes() != None: raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference")) self.minutes = Minutes() self.minutes.setOwner( self ) self.notifyModification() return self.minutes def removeMinutes( self ): if self.getMinutes() is None: return self.minutes.delete() self.minutes.setOwner( None ) self.minutes = None self.notifyModification() def recoverMinutes(self, min): self.removeMinutes() # To ensure that the current minutes are put in # the trash can. self.minutes = min self.minutes.setOwner( self ) min.recover() self.notifyModification() return self.minutes def getMinutes( self ): #To be removed try: if self.minutes: pass except AttributeError, e: self.minutes = None return self.minutes def addMaterial( self, newMat ): try: newMat.setId( str(self.__materialGenerator.newCount()) ) except: self.__materialGenerator = Counter() newMat.setId(self.__materialGenerator.newCount() ) newMat.setOwner( self ) self.materials[ newMat.getId() ] = newMat self.notifyModification() def removeMaterial( self, mat ): if mat.getId() in self.materials.keys(): self.materials[mat.getId()].setOwner(None) del self.materials[ mat.getId() ] mat.delete() self.notifyModification() return "done: %s"%mat.getId() elif mat.getId().lower() == 'minutes': self.removeMinutes() return "done: %s"%mat.getId() elif mat.getId().lower() == 'paper': self.removePaper() return "done: %s"%mat.getId() elif mat.getId().lower() == 'slides': self.removeSlides() return "done: %s"%mat.getId() elif mat.getId().lower() == 'video': self.removeVideo() return "done: %s"%mat.getId() elif mat.getId().lower() == 'poster': self.removePoster() return "done: %s"%mat.getId() return "not done: %s"%mat.getId() def recoverMaterial(self, recMat): # Id must already be set in recMat. recMat.setOwner( self ) self.materials[ recMat.getId() ] = recMat recMat.recover() self.notifyModification() def getMaterialRegistry(self): """ Return the correct material registry for this type """ from MaKaC.webinterface.materialFactories import CategoryMFRegistry return CategoryMFRegistry def getMaterialById( self, matId ): if matId.lower() == 'paper': return self.getPaper() elif matId.lower() == 'slides': return self.getSlides() elif matId.lower() == 'video': return self.getVideo() elif matId.lower() == 'poster': return self.getPoster() elif matId.lower() == 'minutes': return self.getMinutes() elif self.materials.has_key(matId): return self.materials[ matId ] return None def getMaterialList( self ): try: return self.materials.values() except: self.materials={} return self.materials.values() def getAllMaterialList( self ): l = self.getMaterialList() if self.getPaper(): l.append( self.getPaper() ) if self.getSlides(): l.append( self.getSlides() ) if self.getVideo(): l.append( self.getVideo() ) if self.getPoster(): l.append( self.getPoster() ) if self.getMinutes(): l.append( self.getMinutes() ) return l def getTaskList(self): try : return self._tasks.values() except : self._tasks = {} return self._tasks.values() def getTitle(self): return self.name def getTasks(self): try : return self._tasks except : self._tasks = {} return self._tasks def getTask(self, taskId): return self.getTasks().get(taskId,None) def _getTasksAllowed(self): try : return self._tasksAllowed except : self._tasksAllowed = False return self._tasksAllowed def tasksAllowed(self): if self.hasSubcategories(): return False return self._getTasksAllowed() def setTasksAllowed(self): if self.hasSubcategories() : return False self._getTasksAllowed() self._tasksAllowed = True self.notifyModification() return True def setTasksForbidden(self): if len(self.getTaskList()) > 0 : return False self._getTasksAllowed() self._tasksAllowed = False self.notifyModification() return False def _getNewTaskId(self): try : if self._taskIdGenerator : pass except : self._taskIdGenerator = 0 self._taskIdGenerator = self._taskIdGenerator + 1 return self._taskIdGenerator def newTask(self, user): if user is None : return None newTask = task.Task(self, self._getNewTaskId(), user) self.getTasks()["%s"%newTask.getId()] = newTask self.notifyModification() return newTask def tasksPublic(self): try : return self._tasksPublic except : self._tasksPublic = True return self._tasksPublic def setTasksPublic(self): self.tasksPublic() self._tasksPublic = True def setTasksPrivate(self): self.tasksPublic() self._tasksPublic = False def tasksCommentPublic(self): try : return self._tasksCommentPublic except : self._tasksCommentPublic = True return self._tasksCommentPublic def setTasksCommentPublic(self): self.tasksCommentPublic() self._tasksCommentPublic = True def setTasksCommentPrivate(self): self.tasksCommentPublic() self._tasksCommentPublic = False def getTasksManagerList(self): try : return self._tasksManagers except : self._tasksManagers = [] self._p_changed = 1 return self._tasksManagers def getTasksManager(self, index): length = len(self.getTasksManagerList()) if index < 0 or index >= length : return None return self._tasksManagers[index] def addTasksManager(self,user): if user is None : return False self.getTasksManagerList().append(user) self._p_changed = 1 return True def removeTasksManager(self, index): length = len(self.getTasksManagerList()) if index < 0 or index >= length : return False del self.getTasksManagerList()[index] self._p_changed = 1 return True def getTasksCommentatorList(self): try : return self._tasksCommentators except : self._tasksCommentators = [] self._p_changed = 1 return self._tasksCommentators def getTasksCommentator(self, index): length = len(self.getTasksCommentatorList()) if index < 0 or index >= length : return None return self._tasksCommentators[index] def addTasksCommentator(self,user): if user is None : return False self.getTasksCommentatorList().append(user) self._p_changed = 1 return True def removeTasksCommentator(self, index): length = len(self.getTasksCommentatorList()) if index < 0 or index >= length : return False del self._tasksCommentators[index] self._p_changed = 1 return True def getTasksAccessList(self): try : return self._tasksAccessList except : self._tasksAccessList = [] self._p_changed = 1 return self._tasksAccessList def getTasksAccessPerson(self, index): length = len(self.getTasksAccessList()) if index < 0 or index >= length : return None return self._tasksAccessList[index] def addTasksAccessPerson(self,user): if user is None : return False self.getTasksAccessList().append(user) self._p_changed = 1 return True def removeTasksAccessPerson(self, index): length = len(self.getTasksAccessList()) if index < 0 or index >= length : return False del self.getTasksAccessList()[index] self._p_changed = 1 return True def hasSubcategories(self): return len(self.subcategories.values()) > 0 def getVisibility ( self ): # TODO: Check if this actually works # since getOwner() can be None (root categ) try: return max(0,min(int(self._visibility), self.getOwner().getVisibility()+1)) except: self._visibility = 999 return 999 def setVisibility( self, visibility=999 ): self._visibility = int(visibility) self._reindex() def _reindex( self ): catIdx = indexes.IndexesHolder().getIndex('category') catIdx.reindexCateg(self) def isRoot( self ): #to be improved return self.owner == None def notifyOAIModification(self): for conf in self.getAllConferenceList(): conf.notifyOAIModification(updateChildren=True) def getDefaultStyle( self, type ): try: return self._defaultStyle[type] except: return "" def setDefaultStyle( self, type, style, subcatsStyle=False ): try: self._defaultStyle[type] = style except: self._defaultStyle = { "simple_event":"","meeting":"" } self._defaultStyle[type] = style self.notifyModification() #raise str(subcatsStyle) if subcatsStyle: categ=self.getSubCategoryList() for cat in categ: cat.setDefaultStyle(type, style, subcatsStyle ) ################################## # Fermi timezone awareness # ################################## def getTimezone(self): try: if self._timezone not in all_timezones: self.setTimezone('UTC') return self._timezone except: self.setTimezone('UTC') return 'UTC' def setTimezone(self,tz): self._timezone = tz def changeConfTimezones(self, tz): for conference in self.getConferenceList(): conference.moveToTimezone(tz) ################################## # Fermi timezone awareness(end) # ################################## def getOrder( self ): try: return self._order except: self._order = 0 return 0 def setOrder( self, order ): self._order = order def getId( self ): return self.id def setId( self, newId ): self.id = str( newId.strip() ) def getLocator( self ): """Gives back (Locator) a globaly unique identification encapsulated in a Locator object for the category instance """ d = Locator() d["categId"] = self.getId() return d def getCategory(self): return self def getOwner( self ): return self.owner def setOwner( self, newOwner ): if self.getOwner() != None and newOwner != None and self.getOwner() != newOwner: self.move( newOwner ) else: self.owner = newOwner def getCategoryPath(self): if self.isRoot(): return [self.getId()] else: l = self.getOwner().getCategoryPath() l.append(self.getId()) return l def getCategoryPathTitles(self): # Breadcrumbs breadcrumbs = [] cat = self while cat: breadcrumbs.insert(0, cat.getTitle()) cat = cat.getOwner() return breadcrumbs def delete( self, deleteConferences=0 ): """removes completely a category (and all its sub-items) from the system""" if self.isRoot(): raise MaKaCError( _("Root category cannot be deleted"), _("Category")) if not deleteConferences: if self.getNumConferences()>0: raise MaKaCError( _("This category still contains some conferences, please remove them first"), _("Category")) self.cleanCache() for subcateg in self.getSubCategoryList(): subcateg.delete( deleteConferences ) for conference in self.getConferenceList(): self.removeConference( conference, delete = True ) self.getOwner()._removeSubCategory( self ) CategoryManager().remove( self ) TrashCanManager().add(self) return def move( self, newCategory ): ow = self.getOwner() catDateIdx = indexes.IndexesHolder().getIndex('categoryDate') catDateIdx.unindexCateg(self) self.getOwner()._removeSubCategory( self ) newCategory._addSubCategory( self ) self._reindex() catDateIdx.indexCateg(self) self.notifyOAIModification() def getName( self ): return self.name def setName( self, newName ): self.name = newName.strip() # Reindex when name changes nameIdx = indexes.IndexesHolder().getIndex('categoryName') nameIdx.unindex(self.getId()) nameIdx.index(self.getId(), self.getTitle().decode('utf-8')) self.cleanCache() def getDescription( self ): return self.description def setDescription( self, newDesc ): self.description = newDesc.strip() self.cleanCache() def _addSubCategory( self, newSc ): #categories can only contain either conferences either other categories # but can never contain both. For the moment an exception is raised # but this could be replaced by the following policy: if a # sub-category is to be added to a category already containing # conferences then the conferes are moved into the new sub-category # and it is added to target category. #first, check that the category is registered if not raise an exception if len(self.conferences)>0: for conf in self.getConferenceList(): self.removeConference( conf ) newSc._addConference( conf ) if len(self.conferences)>0: raise MaKaCError( _("Cannot add subcategory: the current category already contains events"), _("Category")) newSc.setOwner( self ) self.subcategories[ newSc.getId() ] = newSc self._incNumConfs(newSc.getNumConferences()) self.cleanCache() newSc.updateFatherProtection() def _removeSubCategory( self, sc ): """if the given subcategory belongs to the current category it removes it from the subcategories list (don't use this method, use delete instead) """ if sc in self.getSubCategoryList(): self._decNumConfs(sc.getNumConferences()) del self.subcategories[ sc.getId() ] sc.setOwner( None ) self.cleanCache() def newSubCategory( self, sc=None ): cm = CategoryManager() if sc==None: sc = Category() cm.add( sc ) self._addSubCategory( sc ) self.cleanCache() return sc def _incNumConfs(self, num=1): """Increases the number of conferences for the current category in a given number. WARNING: Only Categories must use this method!!!""" self._numConferences = self.getNumConferences() self._numConferences+=num if self.getOwner() is not None: self.getOwner()._incNumConfs(num) def _decNumConfs(self, num=1): """Decreases the number of conferences for the current category in a given number. WARNING: Only Categories must use this method!!!""" self._numConferences = self.getNumConferences() self._numConferences-=num if self.getOwner() is not None: self.getOwner()._decNumConfs(num) def _addConference( self, newConf ): if len(self.subcategories)>0: raise MaKaCError( _("Cannot add event: the current category already contains some sub-categories"), _("Category")) if newConf.getId() == "": raise MaKaCError( _("Cannot add to a category an event which is not registered"), _("Category")) self.conferences[ newConf.getId() ] = newConf newConf.addOwner(self) self._incNumConfs(1) self.indexConf(newConf) self.cleanCache() newConf.updateFatherProtection() newConf.notifyOAIModification(updateChildren=True) def getAccessKey(self): return "" def indexConf( self, conf ): calIdx = indexes.IndexesHolder().getIndex('calendar') calIdx.indexConf(conf) catIdx = indexes.IndexesHolder().getIndex('category') catIdx.indexConf(conf) catDateIdx = indexes.IndexesHolder().getIndex('categoryDate') catDateIdx.indexConf(conf) def unindexConf( self, conf ): calIdx = indexes.IndexesHolder().getIndex('calendar') calIdx.unindexConf(conf) catIdx = indexes.IndexesHolder().getIndex('category') catIdx.unindexConf(conf) catDateIdx = indexes.IndexesHolder().getIndex('categoryDate') catDateIdx.unindexConf(conf) def newConference( self, creator, id="", creationDate=None, modificationDate=None ): conf = Conference( creator, id, creationDate, modificationDate ) ConferenceHolder().add( conf ) self._addConference( conf ) return conf def removeConference( self, conf, notify=True, delete = False ): if not (conf in self.getConferenceList()): return self.unindexConf( conf ) del self.conferences[ conf.getId() ] if delete: conf.delete() conf.removeOwner( self, notify ) self._decNumConfs(1) if notify: conf.notifyOAIModification(updateChildren=True) self.cleanCache() def getSubCategoryList( self ): subcategs = self.subcategories.values() cl = [] for categ in subcategs: cl.append("%04s%s-%s" % (categ.getOrder(),categ.getName().replace("-",""),categ.getId())) cl.sort() res = [] for c in cl: id = c.split("-")[1] res.append(self.subcategories[id]) return res def getConferenceList( self, dateOrdered = False, sortType=1 ): """returns the list of conferences included in the current category. if dateOrdered (bool) is specified and it is True the returned list will be oredered by starting date. sortType=1--> By date sortType=2--> Alphabetically """ res = [] #ch = ConferenceHolder() #catIdx = indexes.IndexesHolder().getIndex("category") #resid = catIdx.getItems(int(self.getId())) #for id in resid: # res.append(ch.getById(id)) res = self.conferences.values() #TODO: this is not very efficient/elegant. to be improved if dateOrdered: if sortType==1: di = [] for conf in res: di.append("%s%02d%02d-%s"%(conf.getStartDate().year,conf.getStartDate().month,conf.getStartDate().day, conf.getId())) di.sort() res = [] for i in di: id = i.split("-")[1] res.append( self.conferences[id] ) elif sortType==2: res.sort(Conference._cmpTitle) elif sortType==3: di = [] for conf in res: di.append("%s%02d%02d-%s"%(conf.getStartDate().year,conf.getStartDate().month,conf.getStartDate().day, conf.getId())) di.sort() res = [] for i in di: id = i.split("-")[1] res.append( self.conferences[id] ) res.reverse() return res def getAllConferenceList(self): if self.getConferenceList(): return self.getConferenceList else: l = [] for cat in self.getSubCategoryList(): l[:0] = cat.getAllConferenceList() return l def getAllConferenceList( self ): """returns the list of all conferences included in the current category and in all its subcategories""" res = self.getConferenceList() subcategs = self.getSubCategoryList() if subcategs != []: for subcateg in subcategs: res.extend(subcateg.getAllConferenceList()) return res def getPreviousEvent(self, conf): cl=self.getConferenceList(True, 1) v=None try: i=cl.index(conf) if i>0: v=cl[i-1] except ValueError, e: pass return v def getNextEvent(self, conf): cl=self.getConferenceList(True, 1) v=None try: i=cl.index(conf) if i<(len(cl)-1): v=cl[i+1] except ValueError, e: pass return v def getFirstEvent(self, conf=None): cl=self.getConferenceList(True, 1) if len(cl)>0 and cl[0]!=conf: return cl[0] return None def getLastEvent(self, conf=None): cl=self.getConferenceList(True, 1) if len(cl)>0 and cl[-1]!=conf: return cl[-1] return None def getConferenceIdsList( self ): """returns the list of conferences Ids included in the current category. """ res = [] for conf in self.conferences.values(): res.append(conf.getId()) return res def getConferenceById(self, conferenceId): """ returns tle conference identified with id provided""" return self.conferences.get(conferenceId, None) def _setNumConferences(self): self._numConferences=0 if len(self.getSubCategoryList())>0: for sc in self.getSubCategoryList(): sc.getNumConferences() else: self._incNumConfs(len(self.getConferenceList())) def getNumConferences( self ): """returns the total number of conferences contained in the current category and all its sub-categories (if any)""" #this new approach will speed up considerably the counting of category # conferences. However, it will give non accurate results for # conferences within many categories (a conference will be counted # twice in parent categories). # Besides this approach will generate much more conflict errors. This # can be reduced by simply isolating the counter in a separate object. try: if self._numConferences: pass except AttributeError: self._setNumConferences() return self._numConferences def _getRepository( self ): dbRoot = DBMgr.getInstance().getDBConnection().root() try: fr = dbRoot["local_repositories"]["main"] except KeyError, e: fr = fileRepository.MaterialLocalRepository() dbRoot["local_repositories"] = OOBTree() dbRoot["local_repositories"]["main"] = fr return fr def removeResource( self, res ): pass def setIcon( self, iconFile ): iconFile.setOwner( self ) iconFile.setId( "icon" ) iconFile.archive( self._getRepository() ) iconFile.setProtection( -1 ) if self.getIcon() != None: self._icon.delete() self._icon = iconFile self.notifyModification() def getIcon( self ): try: if self._icon: pass except AttributeError, e: self._icon=None return self._icon def getIconURL( self ): if self.getIcon() is None: return "" return self._icon.getURL() def removeIcon(self): if self.getIcon() is None: return self._icon.delete() self._icon = None self.notifyModification() def recoverIcon(self, icon): icon.setOwner(self) if self.getIcon() != None: self._icon.delete() self._icon = icon icon.recover() self.notifyModification() def getManagerList( self ): return self.__ac.getModifierList() def grantModification( self, prin ): self.__ac.grantModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "manager") self.resetModifyCache() self.cleanCache() def revokeModification( self, prin ): self.__ac.revokeModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "manager") self.resetModifyCache() self.cleanCache() def canModify( self, aw ): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.canUserModify( aw.getUser() ) return self._v_canmodify[aw] def canUserModify( self, av ): try: return self._v_canusermodify[av] except AttributeError: self._v_canusermodify = {} except KeyError: pass inherited = 0 if self.getOwner() != None: inherited = self.getOwner().canUserModify( av ) self._v_canusermodify[av] = inherited or self.__ac.canModify( av ) return self._v_canusermodify[av] def getAllowedToAccessList( self ): return self.__ac.getAccessList() def canKeyAccess( self, aw ): # Categories don't allow access keys return False def canIPAccess( self, ip ): try: return self._v_canipaccess[ip] except AttributeError: self._v_canipaccess = {} except KeyError: pass if not self.__ac.canIPAccess( ip ): self._v_canipaccess[ip] = False return self._v_canipaccess[ip] if self.getOwner(): self._v_canipaccess[ip] = self.getOwner().canIPAccess(ip) return self._v_canipaccess[ip] self._v_canipaccess[ip] = True return self._v_canipaccess[ip] def isProtected( self ): return self.__ac.isProtected() def getAccessProtectionLevel( self ): return self.__ac.getAccessProtectionLevel() def isItselfProtected( self ): return self.__ac.isItselfProtected() def hasAnyProtection( self ): if self.__ac.isProtected() or len(self.getDomainList())>0: return True if self.getAccessProtectionLevel() == -1: return False if self.getOwner() is not None: return self.getOwner().hasAnyProtection() return False def updateFatherProtection( self ): """ Allows to change the parent access protection cached in this object """ self.__ac.setFatherProtection( self.getOwner().isProtected() ) self.updateSonsProtection() self.cleanCache() def setProtection( self, private ): """Allows to change the conference access protection """ self.__ac.setProtection( private ) self.updateSonsProtection() self.cleanCache() def updateSonsProtection( self ): for categ in self.getSubCategoryList(): categ.updateFatherProtection() for conf in self.getConferenceList(): conf.updateFatherProtection() def hasProtectedOwner( self ): return self.__ac._getFatherProtection() def isAllowedToAccess( self, av ): """Says whether an avatar can access a category independently of it is or not protected or domain filtered """ try: return self._v_isallowedtoaccess[av] except AttributeError: self._v_isallowedtoaccess = {} except KeyError: pass if self.__ac.canUserAccess( av ) or self.canUserModify( av ): self._v_isallowedtoaccess[av] = True return True if not self.isItselfProtected() and self.getOwner(): self._v_isallowedtoaccess[av] = self.getOwner().isAllowedToAccess( av ) return self._v_isallowedtoaccess[av] def canView(self,aw): if self.canAccess( aw ): return True for conf in self.getConferenceList(): if conf.canView( aw ): return True for subcateg in self.getSubCategoryList(): if subcateg.canView( aw ): return True return False def resetAccessCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canaccess"): del self._v_canaccess if hasattr(self,"_v_isallowedtoaccess"): del self._v_isallowedtoaccess if hasattr(self,"_v_canipaccess"): del self._v_canipaccess if UP and self.getOwner() is not None: self.getOwner().resetAccessCache(True, False) if DOWN: for cat in self.getSubCategoryList(): cat.resetAccessCache(False, True) for conf in self.getConferenceList(): conf.resetAccessCache(False, True) def resetModifyCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canmodify"): del self._v_canmodify if hasattr(self,"_v_canusermodify"): del self._v_canusermodify if UP and DOWN: self.resetAccessCache(UP, DOWN) if UP and self.getOwner() is not None: self.getOwner().resetModifyCache(True, False) if DOWN: for cat in self.getSubCategoryList(): cat.resetModifyCache(False, True) for conf in self.getConferenceList(): conf.resetModifyCache(False, True) def canAccess( self, aw ): try: return self._v_canaccess[aw] except AttributeError: self._v_canaccess = {} except KeyError: pass if not self.hasAnyProtection(): self._v_canaccess[aw] = True return True if not self.isProtected(): #domain checking only triggered if the category is PUBLIC self._v_canaccess[aw] = self.canIPAccess( aw.getIP() ) or \ self.isAllowedToCreateConference(aw.getUser()) or \ self.isAllowedToAccess(aw.getUser()) return self._v_canaccess[aw] self._v_canaccess[aw] = self.isAllowedToCreateConference(aw.getUser()) or \ self.isAllowedToAccess(aw.getUser()) return self._v_canaccess[aw] def grantAccess( self, prin ): self.__ac.grantAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "access") self.resetAccessCache() def revokeAccess( self, prin ): self.__ac.revokeAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "access") self.resetAccessCache() def isConferenceCreationRestricted( self ): return self.__confCreationRestricted def restrictConferenceCreation( self ): self.__confCreationRestricted = 1 def allowConferenceCreation( self ): self.__confCreationRestricted = 0 def grantConferenceCreation( self, prin ): if prin not in self.__confCreators: self.__confCreators.append( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "creator") self._p_changed = 1 def revokeConferenceCreation( self, prin ): if prin in self.__confCreators: self.__confCreators.remove( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "creator") self._p_changed = 1 def getConferenceCreatorList( self ): return self.__confCreators def isAllowedToCreateConference( self, av ): if self.canUserModify( av ): return 1 # Avatar is directly in the list if av in self.__confCreators: return 1 # Otherwise, if it is a member of one of the groups in the list... for group in self.__confCreators: if isinstance(group, MaKaC.user.Group): if group.containsUser(av): return 1 else: pass return 0 def canCreateConference( self, av ): if not self.isConferenceCreationRestricted(): return 1 return self.isAllowedToCreateConference( av ) def requireDomain( self, dom ): self.__ac.requireDomain( dom ) self.resetAccessCache() def freeDomain( self, dom ): self.__ac.freeDomain( dom ) self.resetAccessCache() def getDomainList( self ): return self.__ac.getRequiredDomainList() def getStatistics( self ): try: if self._statistics: pass except AttributeError, e: self._statistics = {} return self._statistics def updateStatistics( self ): self._statistics = self.getStatistics() self._statistics["events"] = {} self._statistics["contributions"] = {} self._statistics["resources"] = 0 if len(self.getSubCategoryList())>0: for cat in self.getSubCategoryList(): self._p_changed = 1 cat.updateStatistics() for year in cat._statistics["events"].keys(): if year in self._statistics["events"].keys(): self._statistics["events"][year] += cat._statistics["events"][year] else: self._statistics["events"][year] = cat._statistics["events"][year] for year in cat._statistics["contributions"].keys(): if year in self._statistics["contributions"].keys(): self._statistics["contributions"][year] += cat._statistics["contributions"][year] else: self._statistics["contributions"][year] = cat._statistics["contributions"][year] self._statistics["resources"] += cat._statistics["resources"] elif len(self.getConferenceList())>0: for conf in self.getConferenceList(): year = conf.getStartDate().year if year in self._statistics["events"].keys(): self._statistics["events"][year] += 1 else: self._statistics["events"][year] = 1 if len(conf.getContributionList())>0: for cont in conf.getContributionList(): if cont.getStartDate() != None: year = cont.getStartDate().year if year in self._statistics["contributions"].keys(): self._statistics["contributions"][year] += 1 else: self._statistics["contributions"][year] = 1 if len(cont.getSubContributionList())>0: for scont in cont.getSubContributionList(): l = scont.getAllMaterialList() for m in l: self._statistics["resources"] += m.getNbResources() l = cont.getAllMaterialList() for m in l: self._statistics["resources"] += m.getNbResources() if len(conf.getSessionList())>0: for sess in conf.getSessionList(): l = sess.getAllMaterialList() for m in l: self._statistics["resources"] += m.getNbResources() l = conf.getAllMaterialList() for m in l: self._statistics["resources"] += m.getNbResources() else: pass self._statistics["updated"] = nowutc() self._p_changed = 1 DBMgr.getInstance().commit() DBMgr.getInstance()._db.cacheFullSweep() def notifyModification( self ): """Method called to notify the current category has been modified. """ self.cleanCache() self._p_changed=1 class CustomLocation(Persistent): def __init__(self, **locationData): self.name = "" self.address = "" self.room = "" def setValues(self, data): self.setName(data.get("name","")) self.setAddress(data.get("address","")) self.setRoom(data.get("room","")) def getValues(self): d={} d["name"]=self.getName() d["address"]=self.getAddress() d["room"]=self.getRoom() return d def clone(self): newCL=CustomLocation() newCL.setValues(self.getValues()) return newCL def setName(self, newName): self.name = newName def getName(self): return self.name def setAddress(self, newAddress): self.address = newAddress def getAddress(self): return self.address def setRoom(self, newRoom): self.room = newRoom def getRoom(self): return self.room class CustomRoom(Persistent): def __init__( self ): self.name = "" def setValues(self, data): self.setName(data.get("name","")) def getValues(self): d={} d["name"]=self.getName() return d def getId(self): return "Custom" def clone(self): newCR=CustomRoom() newCR.setValues(self.getValues()) return newCR def setName( self, newName ): self.name = newName.strip() def getName( self ): return self.name class ConferenceParticipation(Persistent, Fossilizable): fossilizes(IConferenceParticipationFossil, IConferenceParticipationMinimalFossil) def __init__(self): self._firstName="" self._surName="" self._email="" self._affiliation="" self._address="" self._phone="" self._title="" self._fax="" def _notifyModification( self ): pass def setValues(self, data): self.setFirstName(data.get("firstName", "")) self.setFamilyName(data.get("familyName","")) self.setAffiliation(data.get("affilation","")) self.setAddress(data.get("address","")) self.setEmail(data.get("email","")) self.setFax(data.get("fax","")) self.setTitle(data.get("title","")) self.setPhone(data.get("phone","")) self._notifyModification() def getValues(self): data={} data["firstName"]=self.getFirstName() data["familyName"]=self.getFamilyName() data["affilation"]=self.getAffiliation() data["address"]=self.getAddress() data["email"]=self.getEmail() data["fax"]=self.getFax() data["title"]=self.getTitle() data["phone"]=self.getPhone() return data def setId(self, newId): self._id = newId def getId( self ): return self._id def setDataFromAvatar(self,av): # av is an Avatar object. if av is None: return self.setFirstName(av.getName()) self.setFamilyName(av.getSurName()) self.setEmail(av.getEmail()) self.setAffiliation(av.getOrganisation()) self.setAddress(av.getAddress()) self.setPhone(av.getTelephone()) self.setTitle(av.getTitle()) self.setFax(av.getFax()) self._notifyModification() def setDataFromOtherCP(self,cp): # cp is a ConferenceParticipation object. if cp is None: return self.setFirstName(cp.getFirstName()) self.setFamilyName(cp.getFamilyName()) self.setEmail(cp.getEmail()) self.setAffiliation(cp.getAffiliation()) self.setAddress(cp.getAddress()) self.setPhone(cp.getPhone()) self.setTitle(cp.getTitle()) self.setFax(cp.getFax()) self._notifyModification() def delete( self ): TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'firstName') def setFirstName(self,newName): tmp=newName.strip() if tmp==self._firstName: return self._firstName=tmp self._notifyModification() def getFirstName( self ): return self._firstName @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'familyName') def setFamilyName(self,newName): tmp=newName.strip() if tmp==self._surName: return self._surName=tmp self._notifyModification() def getFamilyName( self ): return self._surName @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'email') def setEmail(self,newMail): tmp=newMail.strip() if tmp==self._email: return self._email=newMail.strip() self._notifyModification() def getEmail( self ): return self._email @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'affiliation') def setAffiliation(self,newAffil): self._affiliation=newAffil.strip() self._notifyModification() def getAffiliation(self): return self._affiliation @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'address') def setAddress(self,newAddr): self._address=newAddr.strip() self._notifyModification() def getAddress(self): return self._address @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'phone') def setPhone(self,newPhone): self._phone=newPhone.strip() self._notifyModification() def getPhone(self): return self._phone @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'title') def setTitle(self,newTitle): self._title=newTitle.strip() self._notifyModification() def getTitle(self): return self._title @Updates (['MaKaC.conference.ConferenceParticipation', 'MaKaC.conference.SessionChair', 'MaKaC.conference.SlotChair'], 'fax') def setFax(self,newFax): self._fax=newFax.strip() self._notifyModification() def getFax(self): return self._fax def getFullName( self ): res = self.getFamilyName() if self.getFirstName() != "": if res.strip() != "": res = "%s, %s"%( res, self.getFirstName() ) else: res = self.getFirstName() if self.getTitle() != "": res = "%s %s"%( self.getTitle(), res ) return res def getFullNameNoTitle( self ): res = self.getFamilyName() if self.getFirstName() != "": if res.strip() != "": res = "%s, %s"%( res, self.getFirstName() ) else: res = self.getFirstName() return res def getDirectFullName( self ): res = "%s %s"%( self.getFirstName(), self.getFamilyName() ) res=res.strip() if self.getTitle() != "": res = "%s %s"%( self.getTitle(), res ) return res def getAbrName(self): res = self.getFamilyName() if self.getFirstName() != "": if res != "": res = "%s, "%res res = "%s%s."%(res, self.getFirstName()[0].upper()) return res def _cmpFamilyName( cp1, cp2 ): o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName()) o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName()) o1=o1.lower().strip() o2=o2.lower().strip() return cmp( o1, o2 ) _cmpFamilyName=staticmethod(_cmpFamilyName) class ConferenceChair(ConferenceParticipation): def __init__(self): self._conf=None self._id="" ConferenceParticipation.__init__(self) def _notifyModification( self ): if self._conf != None: self._conf.notifyModification() def clone(self): newCC=ConferenceChair() newCC.setValues(self.getValues()) return newCC def getConference(self): return self._conf def getId(self): return self._id def includeInConference(self,conf,id): if self.getConference()==conf and self.getId()==id.strip(): return self._conf=conf self._id=id def delete( self ): self._conf=None ConferenceParticipation.delete(self) def getLocator(self): if self.getConference() is None: return None loc=self.getConference().getLocator() loc["chairId"]=self.getId() return loc class SubmitterIndex(Persistent): """Index for contribution submitters. This class allows to index users with submission privileges over the conference contributions so the owner can answer optimally to the query if a user has any submission privilege over any contribution of the conference. It is implemented by simply using a BTree where the Avatar id is used as key (because it is unique and non variable) and a list of contributions over which he has submission privileges is kept as values. It is the responsability of the index owner (conference contributions) to keep it up-to-date i.e. notify conference sumitters additions and removals. """ def __init__( self ): self._idx = OOBTree() self._idxEmail = OOBTree() def _getIdxEmail(self): try: return self._idxEmail except: self._idxEmail = OOBTree() return self._idxEmail def getContributions(self,av): """Gives a list with the contributions over which a user has coordination privileges """ if av == None: return [] ret = self._idx.get(av.getId(),[]) if not ret: self._moveEmailtoId(av) ret = self._idx.get(av.getId(),[]) return ret def index(self,av,contrib): """Registers in the index a submitter of a contribution. """ if av==None or contrib==None: return if not self._idx.has_key(av.getId()): l=[] self._idx[av.getId()]=l else: l=self._idx[av.getId()] if contrib not in l: l.append(contrib) self._idx[av.getId()]=l def indexEmail(self, email, contrib): if not email or not contrib: return if not self._getIdxEmail().has_key(email): l = [contrib] self._getIdxEmail()[email] = l else: l = self._getIdxEmail()[email] if not contrib in l: l.append(contrib) self._getIdxEmail()[email] = l def unindex(self,av,contrib): if av==None or contrib==None: return l=self._idx.get(av.getId(),[]) if contrib in l: l.remove(contrib) self._idx[av.getId()]=l def unindexEmail(self, email, contrib): if not email or not contrib: return if self._getIdxEmail().has_key(email): l = self._getIdxEmail()[email] if contrib in l: l.remove(contrib) if l == []: del self._getIdxEmail()[email] else: self._getIdxEmail()[email] = l def _moveEmailtoId(self, av): id = av.getId() email = av.getEmail() if not self._idx.has_key(id): if self._getIdxEmail().has_key(email): self._idx[id] = self._getIdxEmail()[email] del self._getIdxEmail()[email] class ReportNumberHolder(Persistent): def __init__(self, owner): self._owner=owner self._reports={} def getOwner(self): return self._owner def addReportNumber(self, system, number): if system in self.getReportNumberKeys() or system in Config.getInstance().getReportNumberSystems().keys(): try: if not number in self._reports[system]: self._reports[system].append(number) except: self._reports[system]=[ number ] self.notifyModification() def removeReportNumber(self, system, number): if self.hasReportNumber(system): if number in self._reports[system]: self._reports[system].remove(number) self.notifyModification() def removeReportNumberById(self, id): try: rn = self.listReportNumbers()[int(id)] self.removeReportNumber(rn[0], rn[1]) except: pass def hasReportNumber(self, system): return self._reports.has_key(system) def getReportNumber(self, system): if self.hasReportNumber(system): return self._reports[system] return None def getReportNumberKeys(self): return self._reports.keys() def listReportNumbersOnKey(self, key): reports=[] if key in self._reports.keys(): # compatibility with previous versions if type(self._reports[key]) is str: self._reports[key] = [ self._reports[key] ] for number in self._reports[key]: reports.append([key, number]) return reports def listReportNumbers(self): reports=[] keys = self._reports.keys() keys.sort() for key in keys: # compatibility with previous versions if type(self._reports[key]) is str: self._reports[key] = [ self._reports[key] ] for number in self._reports[key]: reports.append([key, number]) return reports def clone(self, owner): newR=ReportNumberHolder(owner) for key in self._reports.keys(): for number in self._reports[key]: newR.addReportNumber(key, number) return newR def notifyModification(self): self._p_changed=1 if self.getOwner() != None: self.getOwner().notifyModification() class Conference(Persistent, Fossilizable, CommonObjectBase): """This class represents the real world conferences themselves. Objects of this class will contain basic data about the confence and will provide access to other objects representing certain parts of the conferences (ex: contributions, sessions, ...). """ fossilizes(IConferenceFossil, IConferenceMinimalFossil, IConferenceEventInfoFossil) def __init__(self, creator, id="", creationDate = None, modificationDate = None): """Class constructor. Initialise the class attributes to the default values. Params: confData -- (Dict) Contains the data the conference object has to be initialised to. """ #IndexedObject.__init__(self) if creator == None: raise MaKaCError( _("A creator must be specified when creating a new Event"), _("Event")) self.__creator = creator self.__creator.linkTo(self, "creator") self.id = id self.title = "" self.description = "" self.places = [] self.rooms = [] ################################### # Fermi timezone awareness # ################################### self.startDate = nowutc() self.endDate = nowutc() self.timezone = "" ################################### # Fermi timezone awareness(end) # ################################### self._screenStartDate = None self._screenEndDate = None self.contactInfo ="" self.chairmanText = "" self.chairmans = [] self._chairGen=Counter() self._chairs=[] self.sessions = {} self.__sessionGenerator = Counter() # Provides session unique # identifiers for this conference self.contributions = {} self.__contribGenerator = Counter() # Provides contribution unique # identifiers for this conference self.programDescription = "" self.program = [] self.__programGenerator = Counter() # Provides track unique # identifiers for this conference self.__ac = AccessController() self.materials = {} self.__materialGenerator = Counter() # Provides material unique # identifiers for this conference self.paper = None self.slides = None self.video = None self.poster = None self.minutes=None self.__schedule=None self.__owners = [] if creationDate: self._creationDS = creationDate else: self._creationDS = nowutc() #creation timestamp if modificationDate: self._modificationDS = modificationDate else: self._modificationDS = nowutc() #modification timestamp self._OAImodificationDS = self._modificationDS self.alarmList = {} self.abstractMgr = review.AbstractMgr(self) self._logo = None self._trackCoordinators = TCIndex() #index for the track coordinators self._supportEmail = "" #Support email for the conference self._contribTypes = {} self.___contribTypeGenerator = Counter() self._authorIdx=AuthorIndex() self._speakerIdx=AuthorIndex() self._primAuthIdx=_PrimAuthIdx(self) self._sessionCoordinators=SCIndex() self._sessionCoordinatorRights = [] self._submitterIdx=SubmitterIndex() self._boa=BOAConfig(self) self._registrationForm = registration.RegistrationForm(self) self._evaluationCounter = Counter() self._evaluations = [Evaluation(self)] self._registrants = {} #key=registrantId; value=Registrant self._bookings = {} self._registrantGenerator = Counter() self._accessKey="" self._modifKey="" self._closed = False self._visibility = 999 self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self) # self.indexConf() self._sections = [] self._participation = Participation(self) self._logHandler = LogHandler() self._reportNumberHolder=ReportNumberHolder(self) self._enableSessionSlots = False self._enableSessions = False self._autoSolveConflict = True self.__badgeTemplateManager = BadgeTemplateManager(self) self.__posterTemplateManager = PosterTemplateManager(self) self._keywords = "" self._confReview = ConferenceReview(self) self._orgText = "" self._comments = "" self._sortUrlTag = "" self._observers = [] if PluginsHolder().hasPluginType("Collaboration"): from MaKaC.plugins.Collaboration.base import CSBookingManager self._CSBookingManager = CSBookingManager(self) def setUrlTag(self, tag): self._sortUrlTag = tag def getUrlTag(self): try: return self._sortUrlTag except: self._sortUrlTag = "" return self._sortUrlTag def setComments(self,comm=""): self._comments = comm.strip() def getComments(self): try: if self._comments: pass except AttributeError,e: self.setComments() return self._comments def getConfReview(self): if not hasattr(self, "_confReview"): self._confReview = ConferenceReview(self) return self._confReview def getOrgText( self ): try: return self._orgText except: self.setOrgText() return "" def setOrgText( self, org="" ): self._orgText = org def cleanCache( self ): minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance() if minfo.isCacheActive(): cache = EventCache({"id":self.getId(), "type": "normal"}) cache.cleanCache() cache = EventCache({"id":self.getId(), "type": "manager"}) cache.cleanCache() cache = EventCache({"id":self.getId(), "type": "static"}) cache.cleanCache() def cleanCategoryCache( self ): if len(self.getOwnerList()) > 0: self.getOwnerList()[0].cleanCache() def isFullyPublic( self ): """ determines whether an event (or any part of it) is private or not""" if hasattr(self, "_fullyPublic"): return self._fullyPublic else: self.setFullyPublic() return self._fullyPublic def setFullyPublic( self ): """ This function calculates the self._fullyPublic attribute""" if self.isProtected(): self._fullyPublic = False self._p_changed=1 return for mat in self.getAllMaterialList(): if not mat.isFullyPublic(): self._fullyPublic = False self._p_changed=1 return for cont in self.getContributionList(): if not cont.isFullyPublic(): self._fullyPublic = False self._p_changed=1 return for ses in self.getSessionList(): if not ses.isFullyPublic(): self._fullyPublic = False self._p_changed=1 return self._fullyPublic = True self._p_changed = 1 def updateFullyPublic( self ): self.setFullyPublic() # Room booking related self.__roomBookingGuids = [] def getKeywords(self): try: return self._keywords except: self._keywords = "" return "" def setKeywords(self, keywords): self._keywords = keywords def _setCreator(self, av): self.__creator = av # Room booking related =================================================== def getRoomBookingList( self ): """ Returns list of bookings for this conference. """ if not "__roomBookingGuids" in ','.join( dir( self ) ): self.__roomBookingGuids = [] #self.__TMP_PopulateRoomBookings() resvs = [] for resvGuid in self.__roomBookingGuids: r = resvGuid.getReservation() if r == None: self.removeRoomBookingGuid( resvGuid ) elif r.isValid: resvs.append( r ) return resvs def getRoomBookingIds( self ): """ Returns list of booking ids for this conference. """ if not "__roomBookingGuids" in ','.join( dir( self ) ): self.__roomBookingGuids = [] #self.__TMP_PopulateRoomBookings() return self.__roomBookingGuids def getBookedRooms( self ): """ Returns list of rooms booked for this conference. Returns [] if room booking module is off. """ rooms = [] minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance() if minfo.getRoomBookingModuleActive(): for r in self.getRoomBookingList(): if not r.room in rooms: rooms.append( r.room ) return rooms def getRoomBookingGuids( self ): if not "__roomBookingGuids" in ','.join( dir( self ) ): self.__roomBookingGuids = [] return self.__roomBookingGuids def setRoomBookingGuids( self, guids ): self.__roomBookingGuids = guids def addRoomBookingGuid( self, guid ): if not "__roomBookingGuids" in ','.join( dir( self ) ): self.__roomBookingGuids = [] self.__roomBookingGuids.append( guid ) self._p_changed = True def removeRoomBookingGuid( self, guid ): if not "__roomBookingGuids" in ','.join( dir( self ) ): self.__roomBookingGuids = [] self.__roomBookingGuids.remove( guid ) self._p_changed = True def __TMP_PopulateRoomBookings( self ): # TEMPORARY GENERATION OF RESERVATIONS FOR CONFERENCE from MaKaC.rb_reservation import ReservationBase from MaKaC.rb_location import ReservationGUID, Location resvs = [] resvs.append( ReservationBase.getReservations( resvID = 395887 ) ) resvs.append( ReservationBase.getReservations( resvID = 381406 ) ) resvs.append( ReservationBase.getReservations( resvID = 387688 ) ) resvs.append( ReservationBase.getReservations( resvID = 383459 ) ) resvGuids = [] for resv in resvs: resvGuids.append( ReservationGUID( Location.getDefaultLocation(), resv.id ) ) self.__roomBookingGuids = resvGuids # ======================================================================== def getParticipation(self): try : if self._participation : pass except AttributeError : self._participation = Participation(self) return self._participation def getType( self ): import MaKaC.webinterface.webFactoryRegistry as webFactoryRegistry wr = webFactoryRegistry.WebFactoryRegistry() wf = wr.getFactory(self) if wf != None: type = wf.getId() else: type = "conference" return type def getVerboseType( self ): # Like getType, but returns "Lecture" instead of "simple_type" type = self.getType() if type == "simple_event": type = "lecture" return type.capitalize() def getLogHandler(self): try : if self._logHandler: pass except AttributeError : self._logHandler = LogHandler() return self._logHandler def getEnableSessionSlots(self): #try : # if self._enableSessionSlots : # pass #except AttributeError : # self._enableSessionSlots = True #if self.getType() == "conference": # return True #return self._enableSessionSlots return True def getEnableSessions(self): try : if self._enableSessions : pass except AttributeError : self._enableSessions = True if self.getType() == "conference": return True return self._enableSessions def enableSessionSlots(self): self._enableSessionSlots = True def disableSessionSlots(self): self._enableSessionSlots = False def enableSessions(self): self._enableSessions = True def disableSessions(self): self._enableSessions = False def setValues(self, confData): """ Sets SOME values of the current conference object from a dictionary containing the following key-value pairs: visibility-(str) title-(str) description-(str) supportEmail-(str) contactInfo-(str) locationName-(str) => name of the location, if not specified it will be set to the conference location name. locationAddress-(str) roomName-(str) => name of the room, if not specified it will be set to the conference room name. Please, note that this method sets SOME values which means that if needed it can be completed to set more values. Also note that if the given dictionary doesn't contain all the values, the missing ones will be set to the default values. """ self.setVisibility(confData.get("visibility", "999")) self.setTitle(confData.get("title", _("NO TITLE ASSIGNED"))) self.setDescription(confData.get("description", "")) self.setSupportEmail(confData.get("supportEmail", "")) self.setContactInfo(confData.get("contactInfo", "")) if confData.get("locationName", "").strip() == "": self.setLocation(None) else: #if the location name is defined we must set a new location (or # modify the existing one) for the conference loc = self.getLocation() if not loc: loc = CustomLocation() self.setLocation(loc) loc.setName(confData["locationName"]) loc.setAddress(confData.get("locationAddress", "")) #same as for the location if confData.get("roomName", "").strip() == "": self.setRoom(None) else: room = self.getRoom() if not room: room = CustomRoom() self.setRoom(room) room.setName(confData["roomName"]) self.notifyModification() def getVisibility ( self ): try: return int(self._visibility) except: self._visibility = 999 return 999 def getFullVisibility( self ): return max(0,min(self.getVisibility(), self.getOwnerList()[0].getVisibility())) def setVisibility( self, visibility=999 ): self._visibility = int(visibility) catIdx = indexes.IndexesHolder().getIndex('category') catIdx.reindexConf(self) def isClosed( self ): try: return self._closed except: self._closed = False return False def setClosed( self, closed=True ): self._closed = closed def indexConf( self ): calIdx = indexes.IndexesHolder().getIndex('calendar') calIdx.indexConf(self) catDateIdx = indexes.IndexesHolder().getIndex('categoryDate') catDateIdx.indexConf(self) def unindexConf( self ): calIdx = indexes.IndexesHolder().getIndex('calendar') calIdx.unindexConf(self) catDateIdx = indexes.IndexesHolder().getIndex('categoryDate') catDateIdx.unindexConf(self) def __generateNewContribTypeId( self ): """Returns a new unique identifier for the current conference sessions """ try: return str(self.___contribTypeGenerator.newCount()) except: self.___contribTypeGenerator = Counter() return str(self.___contribTypeGenerator.newCount()) def addContribType(self, ct): try: if self._contribTypes: pass except: self._contribTypes = {} if ct in self._contribTypes.values(): return id = ct.getId() if id == "": id = self.__generateNewContribTypeId() ct.setId(id) self._contribTypes[id] = ct self.notifyModification() def newContribType(self, name, description): ct = ContributionType(name, description, self) self.addContribType(ct) return ct def getContribTypeList(self): try: return self._contribTypes.values() except: self._contribTypes = {} self.notifyModification() return self._contribTypes.values() def getContribTypeById(self, id): try: if self._contribTypes: pass except: self._contribTypes = {} self.notifyModification() if id in self._contribTypes.keys(): return self._contribTypes[id] return None def removeContribType(self, ct): try: if self._contribTypes: pass except: self._contribTypes = {} if not ct in self._contribTypes.values(): return del self._contribTypes[ct.getId()] for cont in self.getContributionList(): if cont.getType() == ct: cont.setType(None) ct.delete() self.notifyModification() def recoverContribType(self, ct): ct.setConference(self) self.addContribType(ct) ct.recover() def _getRepository( self ): dbRoot = DBMgr.getInstance().getDBConnection().root() try: fr = dbRoot["local_repositories"]["main"] except KeyError, e: fr = fileRepository.MaterialLocalRepository() dbRoot["local_repositories"] = OOBTree() dbRoot["local_repositories"]["main"] = fr return fr def removeResource( self, res ): pass def setLogo( self, logoFile ): logoFile.setOwner( self ) logoFile.setId( "logo" ) logoFile.archive( self._getRepository() ) if self._logo != None: self._logo.delete() self._logo = logoFile self.notifyModification() def getLogo( self ): return self._logo def getLogoURL( self ): try: if self._logo == None: return "" return self._logo.getURL() except AttributeError: self._logo = None return "" def removeLogo(self): if self._logo is None: return self._logo.delete() self._logo = None self.notifyModification() def recoverLogo(self, logo): logo.setOwner(self) if self._logo != None: self._logo.delete() self._logo = logo logo.recover() self.notifyModification() def getSession(self): return None def getContribution(self): return None def getSubContribution(self): return None def getAbstractMgr(self): return self.abstractMgr def notifyModification( self, date=None, updateChildren=False): """Method called to notify the current conference has been modified. """ if not date: date = nowutc() self._modificationDS = date self.notifyOAIModification(date=date, updateChildren = updateChildren) self.cleanCache() self._p_changed=1 def notifyOAIModification(self, date=None, updateChildren=False): #, force=False): # ignore call if the id is not set # this is to avoid empty id entries in the index # TODO: better would be to call the method only when the id is set if self.id == '': return self.getOAIModificationDate() #init _OAImodificationDS value if it don't exist idxPu = indexes.IndexesHolder().getById("OAIConferenceModificationDate") idxPr = indexes.IndexesHolder().getById("OAIPrivateConferenceModificationDate") if self.hasAnyProtection(): if self in idxPu.getConferences(self._OAImodificationDS.strftime("%Y-%m-%d"), self._OAImodificationDS.strftime("%Y-%m-%d")): #The conference was public and is now private idxPu.unindexConference(self) if not date: date = nowutc() self._OAImodificationDS = date self._p_changed=1 idxPr.indexConference(self) elif self in idxPr.getConferences(self._OAImodificationDS.strftime("%Y-%m-%d"), self._OAImodificationDS.strftime("%Y-%m-%d")): #The conference is already indexed in private # if force: idxPr.unindexConference(self) if not date: date = nowutc() self._OAImodificationDS = date idxPr.indexConference(self) else: #The conference wasn't indexed before and is private if not date: date = nowutc() self._OAImodificationDS = date self._p_changed=1 idxPr.indexConference(self) else: if self in idxPr.getConferences(self._OAImodificationDS.strftime("%Y-%m-%d"), self._OAImodificationDS.strftime("%Y-%m-%d")): #The conference was private and is now public idxPr.unindexConference(self) if not date: date = nowutc() self._OAImodificationDS = date idxPu.indexConference(self) elif self in idxPu.getConferences(self._OAImodificationDS.strftime("%Y-%m-%d"), self._OAImodificationDS.strftime("%Y-%m-%d")): #The conference is already indexed in public, reIndex it with new date idxPu.unindexConference(self) if not date: date = nowutc() self._OAImodificationDS = date idxPu.indexConference(self) else: #The conference wasn't indexed before and is public if not date: date = nowutc() self._OAImodificationDS = date idxPu.indexConference(self) if updateChildren: for contrib in self.getContributionList(): contrib.notifyOAIModification(date=date)#, force=force) def getModificationDate( self ): """Returns the date in which the conference was last modified""" return self._modificationDS def getAdjustedModificationDate( self, tz ): """Returns the date in which the conference was last modified""" return self._modificationDS.astimezone(timezone(tz)) def getOAIModificationDate(self): try: return self._OAImodificationDS except: self._OAImodificationDS = nowutc() return self._OAImodificationDS def getCreationDate( self ): """Returns the date in which the conference was created""" return self._creationDS def getAdjustedCreationDate( self, tz ): """Returns the date in which the conference was created""" return self._creationDS.astimezone(timezone(tz)) def getCreator( self ): return self.__creator def setCreator( self, creator): if self.__creator: self.__creator.unlinkTo(self, "creator") creator.linkTo(self, "creator") self.__creator = creator def getId( self ): """returns (string) the unique identifier of the conference""" return self.id def getUniqueId( self ): """returns (string) the unique identiffier of the item""" """used mainly in the web session access key table""" return "a%s" % self.id def setId(self, newId): """changes the current unique identifier of the conference to the one which is specified""" self.id = str(newId) def getLocator( self ): """Gives back (Locator) a globaly unique identification encapsulated in a Locator object for the conference instance """ d = Locator() d["confId"] = self.getId() return d def getOwner( self ): if self.getOwnerList() == []: return None return self.getOwnerList()[0] def getOwnerList( self ): return self.__owners def getOwnerPath( self ): l=[] owner = self.getOwnerList()[0] while owner != None and owner.getId() != "0": l.append(owner) owner = owner.getOwner() return l def getOwnerById( self, key ): """Returns one specific category which contains the conference. Params: - key: The "id" of the category. """ for owner in self.__owners: if key == owner.getId(): return owner return None def addOwner( self, newOwner ): if newOwner == None: return self.__owners.append( newOwner ) self.notifyModification() def removeOwner( self, owner, notify=True ): if not (owner in self.__owners): return self.__owners.remove( owner ) owner.removeConference( self ) if notify: self.notifyModification() def getCategoriesPath(self): return [self.getOwnerList()[0].getCategoryPath()] def unindexContributions(self): # Removes the contributions from the OAI "active" indexes, # adding them to the DeletedObjectHolder for c in self.getContributionList(): c.unindex() # take care of subcontributions for sc in c.getSubContributionList(): sc.unindex() DeletedObjectHolder().add(DeletedObject(sc)) DeletedObjectHolder().add(DeletedObject(c)) def delete( self ): """deletes the conference from the system. """ #we notify the observers that the conference has been deleted for observer in self.getObservers(): try: observer.notifyDeletion() except Exception, e: try: Logger.get('Conference').error("Exception while notifying the observer %s of of a conference deletion for conference %s: %s"% (observer.getObserverName(), self.getId(), str(e))) except Exception, e2: Logger.get('Conference').error("Exception while notifying a conference deletion: %s (origin: %s)"%(str(e2), str(e))) self.unindexContributions() #index a DeletedObject to keep track of the conference after the deletion DeletedObjectHolder().add(DeletedObject(self)) #will have to remove it from all the owners (categories) and the # conference registry ConferenceHolder().remove( self ) for owner in self.__owners: owner.removeConference( self, notify=False ) for alarm in self.getAlarmList(): self.removeAlarm(alarm) self.removeAllEvaluations() #For each conference we have a list of managers. If we delete the conference but we don't delete #the link in every manager to the conference then, when the manager goes to his "My profile" he #will see a link to a conference that doesn't exist. Therefore, we need to delete that link as well for manager in self.getManagerList(): if isinstance(manager, MaKaC.user.Avatar): manager.unlinkTo(self, "manager") TrashCanManager().add(self) indexes.IndexesHolder().getById("OAIConferenceModificationDate").unindexConference(self) indexes.IndexesHolder().getById("OAIPrivateConferenceModificationDate").unindexConference(self) def getConference( self ): return self def getObservers(self): if not hasattr(self, "_observers"): self._observers = [] return self._observers def addObserver(self, observer): self.getObservers().append(observer) self._p_changed=1 def removeObserver(self, observer): self.getObservers().remove(observer) self._p_changed=1 def setDates( self, sDate, eDate=None, check=1, moveEntries=0 ): """ Set the start/end date for a conference """ oldStartDate = self.getStartDate() oldEndDate = self.getEndDate() # do some checks first if sDate > eDate: # obvious case raise MaKaCError( _("Start date cannot be after the end date"), _("Event")) elif sDate == oldStartDate and eDate == oldEndDate: # if there's nothing to do (yet another obvious case) return # if we reached this point, it means either the start or # the end date (or both) changed # If only the end date was changed, moveEntries = 0 if sDate == oldStartDate: moveEntries = 0 # Pre-check for moveEntries if moveEntries == 1: # in case the entries are to be simply shifted # we should make sure the interval is big enough # just store the old values for later oldInterval = oldEndDate - oldStartDate newInterval = eDate - sDate if oldInterval > newInterval: raise TimingError( _("The start/end dates were not changed since the selected " "timespan is not large enough to accomodate the contained " "timetable entries and spacings."), explanation = _("You should try using a larger timespan.")) # so, we really need to try changing something # let's get to work and remove the conference from the date indexes self.unindexConf() # set the dates self.setStartDate(sDate, check=0, moveEntries = moveEntries, index=False, notifyObservers = False) self.setEndDate(eDate, check=0, index=False, notifyObservers = False) # sanity check self._checkInnerSchedule() # reindex the conference self.indexConf() # clear the category cache self.cleanCategoryCache() # notify observers for observer in self.getObservers(): try: observer.notifyEventDateChanges(oldStartDate, self.getStartDate(), oldEndDate, self.getEndDate()) except Exception, e: try: Logger.get('Conference').error("Exception while notifying the observer %s of a start and end date change from %s - %s to %s - %s for conference %s: %s"% (observer.getObserverName(), formatDateTime(oldStartDate), formatDateTime(oldEndDate), formatDateTime(self.getStartDate()), formatDateTime(self.getEndDate()), self.getId(), str(e))) except Exception, e2: Logger.get('Conference').error("Exception while notifying a start and end date change: %s (origin: %s)"%(str(e2), str(e))) def _checkInnerSchedule( self ): self.getSchedule().checkSanity() def setStartDate(self, sDate, check = 1, moveEntries = 0, index = True, notifyObservers = True): """ Changes the current conference starting date/time to the one specified by the parameters. """ if not sDate.tzname(): raise MaKaCError("date should be timezone aware") if sDate == self.getStartDate(): return ################################### # Fermi timezone awareness # ################################### if sDate.year < 1900: sDate = timezone('UTC').localize(1900,sDate.month, \ sDate.day,sDate.hour,sDate.minute) ################################### # Fermi timezone awareness # ################################### if check != 0: self.verifyStartDate(sDate) oldSdate = self.getStartDate() diff = sDate - oldSdate if index: self.unindexConf() self.startDate = sDate if moveEntries and diff is not None: # If the start date changed, we move entries inside the timetable self.getSchedule()._startDate=None self.getSchedule()._endDate=None #if oldSdate.date() != sDate.date(): # entries = self.getSchedule().getEntries()[:] #else: # entries = self.getSchedule().getEntriesOnDay(sDate.astimezone(timezone(self.getTimezone())))[:] entries = self.getSchedule().getEntries()[:] self.getSchedule().moveEntriesBelow(diff, entries) #datetime object is non-mutable so we must "force" the modification # otherwise ZODB won't be able to notice the change self.notifyModification() if index: self.indexConf() #if everything went well, we notify the observers that the start date has changed if notifyObservers: for observer in self.getObservers(): try: observer.notifyEventDateChanges(oldSdate, sDate, None, None) except Exception, e: try: Logger.get('Conference').error("Exception while notifying the observer %s of a start date change from %s to %s for conference %s: %s"% (observer.getObserverName(), formatDateTime(oldSdate), formatDateTime(sDate), self.getId(), str(e))) except Exception, e2: Logger.get('Conference').error("Exception while notifying a start date change: %s (origin: %s)"%(str(e2), str(e))) def verifyStartDate(self, sdate, check=1): if sdate>self.getEndDate(): raise MaKaCError( _("End date cannot be before the Start date"), _("Event")) def setStartTime(self, hours=0, minutes=0, notifyObservers = True): """ Changes the current conference starting time (not date) to the one specified by the parameters. """ sdate = self.getStartDate() self.startDate = datetime( sdate.year, sdate.month, sdate.day, int(hours), int(minutes) ) self.verifyStartDate(self.startDate) self.notifyModification() #if everything went well, we notify the observers that the start date has changed if notifyObservers: for observer in self.getObservers(): try: observer.notifyEventDateChanges(sdate, self.startDate, None, None) except Exception, e: try: Logger.get('Conference').error("Exception while notifying the observer %s of a start date change from %s to %s for conference %s: %s"% (observer.getObserverName(), formatDateTime(sdate), formatDateTime(self.startDate), self.getId(), str(e))) except Exception, e2: Logger.get('Conference').error("Exception while notifying a start time change: %s (origin: %s)"%(str(e2), str(e))) def getStartDate(self): """returns (datetime) the starting date of the conference""" return self.startDate ################################### # Fermi timezone awareness # ################################### def getAdjustedStartDate(self,tz=None): if not tz: tz = self.getTimezone() if tz not in all_timezones: tz = 'UTC' return self.getStartDate().astimezone(timezone(tz)) ################################### # Fermi timezone awareness(end) # ################################### def setScreenStartDate(self, date): if date == self.getStartDate(): date = None self._screenStartDate = date self.notifyModification() def getScreenStartDate(self): try: date = self._screenStartDate except: date = self._screenStartDate = None if date != None: return date else: return self.getStartDate() def getAdjustedScreenStartDate(self, tz=None): if not tz: tz = self.getTimezone() return self.getScreenStartDate().astimezone(timezone(tz)) def calculateDayStartTime(self, day): """returns (date) the start date of the conference on a given day day is a tz aware datetime""" if self.getStartDate().astimezone(day.tzinfo).date() == day.date(): return self.getStartDate().astimezone(day.tzinfo) return self.getSchedule().calculateDayStartDate(day) def verifyEndDate(self, edate): if edate0: return self.places[0] return None def setLocation( self, newLocation ): if newLocation == None: if len(self.places)>0: del self.places[0] elif len(self.places)>0: self.places[0] = newLocation else: self.places.append( newLocation ) self.notifyModification() def getOwnRoom( self ): return self.getRoom() def getRoom( self ): if len(self.rooms)>0: return self.rooms[0] return None def setRoom( self, newRoom ): if newRoom == None: if len(self.rooms)>0: del self.rooms[0] elif len(self.rooms)>0: self.rooms[0] = newRoom else: self.rooms.append( newRoom ) self.notifyModification() def getLocationList(self): """Method returning a list of "location" objects which contain the information about the different places the conference is gonna happen """ return self.places def getFavoriteRooms(self): roomList = [] roomList.extend(self.getRoomList()) roomList.extend(map(lambda x: x._getName(), self.getBookedRooms())) return roomList def addLocation(self, newPlace): self.places.append( newPlace ) self.notifyModification() def setAccessKey(self, accessKey=""): """sets the access key of the conference""" self._accessKey = accessKey self.notifyModification() self.resetAccessCache() def getAccessKey(self): try: return self._accessKey except AttributeError: self._accessKey = "" return self._accessKey def setModifKey(self, modifKey=""): """sets the modification key of the conference""" self._modifKey = modifKey self.notifyModification() self.resetModifyCache() def getModifKey(self): try: return self._modifKey except AttributeError: self._modifKey = "" return self._modifKey def __generateNewSessionId( self ): """Returns a new unique identifier for the current conference sessions """ return str(self.__sessionGenerator.newCount()) def addSession(self,newSession, check = 2, id = None): """Adds a new session object to the conference taking care of assigning a new unique id to it """ """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" if self.hasSession(newSession): return if self.getSchedule().isOutside(newSession): if check == 1: MaKaCError( _("Cannot add this session (Start:%s - End:%s) Outside of the event's time table(Start:%s - End:%s)") % (newSession.getStartDate(),newSession.getEndDate(),self.getSchedule().getStartDate(), self.getSchedule().getEndDate()),"Event") elif check == 2: if self.getSchedule().getStartDate() > newSession.getStartDate(): self.setStartDate(newSession.getStartDate()) if self.getSchedule().getEndDate() < newSession.getEndDate(): self.setEndDate(newSession.getEndDate()) if id!=None: sessionId = id else: sessionId=self.__generateNewSessionId() self.sessions[sessionId]=newSession newSession.includeInConference(self,sessionId) #keep the session coordinator index updated for sc in newSession.getCoordinatorList(): self.addSessionCoordinator(newSession,sc) self.notifyModification() def hasSession(self,session): if session != None and session.getConference()==self and \ self.sessions.has_key(session.getId()): return True return False def removeSession(self,session, deleteContributions=False): if self.hasSession(session): for sc in session.getCoordinatorList(): self.removeSessionCoordinator(session,sc) if deleteContributions: for contrib in session.getContributionList(): contrib.delete() del self.sessions[session.getId()] session.delete() self.notifyModification() def recoverSession(self, session, check, isCancelled): self.addSession(session, check, session.getId()) session.recover(isCancelled) def getSessionById( self, sessionId ): """Returns the session from the conference list corresponding to the unique session id specified """ return self.sessions.get(sessionId,None) def getRoomList(self): roomList =[] for session in self.sessions.values(): if session.getRoom()!=None: roomname = session.getRoom().getName() if roomname not in roomList: roomList.append(roomname) return roomList def getSessionList( self ): """Retruns a list of the conference session objects """ return self.sessions.values() def getSessionListSorted( self ): """Retruns a sorted list of the conference sessions """ res=[] for entry in self.getSchedule().getEntries(): if isinstance(entry,LinkedTimeSchEntry) and \ isinstance(entry.getOwner(),SessionSlot): session=entry.getOwner().getSession() if session not in res: res.append(session) return res def _generateNewContributionId( self ): """Returns a new unique identifier for the current conference contributions """ return str(self.__contribGenerator.newCount()) def genNewAbstractId(self): return str(self.__contribGenerator.newCount()) def syncContribCounter(self): self.__contribGenerator.sync(self.getAbstractMgr()._getOldAbstractCounter()) return self.__contribGenerator._getCount() def addContribution(self,newContrib,id=""): """Adds a new contribution object to the conference taking care of assigning a new unique id to it """ if self.hasContribution(newContrib): return if isinstance(newContrib.getCurrentStatus(),ContribStatusWithdrawn): raise MaKaCError( _("Cannot add a contribution which has been withdrawn"), _("Event")) if id is None or id=="": contribId=self._generateNewContributionId() while self.contributions.has_key(contribId): contribId=self._generateNewContributionId() else: contribId=str(id) if self.contributions.has_key(contribId): raise MaKaCError( _("Cannot add this contribution id:(%s) as it has already been used")%contribId, _("Event")) newContrib.includeInConference(self,contribId) self.contributions[contribId]=newContrib for auth in newContrib.getAuthorList(): self.indexAuthor(auth) for spk in newContrib.getSpeakerList(): self.indexSpeaker(spk) for sub in newContrib.getSubmitterList(): self.addContribSubmitter(newContrib,sub) self.notifyModification() def hasContribution(self,contrib): return contrib.getConference()==self and \ self.contributions.has_key(contrib.getId()) def removeContribution( self, contrib, callDelete=True ): if not self.contributions.has_key( contrib.getId() ): return for sub in contrib.getSubmitterList(): self.removeContribSubmitter(contrib,sub) for auth in contrib.getPrimaryAuthorList(): contrib.removePrimaryAuthor(auth) for auth in contrib.getCoAuthorList(): contrib.removeCoAuthor(auth) for spk in contrib.getSpeakerList(): contrib.removeSpeaker(spk) del self.contributions[ contrib.getId() ] if callDelete: contrib.delete() else: contrib.unindex() self.notifyModification() def recoverContribution(self, contrib): self.addContribution(contrib, contrib.getId()) contrib.recover() # Note: this kind of factories should never be used as they only allow to # create a single type of contributions def newContribution( self, id=None ): """Creates and returns a new contribution object already added to the conference list (all its data is set to the default) """ c = Contribution() self.addContribution( c, id ) return c def getOwnContributionById( self, id ): """Returns the contribution from the conference list corresponding to the unique contribution id specified """ if self.contributions.has_key( id ): return self.contributions[ id ] return None def getContributionById( self, id ): """Returns the contribution corresponding to the id specified """ return self.contributions.get(str(id).strip(),None) def getContributionList(self): """Returns a list of the conference contribution objects """ return self.contributions.values() def getContributionListSortedById(self): """Returns a list of the conference contribution objects, sorted by their id """ contributions = self.contributions.values() contributions.sort(key = lambda c: c.getId()) return contributions def getNumberOfContributions(self): return len(self.contributions) def getProgramDescription(self): try: return self.programDescription except: self.programDescription = "" return self.programDescription def setProgramDescription(self, txt): self.programDescription = txt def _generateNewTrackId( self ): """ """ return str(self.__programGenerator.newCount()) def addTrack( self, newTrack ): """ """ #XXX: The conference program shoul be isolated in a separated object if newTrack in self.program: return trackId = newTrack.getId() if trackId == "not assigned": trackId = self._generateNewTrackId() self.program.append( newTrack ) newTrack.setConference( self ) newTrack.setId( trackId ) self.notifyModification() def removeTrack( self, track ): if track in self.program: track.delete() if track in self.program: self.program.remove( track ) self.notifyModification() def recoverTrack(self, track): self.addTrack(track) track.recover() def newTrack( self ): """ """ t = Track() self.addTrack( t ) return t def getTrackById( self, id ): """ """ for track in self.program: if track.getId() == id.strip(): return track return None def getTrackList( self ): """ """ return self.program def isLastTrack(self,track): """ """ return self.getTrackPos(track)==(len(self.program)-1) def isFirstTrack(self,track): """ """ return self.getTrackPos(track)==0 def getTrackPos(self,track): """ """ return self.program.index(track) def moveTrack(self,track,newPos): """ """ self.program.remove(track) self.program.insert(newPos,track) self.notifyModification() def moveUpTrack(self,track): """ """ if self.isFirstTrack(track): return newPos=self.getTrackPos(track)-1 self.moveTrack(track,newPos) def moveDownTrack(self,track): """ """ if self.isLastTrack(track): return newPos=self.getTrackPos(track)+1 self.moveTrack(track,newPos) def _cmpTracks( self, t1, t2 ): o1 = self.program.index(t1) o2 = self.program.index(t2) return cmp( o1, o2 ) def sortTrackList( self, l ): """Sorts out a list of tracks according to the current programme order. """ if len(l) == 0: return [] elif len(l) == 1: return [l[0]] else: res = [] for i in l: res.append( i ) res.sort( self._cmpTracks ) return res def canIPAccess( self, ip ): try: return self._v_canipaccess[ip] except AttributeError: self._v_canipaccess = {} except KeyError: pass if not self.__ac.canIPAccess( ip ): self._v_canipaccess[ip] = False return False for owner in self.getOwnerList(): if not owner.canIPAccess(ip): self._v_canipaccess[ip] = False return self._v_canipaccess[ip] self._v_canipaccess[ip] = True return self._v_canipaccess[ip] def requireDomain( self, dom ): self.__ac.requireDomain( dom ) self.resetAccessCache() self.notifyOAIModification() def freeDomain( self, dom ): self.__ac.freeDomain( dom ) self.resetAccessCache() self.notifyOAIModification() def getDomainList( self ): return self.__ac.getRequiredDomainList() def isProtected( self ): """Tells whether a conference is protected for accessing or not """ return self.__ac.isProtected() def getAccessProtectionLevel( self ): return self.__ac.getAccessProtectionLevel() def isItselfProtected( self ): return self.__ac.isItselfProtected() def hasAnyProtection( self ): """Tells whether a conference has any kind of protection over it: access or domain protection. """ if self.isProtected(): return True if self.getDomainList(): return True if self.getAccessProtectionLevel() == -1: return False for owner in self.getOwnerList(): if owner.hasAnyProtection(): return True return False def hasProtectedOwner( self ): return self.__ac._getFatherProtection() def updateFatherProtection( self ): protectionBefore = self.__ac.isFatherProtected() self.__ac.setFatherProtection(0) for owner in self.getOwnerList(): if owner.isProtected(): self.__ac.setFatherProtection(1) protectionAfter = self.__ac.isFatherProtected() if protectionBefore != protectionAfter: self.notifyOAIModification(updateChildren=True) def setProtection( self, private ): """Allows to change the conference access protection """ self.__ac.setProtection( private ) self.updateFullyPublic() self.cleanCategoryCache() self.notifyOAIModification(updateChildren=True) def grantAccess( self, prin ): self.__ac.grantAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "access") self.resetAccessCache() def revokeAccess( self, prin ): self.__ac.revokeAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "access") self.resetAccessCache() def canView( self, aw ): """tells whether the specified access wrappers has access to the current object or any of its parts""" if self.canAccess( aw ): return True for session in self.getSessionList(): if session.canView( aw ): return True for contrib in self.getContributionList(): if contrib.canView( aw ): return True return False def isAllowedToAccess( self, av): """tells if a user has privileges to access the current conference (independently that it is protected or not) """ try: return self._v_isallowedtoaccess[av] except AttributeError: self._v_isallowedtoaccess = {} except KeyError: pass if not av: return False if (av in self.getChairList()) or (self.__ac.canUserAccess( av )) or (self.canUserModify( av )): self._v_isallowedtoaccess[av] = True return True # if the conference is not protected by itself if not self.isItselfProtected(): # then inherit behavior from parent category for owner in self.getOwnerList(): if owner.isAllowedToAccess( av ): self._v_isallowedtoaccess[av] = True return True # track coordinators are also allowed to access the conference for track in self.getTrackList(): if track.isCoordinator( av ): self._v_isallowedtoaccess[av] = True return True # video services managers are also allowed to access the conference if PluginsHolder().hasPluginType("Collaboration"): if self.getCSBookingManager().isPluginManagerOfAnyPlugin(av): self._v_isallowedtoaccess[av] = True return True self._v_isallowedtoaccess[av] = False return False def resetAccessCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canaccess"): del self._v_canaccess if hasattr(self,"_v_isallowedtoaccess"): del self._v_isallowedtoaccess if hasattr(self,"_v_cankeyaccess"): del self._v_cankeyaccess if hasattr(self,"_v_canipaccess"): del self._v_canipaccess if UP: for owner in self.getOwnerList(): owner.resetAccessCache(True, False) if DOWN: for session in self.getSessionList(): session.resetAccessCache(False, False) for cont in self.getContributionList(): cont.resetAccessCache(False, True) for mat in self.getMaterialList(): mat.resetAccessCache(False, True) def canAccess( self, aw ): """Tells whether an access wrapper is allowed to access the current conference: when the conference is protected, only if the user is a chair or is granted to access the conference, when the client ip is not restricted. """ try: return self._v_canaccess[aw] except AttributeError: self._v_canaccess = {} except KeyError: pass # Allow harvesters (Invenio, offline cache) to access # protected pages if self.__ac.isHarvesterIP(aw.getIP()): self._v_canaccess[aw] = True return True ##################################################### if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ): self._v_canaccess[aw] = False return False if not self.isProtected(): self._v_canaccess[aw] = True return True flag = self.isAllowedToAccess( aw.getUser() ) self._v_canaccess[aw] = flag or self.canKeyAccess( aw ) return self._v_canaccess[aw] def canKeyAccess( self, aw, key=None ): sess = aw.getSession() try: return self._v_cankeyaccess[aw] except AttributeError: self._v_cankeyaccess = {} except KeyError: pass accessKey = self.getAccessKey() if accessKey != "" and sess: if key and key == accessKey: return True keys = sess.getVar("accessKeys") if keys != None: if keys.has_key(self.getUniqueId()): if keys[self.getUniqueId()] == accessKey: self._v_cankeyaccess[aw] = True return True self._v_cankeyaccess[aw] = False return False def canKeyModify( self, aw ): sess = aw.getSession() try: return self._v_cankeymodify[aw] except AttributeError: self._v_cankeymodify = {} except KeyError: pass modifKey = self.getModifKey() if modifKey != "" and sess: keys = sess.getVar("modifKeys") if keys != None: if keys.has_key(self.id): if keys[self.id] == modifKey: self._v_cankeymodify[aw] = True return True self._v_cankeymodify[aw] = False return False def grantModification( self, prin, sendEmail=True ): email = None if isinstance(prin, ConferenceChair): email = prin.getEmail() elif isinstance(prin, str): email = prin if email != None: if email == "": return ah = AvatarHolder() results=ah.match({"email":email}, exact=1) #No registered user in Indico with that email if len(results) == 0: self.__ac.grantModificationEmail(email) if sendEmail and isinstance(prin, ConferenceChair): notif = pendingQueues._PendingConfManagerNotification( [prin] ) mail.GenericMailer.sendAndLog( notif, self.getConference() ) #The user is registered in Indico and is activated as well elif len(results) == 1 and results[0] is not None and results[0].isActivated(): self.__ac.grantModification(results[0]) results[0].linkTo(self, "manager") else: self.__ac.grantModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "manager") self.resetModifyCache() def revokeModification( self, prin ): self.__ac.revokeModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "manager") self.resetModifyCache() def canUserModify( self, av ): if av == None: return False try: return self._v_canusermodify[av] except AttributeError: self._v_canusermodify = {} except KeyError: pass if ( av == self.getCreator()) or self.getAccessController().canModify( av ): self._v_canusermodify[av] = True return True for owner in self.getOwnerList(): if owner.canUserModify( av ): self._v_canusermodify[av] = True return True self._v_canusermodify[av] = False return False def resetModifyCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canmodify"): del self._v_canmodify if hasattr(self,"_v_canusermodify"): del self._v_canusermodify if hasattr(self,"_v_cankeymodify"): del self._v_cankeymodify if UP and DOWN: self.resetAccessCache(UP, DOWN) if UP: for owner in self.getOwnerList(): owner.resetModifyCache(True, False) if DOWN: for session in self.getSessionList(): session.resetModifyCache(False, False) for cont in self.getContributionList(): cont.resetModifyCache(False, True) for mat in self.getMaterialList(): mat.resetModifyCache(False, True) def canModify( self, aw ): """Tells whether an access wrapper is allowed to modify the current conference: only if the user is granted to modify the conference and he is accessing from an IP address which is not restricted. """ try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.canUserModify( aw.getUser() ) or self.canKeyModify( aw ) return self._v_canmodify[aw] def getManagerList( self ): return self.__ac.getModifierList() def addToRegistrars(self, av): self.getRegistrarList().append(av) self.notifyModification() if isinstance(av, MaKaC.user.Avatar): av.linkTo(self, "registrar") def removeFromRegistrars(self, av): self.getRegistrarList().remove(av) self.notifyModification() if isinstance(av, MaKaC.user.Avatar): av.unlinkTo(self, "registrar") def isRegistrar(self, av): if av == None: return False try: return av in self.getRegistrarList() except AttributeError: return False def getRegistrarList(self): try: return self.__registrars except AttributeError: self.__registrars = [] return self.__registrars def canManageRegistration(self, av): return self.isRegistrar(av) or self.canUserModify(av) def getAllowedToAccessList( self ): return self.__ac.getAccessList() def addMaterial( self, newMat ): newMat.setId( str(self.__materialGenerator.newCount()) ) newMat.setOwner( self ) self.materials[ newMat.getId() ] = newMat self.notifyModification() def removeMaterial( self, mat ): if mat.getId() in self.materials.keys(): mat.delete() self.materials[mat.getId()].setOwner(None) del self.materials[ mat.getId() ] self.notifyModification() elif mat.getId().lower() == 'paper': self.removePaper() self.notifyModification() elif mat.getId().lower() == 'slides': self.removeSlides() self.notifyModification() elif mat.getId().lower() == 'minutes': self.removeMinutes() self.notifyModification() elif mat.getId().lower() == 'video': self.removeVideo() self.notifyModification() elif mat.getId().lower() == 'poster': self.removePoster() self.notifyModification() def recoverMaterial(self, recMat): # Id must already be set in recMat. recMat.setOwner(self) self.materials[recMat.getId()] = recMat recMat.recover() self.notifyModification() def getMaterialRegistry(self): """ Return the correct material registry for this type """ from MaKaC.webinterface.materialFactories import ConfMFRegistry return ConfMFRegistry def getMaterialById( self, matId ): if matId.lower() == 'paper': return self.getPaper() elif matId.lower() == 'slides': return self.getSlides() elif matId.lower() == 'video': return self.getVideo() elif matId.lower() == 'poster': return self.getPoster() elif matId.lower() == 'minutes': return self.getMinutes() elif self.materials.has_key(matId): return self.materials[ matId ] return None def getMaterialList( self ): return self.materials.values() def getAllMaterialList( self ): l = self.getMaterialList() if self.getPaper(): l.append( self.getPaper() ) if self.getSlides(): l.append( self.getSlides() ) if self.getVideo(): l.append( self.getVideo() ) if self.getPoster(): l.append( self.getPoster() ) if self.getMinutes(): l.append( self.getMinutes() ) l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle())) return l def setPaper( self, newPaper ): if self.getPaper() != None: raise MaKaCError( _("The paper for this conference has already been set"), _("Conference")) self.paper=newPaper self.paper.setOwner( self ) self.notifyModification() def removePaper( self ): if self.paper is None: return self.paper.delete() self.paper.setOwner(None) self.paper = None self.notifyModification() def recoverPaper(self, p): self.setPaper(p) p.recover() def getPaper( self ): try: if self.paper: pass except AttributeError: self.paper = None return self.paper def setSlides( self, newSlides ): if self.getSlides() != None: raise MaKaCError( _("The slides for this conference have already been set"), _("Conference")) self.slides=newSlides self.slides.setOwner( self ) self.notifyModification() def removeSlides( self ): if self.slides is None: return self.slides.delete() self.slides.setOwner( None ) self.slides= None self.notifyModification() def recoverSlides(self, s): self.setSlides(s) s.recover() def getSlides( self ): try: if self.slides: pass except AttributeError: self.slides = None return self.slides def setVideo( self, newVideo ): if self.getVideo() != None: raise MaKaCError( _("The video for this conference has already been set"), _("Conference")) self.video=newVideo self.video.setOwner( self ) self.notifyModification() def removeVideo( self ): if self.getVideo() is None: return self.video.delete() self.video.setOwner(None) self.video = None self.notifyModification() def recoverVideo(self, v): self.setVideo(v) v.recover() def getVideo( self ): try: if self.video: pass except AttributeError: self.video = None return self.video def setPoster( self, newPoster ): if self.getPoster() != None: raise MaKaCError( _("the poster for this conference has already been set"), _("Conference")) self.poster=newPoster self.poster.setOwner( self ) self.notifyModification() def removePoster( self ): if self.getPoster() is None: return self.poster.delete() self.poster.setOwner(None) self.poster = None self.notifyModification() def recoverPoster(self, p): self.setPoster(p) p.recover() def getPoster( self ): try: if self.poster: pass except AttributeError: self.poster = None return self.poster def setMinutes( self, newMinutes ): if self.getMinutes() != None: raise MaKaCError( _("The Minutes for this conference has already been set")) self.minutes=newMinutes self.minutes.setOwner( self ) self.notifyModification() def createMinutes( self ): if self.getMinutes() != None: raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference")) self.minutes = Minutes() self.minutes.setOwner( self ) self.notifyModification() return self.minutes def removeMinutes( self ): if self.getMinutes() is None: return self.minutes.delete() self.minutes.setOwner( None ) self.minutes = None self.notifyModification() def recoverMinutes(self, min): self.removeMinutes() # To ensure that the current minutes are put in # the trash can. self.minutes = min self.minutes.setOwner( self ) min.recover() self.notifyModification() return self.minutes def getMinutes( self ): #To be removed try: if self.minutes: pass except AttributeError, e: self.minutes = None return self.minutes def _setSchedule( self, sch=None ): self.__schedule=ConferenceSchedule(self) for session in self.getSessionList(): for slot in session.getSlotList(): self.__schedule.addEntry(slot.getConfSchEntry()) def getSchedule( self ): try: if not self.__schedule: self._setSchedule() except AttributeError, e: self._setSchedule() return self.__schedule def fit( self ): sch = self.getSchedule() sDate = sch.calculateStartDate() eDate = sch.calculateEndDate() self.setStartDate(sDate) self.setEndDate(eDate) def fitSlotsOnDay( self, day ): for entry in self.getSchedule().getEntriesOnDay(day) : if isinstance(entry.getOwner(), SessionSlot) : entry.getOwner().fit() def getDefaultStyle( self ): from MaKaC.webinterface import displayMgr return displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self).getDefaultStyle() def clone( self, startDate, options, eventManager=None ): # startDate must be in the timezone of the event (to avoid problems with daylight-saving times) cat = self.getOwnerList()[0] managing = options.get("managing",None) if managing is not None: creator = managing else: creator = self.getCreator() conf = cat.newConference(creator) if managing is not None : conf.grantModification(managing) conf.setTitle(self.getTitle()) conf.setDescription(self.getDescription()) conf.setTimezone(self.getTimezone()) for loc in self.getLocationList(): if loc is not None: conf.addLocation(loc.clone()) if self.getRoom() is not None: conf.setRoom(self.getRoom().clone()) startDate = timezone(self.getTimezone()).localize(startDate).astimezone(timezone('UTC')) timeDelta = startDate - self.getStartDate() endDate = self.getEndDate() + timeDelta conf.setDates( startDate, endDate, moveEntries=1 ) conf.setContactInfo(self.getContactInfo()) conf.setChairmanText(self.getChairmanText()) conf.setVisibility(self.getVisibility()) conf.setSupportEmail(self.getSupportEmail()) conf.setReportNumberHolder(self.getReportNumberHolder().clone(self)) for ch in self.getChairList(): conf.addChair(ch.clone()) # Display Manager from MaKaC.webinterface import displayMgr selfDispMgr=displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self) selfDispMgr.clone(conf) # Contribution Types' List (main detailes of the conference) for t in self.getContribTypeList() : conf.addContribType(t.clone(conf)) for item in self.getSections() : conf._sections.append(item) if options.get("sessions", False): for entry in self.getSchedule().getEntries(): if isinstance(entry,BreakTimeSchEntry): conf.getSchedule().addEntry(entry.clone(conf)) db_root = DBMgr.getInstance().getDBConnection().root() if db_root.has_key( "webfactoryregistry" ): confRegistry = db_root["webfactoryregistry"] else: confRegistry = OOBTree.OOBTree() db_root["webfactoryregistry"] = confRegistry meeting=False # if the event is a meeting or a lecture if confRegistry.get(str(self.getId()), None) is not None : meeting=True confRegistry[str(conf.getId())] = confRegistry[str(self.getId())] # if it's a conference, no web factory is needed # Tracks in a conference if options.get("tracks",False) : for tr in self.getTrackList() : conf.addTrack(tr.clone(conf)) # Meetings' and conferences' sessions cloning if options.get("sessions",False) : for s in self.getSessionList() : conf.addSession(s.clone(timeDelta, conf, options)) # Materials' cloning if options.get("materials",False) : for m in self.getMaterialList() : conf.addMaterial(m.clone(conf)) if self.getPaper() is not None: conf.setPaper(self.getPaper().clone(conf)) if self.getSlides() is not None: conf.setSlides(self.getSlides().clone(conf)) if self.getVideo() is not None: conf.setVideo(self.getVideo().clone(conf)) if self.getPoster() is not None: conf.setPoster(self.getPoster().clone(conf)) if self.getMinutes() is not None: conf.setMinutes(self.getMinutes().clone(conf)) # access and modification keys if options.get("keys", False) : conf.setAccessKey(self.getAccessKey()) conf.setModifKey(self.getModifKey()) # Access Control cloning if options.get("access",False) : conf.setProtection(self.isItselfProtected()) for mgr in self.getManagerList() : conf.grantModification(mgr) for user in self.getAllowedToAccessList() : conf.grantAccess(user) for right in self.getSessionCoordinatorRights(): conf.addSessionCoordinatorRight(right) for domain in self.getDomainList(): conf.requireDomain(domain) # conference's registration form if options.get("registration",False) : conf.setRegistrationForm(self.getRegistrationForm().clone(conf)) # conference's evaluation if options.get("evaluation",False) : #Modify this, if you have now many evaluations. #You will have to clone every evaluations of this conference. conf.setEvaluations([self.getEvaluation().clone(conf)]) #conference's abstracts if options.get("abstracts",False) : conf.abstractMgr = self.abstractMgr.clone(conf) # conference's alerts if options.get("alerts",False) : for alarm in self.getAlarmList() : conf.addAlarm(alarm.clone(conf)) # Meetings' and conferences' contributions cloning if options.get("contributions",False) : sch = conf.getSchedule() for cont in self.getContributionList(): if cont.getSession() is None : if not meeting: nc = cont.clone(conf, options, timeDelta) conf.addContribution(nc) if cont.isScheduled() : sch.addEntry(nc.getSchEntry()) elif cont.isScheduled(): # meetings...only scheduled nc = cont.clone(conf, options, timeDelta) conf.addContribution(nc) sch.addEntry(nc.getSchEntry()) # Participants' module settings and list cloning if options.get("participants",False) : self.getParticipation().clone(conf, options, eventManager) conf.notifyModification() return conf def newAlarm(self): al = Alarm(self) tl = HelperTaskList.getTaskListInstance() tl.addTask(al) self.alarmList[al.getId()] = al self._p_changed = 1 al.setOwner(self) return al def removeAlarm(self, alarm): if alarm in self.alarmList.values(): del self.alarmList[alarm.getId()] self._p_changed = 1 tl = HelperTaskList.getTaskListInstance() tl.removeTask(alarm) alarm.setOwner(None) alarm.delete() def addAlarm(self, alarm): tl = HelperTaskList.getTaskListInstance() tl.addTask(alarm) self.alarmList[alarm.getId()] = alarm self._p_changed = 1 alarm.setOwner(self) def recoverAlarm(self, alarm): self.addAlarm(alarm) alarm.conf = self alarm.recover() def getAlarmList(self): return self.alarmList.values() def getAlarmById(self, id): """For given id returns corresponding Alarm or None if not found.""" return self.alarmList.get(id, None) def getCoordinatedTracks( self, av ): """Returns a list with the tracks for which a user is coordinator. """ try: if self._trackCoordinators: pass except AttributeError: self._trackCoordinators = TCIndex() self.notifyModification() return self._trackCoordinators.getTracks( av ) def addTrackCoordinator( self, track, av ): """Makes a user become coordinator for a track. """ try: if self._trackCoordinators: pass except AttributeError: self._trackCoordinators = TCIndex() self.notifyModification() if track in self.program: track.addCoordinator( av ) self._trackCoordinators.indexCoordinator( av, track ) self.notifyModification() def removeTrackCoordinator( self, track, av ): """Removes a user as coordinator for a track. """ try: if self._trackCoordinators: pass except AttributeError: self._trackCoordinators = TCIndex() self.notifyModification() if track in self.program: track.removeCoordinator( av ) self._trackCoordinators.unindexCoordinator( av, track ) self.notifyModification() def _rebuildAuthorIndex(self): self._authorIdx=AuthorIndex() for contrib in self.getContributionList(): if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn): for auth in contrib.getAuthorList(): self._authorIdx.index(auth) def getAuthorIndex(self): try: if self._authorIdx: pass except AttributeError: self._rebuildAuthorIndex() return self._authorIdx def indexAuthor(self,auth): c=auth.getContribution() if c.isAuthor(auth): if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn): self.getAuthorIndex().index(auth) if c.isPrimaryAuthor(auth): self._getPrimAuthIndex().index(auth) def unindexAuthor(self,auth): c=auth.getContribution() if c.isAuthor(auth): self.getAuthorIndex().unindex(auth) if c.isPrimaryAuthor(auth): self._getPrimAuthIndex().unindex(auth) def _rebuildSpeakerIndex(self): self._speakerIdx=AuthorIndex() for contrib in self.getContributionList(): if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn): for auth in contrib.getSpeakerList(): self._speakerIdx.index(auth) for subcontrib in contrib.getSubContributionList(): for auth in subcontrib.getSpeakerList(): self._speakerIdx.index(auth) def getSpeakerIndex(self): try: if self._speakerIdx: pass except AttributeError: self._rebuildSpeakerIndex() return self._speakerIdx def indexSpeaker(self,auth): c=auth.getContribution() if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn): self.getSpeakerIndex().index(auth) def unindexSpeaker(self,auth): c=auth.getContribution() if c and not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn): self.getSpeakerIndex().unindex(auth) def getRegistrationForm(self): try: if self._registrationForm is None: self._registrationForm = registration.RegistrationForm(self) except AttributeError,e: self._registrationForm = registration.RegistrationForm(self) return self._registrationForm def setRegistrationForm(self,rf): self._registrationForm = rf rf.setConference(self) def removeRegistrationForm(self): try: self._registrationForm.delete() self._registrationForm.setConference(None) self._registrationForm = None except AttributeError: self._registrationForm = None def recoverRegistrationForm(self, rf): self.setRegistrationForm(rf) rf.recover() def getEvaluation(self, id=0): ############################################################################ #For the moment only one evaluation per conference is used. # #In the future if there are more than one evaluation, modify this function.# ############################################################################ """ Return the evaluation given by its ID or None if nothing found. Params: id -- id of the wanted evaluation """ for evaluation in self.getEvaluations(): if str(evaluation.getId()) == str(id) : return evaluation if HelperMaKaCInfo.getMaKaCInfoInstance().isDebugActive(): raise Exception(_("Error with id: expected '%s', found '%s'.")%(id, self.getEvaluations()[0].getId())) else: return self.getEvaluations()[0] def getEvaluations(self): if not hasattr(self, "_evaluations"): self._evaluations = [Evaluation(self)] return self._evaluations def setEvaluations(self, evaluationsList): self._evaluations = evaluationsList for evaluation in self._evaluations: evaluation.setConference(self) def removeEvaluation(self, evaluation): """remove the given evaluation from its evaluations.""" evaluations = self.getEvaluations() if evaluations.count(evaluation)>0: evaluations.remove(evaluation) evaluation.removeReferences() self.notifyModification() def removeAllEvaluations(self): for evaluation in self.getEvaluations(): evaluation.removeReferences() self._evaluations = [] self.notifyModification() def _getEvaluationCounter(self): if not hasattr(self, "_evaluationCounter"): self._evaluationCounter = Counter() return self._evaluationCounter ## Videoconference bookings related def getBookings(self): try: if self._bookings: pass except AttributeError, e: self._bookings = {} self.notifyModification() return self._bookings def getBookingsList(self, sort = False): bl = self.getBookings().values() if sort: bl.sort() return bl def _getBookingGenerator(self): try: return self._bookingGenerator except AttributeError, e: self._bookingGenerator = Counter() return self._bookingGenerator def getNewBookingId(self): return str(self._getBookingGenerator().newCount()) def addBooking(self, bp): if (bp.getId() == ""): bp.setId(self.getNewBookingId()) self.getBookings()[bp.getId()] = bp self.notifyModification() def hasBooking(self,booking): return booking.getConference()==self and \ self.getBookings().has_key(booking.getId()) def removeBooking(self, booking): if self.hasBooking(booking): deletion= booking.deleteBooking() if deletion[0] != 1: del self.getBookings()[booking.getId()] self.notifyModification() return deletion def getBookingByType(self, type): if self.getBookings().has_key(type): return self.getBookings()[type] return None def getBookingById(self, id): if self.getBookings().has_key(id): return self.getBookings()[id] return None ## End of Videoconference bookings related def getModPay(self): try: if self._modPay is None: self._modPay= epayment.EPayment(self) except AttributeError,e: self._modPay= epayment.EPayment(self) return self._modPay def getRegistrants(self): try: if self._registrants: pass except AttributeError, e: self._registrants = {} self.notifyModification() return self._registrants def getRegistrantsList(self, sort = False): rl = self.getRegistrants().values() if sort: rl.sort(registration.Registrant._cmpFamilyName) return rl def _getRegistrantGenerator(self): try: return self._registrantGenerator except AttributeError, e: self._registrantGenerator = Counter() return self._registrantGenerator def addRegistrant(self, rp): rp.setId( str(self._getRegistrantGenerator().newCount()) ) rp.setOwner( self ) self.getRegistrants()[rp.getId()] = rp self.notifyModification() def hasRegistrant(self,rp): return rp.getConference()==self and \ self.getRegistrants().has_key(rp.getId()) def hasRegistrantByEmail(self, email, registrant=None): # Return true if there is someone with the email of the param "email" but # the email has to be different to the one of the "registrant" (just in case we # try to modify the data of the registrant) for r in self.getRegistrantsList(): if r.getEmail().strip().lower() == email.strip().lower(): if registrant is not None and registrant.getEmail().strip().lower() == email.strip().lower(): continue return True return False def removeRegistrant(self, id): part = self.getRegistrants()[id] self._registrationForm.notifyRegistrantRemoval(self.getRegistrants()[id]) del self.getRegistrants()[id] if part.getAvatar() is not None: part.getAvatar().removeRegistrant(part) TrashCanManager().add(part) self.notifyModification() def getRegistrantById(self, id): if self.getRegistrants().has_key(id): return self.getRegistrants()[id] return None def _getPrimAuthIndex(self): try: if self._primAuthIdx: pass except AttributeError: self._primAuthIdx=_PrimAuthIdx(self) return self._primAuthIdx def getContribsMatchingAuth(self,query,onlyPrimary=True): if str(query).strip()=="": return self.getContributionList() res=self._getPrimAuthIndex().match(query) return [self.getContributionById(id) for id in res] def getCoordinatedSessions( self, av ): """Returns a list with the sessions for which a user is coordinator. """ try: if self._sessionCoordinators: pass except AttributeError: self._sessionCoordinators = SCIndex() sessions = self._sessionCoordinators.getSessions( av ) for session in self.getSessionList(): if session not in sessions and av != None: for email in av.getEmails(): if email in session.getCoordinatorEmailList(): sessions.append(session) break return sessions def getManagedSession( self, av ): ls = [] for session in self.getSessionList(): pending = False if av != None: for email in av.getEmails(): if email in session.getAccessController().getModificationEmail(): pending = True break if av in session.getManagerList() or pending: ls.append(session) return ls def addSessionCoordinator(self,session,av): """Makes a user become coordinator for a session. """ try: if self._sessionCoordinators: pass except AttributeError: self._sessionCoordinators = SCIndex() if self.sessions.has_key(session.getId()): session.addCoordinator(av) self._sessionCoordinators.index(av,session) def removeSessionCoordinator( self, session, av ): """Removes a user as coordinator for a session. """ try: if self._sessionCoordinators: pass except AttributeError: self._sessionCoordinators = SCIndex() if self.sessions.has_key(session.getId()): session.removeCoordinator( av ) self._sessionCoordinators.unindex(av,session) def _getSubmitterIdx(self): try: return self._submitterIdx except AttributeError: self._submitterIdx=SubmitterIndex() return self._submitterIdx def addContribSubmitter(self,contrib,av): self._getSubmitterIdx().index(av,contrib) def removeContribSubmitter(self,contrib,av): self._getSubmitterIdx().unindex(av,contrib) def getContribsForSubmitter(self,av): return self._getSubmitterIdx().getContributions(av) def getBOAConfig(self): try: if self._boa: pass except AttributeError: self._boa=BOAConfig(self) return self._boa def getSessionCoordinatorRights(self): try: if self._sessionCoordinatorRights: pass except AttributeError, e: self._sessionCoordinatorRights = [] self.notifyModification() return self._sessionCoordinatorRights def hasSessionCoordinatorRight(self, right): return right in self.getSessionCoordinatorRights() def addSessionCoordinatorRight(self, right): if SessionCoordinatorRights().hasRight(right) and not self.hasSessionCoordinatorRight(right): self._sessionCoordinatorRights.append(right) self.notifyModification() def removeSessionCoordinatorRight(self, right): if SessionCoordinatorRights().hasRight(right) and self.hasSessionCoordinatorRight(right): self._sessionCoordinatorRights.remove(right) self.notifyModification() def getSections(self): try: if self._sections: pass except AttributeError, e: self._sections = ConfSectionsMgr().getSectionKeys() self.notifyModification() return self._sections def hasEnabledSection(self, section): # This hack is there since there is no more enable/disable boxes # in the conference managment area corresponding to those features. # Until the managment area is improved to get a more user-friendly # way of enabling/disabling those features, we always make them # available for the time being, but we keep the previous code for # further improvements #return section in self.getSections() if section in ["paperReviewing"] : return False else : return True def enableSection(self, section): if ConfSectionsMgr().hasSection(section) and not self.hasEnabledSection(section): self._sections.append(section) self.notifyModification() def disableSection(self, section): if ConfSectionsMgr().hasSection(section) and self.hasEnabledSection(section): self._sections.remove(section) self.notifyModification() def getPendingQueuesMgr(self): try: if self._pendingQueuesMgr: pass except AttributeError, e: self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self) return self._pendingQueuesMgr def getAccessController(self): return self.__ac def _cmpTitle( c1, c2 ): o1 = c1.getTitle().lower().strip() o2 = c2.getTitle().lower().strip() return cmp( o1, o2 ) _cmpTitle=staticmethod(_cmpTitle) def getReportNumberHolder(self): try: if self._reportNumberHolder: pass except AttributeError, e: self._reportNumberHolder=ReportNumberHolder(self) return self._reportNumberHolder def setReportNumberHolder(self, rnh): self._reportNumberHolder=rnh def getBadgeTemplateManager(self): try: if self.__badgeTemplateManager: pass except AttributeError: self.__badgeTemplateManager = BadgeTemplateManager(self) return self.__badgeTemplateManager def setBadgeTemplateManager(self, badgeTemplateManager): self.__badgeTemplateManager = badgeTemplateManager def getPosterTemplateManager(self): try: if self.__posterTemplateManager: pass except AttributeError: self.__posterTemplateManager = PosterTemplateManager(self) return self.__posterTemplateManager def setPosterTemplateManager(self, posterTemplateManager): self.__posterTemplateManager = posterTemplateManager def getCSBookingManager(self): if PluginsHolder().hasPluginType("Collaboration"): if not hasattr(self, "_CSBookingManager"): from MaKaC.plugins.Collaboration.base import CSBookingManager self._CSBookingManager = CSBookingManager(self) return self._CSBookingManager else: return None class DefaultConference(Conference): """ 'default' conference, which stores the default templates for posters and badges """ def notifyOAIModification(self, date=None, updateChildren=False): pass def indexConf(self): pass def __init__(self): """ Default constructor """ try: Conference.__init__(self, AdminList.getInstance().getList()[0], "default") except IndexError: raise MaKaCError(_("""There are no admin users. The "default" conference that stores the template cannot be created. Please add at least 1 user to the admin list.""")) class ConferenceHolder( ObjectHolder ): """Specialised ObjectHolder dealing with conference objects. It gives a common entry point and provides simple methods to access and maintain the collection of stored conferences (DB). """ idxName = "conferences" counterName = "CONFERENCE" def _newId( self ): id = ObjectHolder._newId( self ) return "%s"%id def getByStartDate( self, sday, eday = None ): # XXX This function seems strange? res=[] sDayStart=datetime(sday.year,sday.month,sday.day,0,0) sDayEnd=datetime(sday.year,sday.month,sday.day,23,59) for conf in self.getList(): if sday>=sDayStart and sdat<=sDayEnd: res.append(conf) return conf def getById( self, id ): """returns an object from the index which id corresponds to the one which is specified. """ if (id == "default"): return CategoryManager().getDefaultConference() if type(id) is int: id = str(id) if self._getIdx().has_key(str(id)): return self._getIdx()[str(id)] else: raise MaKaCError( _("Event id %s does not exist") % str(id) ) class ConfSectionsMgr: def __init__(self): self._sections = { "cfa": _("Call for abstracts"), #TODO: comment the following line to make the Paper Reviewing module not appear "paperReviewing" : _("Paper Reviewing"), "evaluation": _("Evaluation Form"), "videoconference": _("Videoconference"), # only for meetings "collaboration": _("Collaboration"), # only for meetings "regForm": _("Registration Form") } def hasSection(self, s): # This hack is there since there is no more enable/disable boxes # in the conference managment area corresponding to those features. # Until the managment area is improved to get a more user-friendly # way of enabling/disabling those features, we always make them # available in the side menu for the time being, but we keep # the previous code for further improvements #return self._sections.has_key(s) return True def getSections(self): return self._sections def getSectionList(self, sort=False): l=self._sections.values() if sort: l.sort() return l def getSectionKeys(self): return self._sections.keys() def getSection(self, id): if self._sections.has_key(id): return self._sections[id] return None class Observer(object): """ Base class for Observer objects. Inheriting classes should overload the following boolean class attributes: _shouldBeTitleNotified _shouldBeDateChangeNotified _shouldBeDeletionNotified And set them to True if they want to be notified of the corresponding event. In that case, they also have to implement the corresponding methods: _notifyTitleChange (for title notification) _notifyEventDateChanges and _notifyTimezoneChange (for date / timezone notification) _notifyDeletion (for deletion notification). The interface for those methods is also specified in this class. If the corresponding class attribute is set to False but the method is not implemented, an exception will be thrown. """ _shouldBeTitleNotified = False _shouldBeDateChangeNotified = False _shouldBeDeletionNotified = False def getObserverName(self): name = "'Observer of class" + self.__class__.__name__ try: conf = self.getOwner() name = name + " of event " + conf.getId() + "'" except AttributeError: pass return name def notifyTitleChange(self, oldTitle, newTitle): if self._shouldBeTitleNotified: self._notifyTitleChange(oldTitle, newTitle) def notifyEventDateChanges(self, oldStartDate = None, newStartDate = None, oldEndDate = None, newEndDate = None): if self._shouldBeDateChangeNotified: self._notifyEventDateChanges(oldStartDate, newStartDate, oldEndDate, newEndDate) def notifyTimezoneChange(self, oldTimezone, newTimezone): if self._shouldBeDateChangeNotified: self._notifyTimezoneChange(oldTimezone, newTimezone) def notifyDeletion(self): if self._shouldBeDeletionNotified: self._notifyDeletion() def _notifyTitleChange(self, oldTitle, newTitle): """ To be implemented by inheriting classes Notifies the observer that the Conference object's title has changed """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method _notifyTitleChange") def _notifyEventDateChanges(self, oldStartDate, newStartDate, oldEndDate, newEndDate): """ To be implemented by inheriting classes Notifies the observer that the start and / or end dates of the object it is attached to has changed. If the observer finds any problems during whatever he needs to do as a consequence of the event dates changing, he should write strings describing the problems in the 'dateChangeNotificationProblems' context variable (which is a list of strings). """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyStartDateChange") def _notifyTimezoneChange(self, oldTimezone, newTimezone): """ To be implemented by inheriting classes. Notifies the observer that the end date of the object it is attached to has changed. This method has to return a list of strings describing problems encountered during whatever the DateChangeObserver object does as a consequence of the notification. If there are no problems, the DateChangeObserver should return an empty list. """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTimezoneChange") def _notifyDeletion(self): """ To be implemented by inheriting classes Notifies the observer that the Conference object it is attached to has been deleted """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyDeletion") class TitleChangeObserver(Observer): """ Base class for objects who want to be notified of a Conference object being deleted. Inheriting classes have to implement the notifyTitleChange method, and probably the __init__ method too. """ def notifyTitleChange(self, oldTitle, newTitle): """ To be implemented by inheriting classes Notifies the observer that the Conference object's title has changed """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTitleChange") class DateChangeObserver(Observer): """ Base class for objects who want to be notified of a change in the start date / end date of an object (for example a Conference object). Inheriting classes have to implement the notifyStartDateChange and notifyEndDateChange methods, and probably the __init__ method too. """ def notifyEventDateChanges(self, oldStartDate = None, newStartDate = None, oldEndDate = None, newEndDate = None): """ To be implemented by inheriting classes Notifies the observer that the start and / or end dates of the object it is attached to has changed. If the observer finds any problems during whatever he needs to do as a consequence of the event dates changing, he should write strings describing the problems in the 'dateChangeNotificationProblems' context variable (which is a list of strings). """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyStartDateChange") def notifyTimezoneChange(self, oldTimezone, newTimezone): """ To be implemented by inheriting classes. Notifies the observer that the end date of the object it is attached to has changed. This method has to return a list of strings describing problems encountered during whatever the DateChangeObserver object does as a consequence of the notification. If there are no problems, the DateChangeObserver should return an empty list. """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTimezoneChange") class DeleteObserver(Observer): """ Base class for objects who want to be notified of a Conference object being deleted. Inheriting classes have to implement the notifyDeletion method, and probably the __init__ method too. """ def notifyDeletion(self): """ To be implemented by inheriting classes Notifies the observer that the Conference object it is attached to has been deleted """ raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyDeletion") class SessionChair(ConferenceParticipation): def __init__(self): self._session=None self._id="" ConferenceParticipation.__init__(self) def _notifyModification( self ): if self._session != None: self._session.notifyModification() def clone(self): chair = SessionChair() chair.setValues(self.getValues()) return chair def getSession(self): return self._session def getConference(self): s=self.getSession() if s is None: return None return s.getConference() def includeInSession(self,session,id): if self.getSession()==session and self.getId()==id.strip(): return self._session=session self._id=id def delete( self ): self._session=None ConferenceParticipation.delete(self) def getLocator(self): if self.getSession() is None: return None loc=self.getSession().getLocator() loc["convId"]=self.getId() return loc class SlotChair(ConferenceParticipation): def __init__(self): self._slot=None self._id="" ConferenceParticipation.__init__(self) def _notifyModification( self ): if self._slot != None: self._slot.notifyModification() def clone(self): chair = SlotChair() chair.setValues(self.getValues()) return chair def getSlot(self): return self._slot def getSession(self): s=self.getSlot() if s is None: return None return s.getSession() def getConference(self): s=self.getSlot() if s is None: return None return s.getConference() def includeInSlot(self,slot,id): if self.getSlot()==slot and self.getId()==id.strip(): return self._slot=slot self._id=id def delete( self ): self._slot=None ConferenceParticipation.delete(self) def getLocator(self): if self.getSlot() is None: return None loc=self.getSlot().getLocator() loc["convId"]=self.getId() return loc class SessionCoordinatorRights: def __init__(self): self._rights = {"modifContribs": _("Modify the contributions"), \ "unrestrictedSessionTT": _("Unrestricted session timetable management") } def hasRight(self, r): return self._rights.has_key(r) def getRights(self): return self._rights def getRightList(self, sort=False): l=self._rights.values() if sort: l.sort() return l def getRightKeys(self): return self._rights.keys() def getRight(self, id): if self._rights.has_key(id): return self._rights[id] return None class SCIndex(Persistent): """Index for conference session coordinators. This class allows to index conference session coordinators so the owner can answer optimally to the query if a user is coordinating any conference session. It is implemented by simply using a BTree where the Avatar id is used as key (because it is unique and non variable) and a list of coordinated sessions is kept as keys. It is the responsability of the index owner (conference) to keep it up-to-date i.e. notify session coordinator additions and removals. """ def __init__( self ): self._idx=OOBTree() def getSessions(self,av): """Gives a list with the sessions a user is coordinating. """ if av == None: return [] return self._idx.get(av.getId(),[]) def index(self,av,session): """Registers in the index a coordinator of a session. """ if av == None or session == None: return if not self._idx.has_key(av.getId()): l=[] self._idx[av.getId()]=l else: l=self._idx[av.getId()] if session not in l: l.append(session) self.notifyModification() def unindex(self,av,session): if av==None or session==None: return l=self._idx.get(av.getId(),[]) if session in l: l.remove(session) self.notifyModification() def notifyModification(self): self._idx._p_changed=1 class Session(Persistent, Fossilizable, CommonObjectBase): """This class implements a conference session, being the different parts in which the conference can be divided and the contributions can be organised in. The class contains necessary attributes to store session basic data and provides the operations related to sessions. In principle, a session has no sense to exist without being related to a conference but it is allowed for flexibility. """ fossilizes(ISessionFossil) def __init__(self, **sessionData): """Class constructor. Initialise the class attributes to the default values. Params: sessionData -- (Dict) Contains the data the session object has to be initialised to. """ self.conference=None self.id="not assigned" self.title="" self.description="" ################################# # Fermi timezone awareness # ################################# self.startDate = nowutc() ################################# # Fermi timezone awareness(end) # ################################# self.duration=timedelta(minutes=1) self.places=[] self.rooms=[] self.conveners=[] # This attribute must not be used and should disappear someday self._conveners=[] self._convenerGen=Counter() self.convenerText="" self.contributions={} self._contributionDuration=timedelta(minutes=20) self.__ac=AccessController() self.materials={} self.__materialGenerator=Counter() self.minutes=None self._comments = "" self.slots={} self.__slotGenerator=Counter() self._setSchedule() self._coordinators=OOBTree() self._coordinatorsEmail = [] self._code="" self._color="#e3f2d3" self._textColor="#202020" self._textColorToLinks=False self._ttType=SlotSchTypeFactory.getDefaultId() self._closed = False self._registrationSession = None self._creationDS = nowutc() self._modificationDS = nowutc() self._keywords = "" def getTimezone( self ): return self.getConference().getTimezone() def isFullyPublic( self ): if hasattr(self, "_fullyPublic"): return self._fullyPublic else: self.setFullyPublic() return self._fullyPublic def setFullyPublic( self ): if self.isProtected(): self._fullyPublic = False self._p_changed = 1 return for res in self.getAllMaterialList(): if not res.isFullyPublic(): self._fullyPublic = False self._p_changed = 1 return for res in self.getContributionList(): if not res.isFullyPublic(): self._fullyPublic = False self._p_changed = 1 return self._fullyPublic = True self._p_changed = 1 def updateFullyPublic( self ): self.setFullyPublic() self.getOwner().updateFullyPublic() def getKeywords(self): try: return self._keywords except: self._keywords = "" return "" def setKeywords(self, keywords): self._keywords = keywords def notifyModification( self, date=None ): """Method called to notify the current session has been modified. """ if not date: date = nowutc() self._modificationDS = date parent = self.getConference() if parent: parent.notifyModification() self._p_changed=1 def getModificationDate( self ): """Returns the date in which the session was last modified""" try: return self._modificationDS except: self._modificationDS = nowutc() return self._modificationDS def getCreationDate( self ): """Returns the date in which the session was created""" try: return self._creationDS except: self._creationDS = nowutc() return self._creationDS def getLogInfo(self): data = {} data["subject"] = self.title data["session id"] = self.id data["session code"] = self._code data["title"] = self.title data["description"] = self.description data["start date"] = self.startDate data["duration"] = self.duration for p in self.places : data["place"] = p.getName() for r in self.rooms : data["room"] = r.getName() for sc in self.getConvenerList() : data["convener %s"%sc.getId()] = sc.getFullName() for co in self.getCoordinatorList() : data["contribution %s"%co.getId()] = co.getFullName() for s in self.getSlotList() : data["contribution %s"%s.getId()] = s.getTitle() for c in self.getContributionList() : data["contribution %s"%c.getId()] = c.getTitle() return data def getEnableSessionSlots(self): try: return self.getConference().getEnableSessionSlots() except: return True def cmpSessionByTitle(session1, session2): return cmp(session1.getTitle(), session2.getTitle()) cmpSessionByTitle = staticmethod(cmpSessionByTitle) def hasRegistrationSession(self): return self.getRegistrationSession() is not None def getRegistrationSession(self): try: if self._registrationSession: pass except AttributeError, e: self._registrationSession = None return self._registrationSession def setRegistrationSession(self, rs): self._registrationSession = rs def isClosed( self ): if self.getConference().isClosed(): return True try: return self._closed except: self._closed = False return False def setClosed( self, closed=True ): self._closed = closed self.notifyModification() def includeInConference(self,conf,newId): self.conference=conf self.id=newId for slot in self.getSlotList(): conf.getSchedule().addEntry(slot.getConfSchEntry(),2) self.getConference().addSession(self) self.notifyModification() def delete(self): while len(self.getConvenerList()) > 0: self.removeConvener(self.getConvenerList()[0]) while len(self.getMaterialList()) > 0: self.removeMaterial(self.getMaterialList()[0]) self.removeMinutes() for c in self.getCoordinatorList()[:]: self.removeCoordinator(c) while len(self.contributions.values())>0: self.removeContribution(self.contributions.values()[0]) while len(self.slots.values())>0: self._removeSlot(self.slots.values()[0]) if self.getConference() is not None: self.getConference().removeSession(self) if self.hasRegistrationSession(): self.getConference().getRegistrationForm().getSessionsForm().removeSession(self.getId()) self.getRegistrationSession().setRegistrationForm(None) TrashCanManager().add(self.getRegistrationSession()) self.conference=None TrashCanManager().add(self) def recover(self, isCancelled): if self.hasRegistrationSession(): if not isCancelled: self.getRegistrationSession().setRegistrationForm(self.getConference().getRegistrationForm()) self.getConference().getRegistrationForm().getSessionsForm().addSession(self.getRegistrationSession()) TrashCanManager().remove(self.getRegistrationSession()) TrashCanManager().remove(self) def getLocator( self ): """Gives back a globaly unique identification encapsulated in a Locator object for the session instance """ if self.conference == None: return Locator() lconf = self.conference.getLocator() lconf["sessionId"] = self.getId() return lconf def getConference( self ): return self.conference def getSession( self ): return self def getOwner( self ): return self.getConference() def getId( self ): return self.id def getUniqueId( self ): """returns (string) the unique identiffier of the item""" """used mainly in the web session access key table""" return "%ss%s" % (self.getConference().getUniqueId(),self.id) def getModifKey( self ): return self.getConference().getModifKey() def getAccessKey( self ): return self.getConference().getAccessKey() def getContribDuration(self): try: return self._contributionDuration except: self._contributionDuration = timedelta(minutes=20) return self._contributionDuration def setContribDuration(self, hour=0, min=20, dur=None): if dur is not None: self._contributionDuration=dur else: self._contributionDuration = timedelta(hours=hour,minutes=min) def fit(self): #if not self.getConference().getEnableSessionSlots(): # self.getSlotList()[0].fit() self.setStartDate(self.getMinSlotStartDate(),0,0) self.setEndDate(self.getMaxSlotEndDate(),0) def addSlot(self,newSlot): id = newSlot.getId() if id == "not assigned": newSlot.setId(str(self.__slotGenerator.newCount())) self.slots[newSlot.getId()]=newSlot self.fit() self.getSchedule().addEntry(newSlot.getSessionSchEntry(),2) if self.getConference() is not None: self.getConference().getSchedule().addEntry(newSlot.getConfSchEntry(),2) self.notifyModification() def _removeSlot(self,slot): del self.slots[slot.getId()] self.getSchedule().removeEntry(slot.getSessionSchEntry()) if self.getConference() is not None: self.getConference().getSchedule().removeEntry(slot.getConfSchEntry()) slot.delete() def removeSlot(self, slot, force=False): if self.slots.has_key(slot.getId()): if len(self.slots)==1 and not force: raise MaKaCError( _("A session must have at least one slot"), _("Session")) self._removeSlot(slot) self.fit() self.notifyModification() def recoverSlot(self, slot): self.addSlot(slot) slot.recover() def getSlotById(self,slotId): return self.slots.get(slotId,None) def getSlotList(self): return self.slots.values() def getSortedSlotList(self): sl = self.getSlotList() sl.sort(utils.sortSlotByDate) return sl def getMinSlotStartTime(self): min = (25,61) for slot in self.getSlotList(): if slot.isMoreThanDay(): return (0,0) shour = slot.getStartDate().hour smin = slot.getStartDate().minute if (shour, smin) < min: min = (shour, smin) return min def getMaxSlotEndTime(self): max = (-1,-1) for slot in self.getSlotList(): if slot.isMoreThanDay(): return (23, 59) endDate = slot.getEndDate() if (endDate.hour, endDate.minute) > max: newEndDate = endDate - timedelta(0, 0, 0) max = (newEndDate.hour, newEndDate.minute) return max def getMinSlotStartDate(self): slotList = self.getSlotList() if len(slotList)==0: return self.getStartDate() else: sDate = self.getEndDate() for slot in slotList: if slot.getStartDate() < sDate: sDate = slot.getStartDate() return sDate def getMaxSlotEndDate(self): slotList = self.getSlotList() if len(slotList)==0: return self.getEndDate() else: eDate = self.getStartDate() for slot in slotList: if slot.getEndDate() > eDate: eDate = slot.getEndDate() return eDate def _getCorrectColor(self, color): if not color.startswith("#"): color = "#%s"%color m = re.match("^#[0-9A-Fa-f]{6}$", color) if m: return color return None def _getCorrectBgColor(self, color): color=self._getCorrectColor(color) if color is None: return self._color return color def _getCorrectTextColor(self, color): color=self._getCorrectColor(color) if color is None: return self._textColor return color def setValues( self, sessionData,check=2,moveEntries=0 ): """Sets all the values of the current session object from a dictionary containing the following key-value pairs: title-(str) description-(str) locationName-(str) => name of the location, if not specified it will be set to the conference location name. locationAddress-(str) roomName-(str) => name of the room, if not specified it will be set to the conference room name. sDate - (datetime) => starting date of the session, if not specified it will be set to now. eDate - (datetime) => ending date of the session, if not specified the end date will be set to the start one durHour - (int) => hours of duration for each entry in the session by default. durMin - (int) => hours of duration for each entry in the session by default. _conveners - (str) check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates Please, note that this method sets ALL values which means that if the given dictionary doesn't contain any of the keys the value will set to a default value. """ self.setTitle( sessionData.get("title", _("NO TITLE ASSIGNED")) ) self.setDescription( sessionData.get("description", "") ) code = sessionData.get("code", "") if code.strip() == "": if self.getId()=="not assigned": self.setCode("no code") else: self.setCode(self.getId()) else: self.setCode(code) bgcolor = sessionData.get("backgroundColor", "") if bgcolor.strip() != "": self.setColor(self._getCorrectBgColor(bgcolor)) textcolor = sessionData.get("textColor", "") if textcolor.strip() != "": if sessionData.has_key("autotextcolor"): self.setTextColor(utils.getTextColorFromBackgroundColor(self.getColor())) else: self.setTextColor(self._getCorrectTextColor(textcolor)) self.setTextColorToLinks(sessionData.has_key("textcolortolinks")) if "locationName" in sessionData: loc = self.getOwnLocation() if not loc: loc = CustomLocation() self.setLocation( loc ) loc.setName( sessionData["locationName"] ) loc.setAddress( sessionData.get("locationAddress", "") ) else: self.setLocation(None) #same as for the location if "roomName" in sessionData: room = self.getOwnRoom() if not room: room = CustomRoom() self.setRoom( room ) room.setName( sessionData["roomName"] ) else: self.setRoom(None) if sessionData.get("sDate",None) is not None: self.setStartDate(sessionData["sDate"],check,moveEntries=moveEntries) if sessionData.get("eDate",None) is not None: self.setEndDate(sessionData["eDate"],check) self._checkInnerSchedule() if sessionData.get("contribDuration","")!="": self._contributionDuration = sessionData.get("contribDuration") else: self._contributionDuration = timedelta(hours=int(sessionData.get("durHour",0)), minutes=int(sessionData.get("durMin",20))) self.notifyModification() def move(self, sDate): """ Move a session from the old start date to a new start date, and it moves all the entries of the session as well, without date validations. """ if sDate is not None: oldStartDate=self.startDate self.startDate=copy.copy(sDate) diff=self.startDate-oldStartDate # Check date to not be prior conference start date and to not surpass conference end date # The schedule is returning the datetime object as timezone aware relative to the conference # timezone. Must adjust the startdate accordingly for comparison. JMF conftz = self.getConference().getTimezone() if self.getStartDate() < self.getConference().getSchedule().getStartDate() or \ self.getEndDate() > self.getConference().getSchedule().getEndDate(): raise MaKaCError( _("Impossible to move the session because it would be out of the conference dates")) for entry in self.getSchedule().getEntries(): if isinstance(entry,LinkedTimeSchEntry) and \ isinstance(entry.getOwner(), SessionSlot): e = entry.getOwner() e.move(e.getStartDate() + diff) self.getSchedule().reSchedule() self.getConference().getSchedule().reSchedule() self.notifyModification() def clone(self, deltaTime, conf, options): ses = Session() conf.addSession(ses,check=0) ses.setTitle(self.getTitle()) ses.setDescription(self.getDescription()) startDate = self.getStartDate() + deltaTime ses.setStartDate(startDate, check=1) ses.setDuration(dur=self.getDuration()) if self.getOwnLocation() is not None: ses.addLocation(self.getOwnLocation().clone()) if self.getOwnRoom() is not None: ses.setRoom(self.getOwnRoom().clone()) for conv in self.getConvenerList(): ses.addConvener(conv.clone()) ses.setConvenerText(self.getConvenerText()) ses.setColor(self.getColor()) ses.setTextColor(self.getTextColor()) ses.setTextColorToLinks(self.isTextColorToLinks()) ses.setCode(self.getCode()) ses.setContribDuration(dur=self.getContribDuration()) ses.setScheduleType(self.getScheduleType()) ses.setComments(self.getComments()) # Access Control cloning if options.get("access", False) : ses.setProtection(self.isItselfProtected()) for mgr in self.getManagerList() : ses.grantModification(mgr) for user in self.getAllowedToAccessList() : ses.grantAccess(user) for domain in self.getDomainList(): ses.requireDomain(domain) for coord in self.getCoordinatorList(): ses.addCoordinator(coord) #slots in timeschedule for slot in self.getSlotList() : newslot = slot.clone(ses, options) ses.addSlot(newslot) ses.notifyModification() return ses def setTitle( self, newTitle ): self.title = newTitle self.notifyModification() def getTitle( self ): return self.title def setDescription(self, newDescription ): self.description = newDescription self.notifyModification() def getDescription(self): return self.description def getCode(self): try: if self._code: pass except AttributeError: self._code=self.id return self._code def setCode(self,newCode): self._code=str(newCode).strip() def getColor(self): try: if self._color: pass except AttributeError: self._color="#e3f2d3" return self._color getBgColor=getColor def setColor(self,newColor): self._color=str(newColor).strip() setBgColor=setColor def getTextColor(self): try: if self._textColor: pass except AttributeError: self._textColor="#202020" return self._textColor def setTextColor(self,newColor): self._textColor=str(newColor).strip() def isTextColorToLinks(self): try: if self._textColorToLink: pass except AttributeError: self._textColorToLink=False return self._textColorToLink def setTextColorToLinks(self, v): self._textColorToLink=v def getStartDate(self): return self.startDate def getAdjustedStartDate(self,tz=None): if not tz: tz = self.getConference().getTimezone() if tz not in all_timezones: tz = 'UTC' return self.startDate.astimezone(timezone(tz)) def verifyStartDate(self, sdate, check=2): """check parameter: 0: no check at all 1: check and raise error in case of problem (default) 2: check and adapt the owner dates """ conf=self.getConference() if conf is not None and sdate < conf.getSchedule().getStartDate(): if check==1: raise ParentTimingError( _("The session starting date cannot be prior to the event starting date"), _("Session")) elif check==2: ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED", conf, sdate.astimezone(timezone(conf.getTimezone())))) conf.setStartDate(sdate,check=0,moveEntries=0) def setStartDate(self,newDate,check=2,moveEntries=0): """ moveEntries parameter: 0: do not move inner slots 1: move 2: do not move but check that session is not out of the conference dates """ if not newDate.tzname(): raise MaKaCError("date should be timezone aware") if check != 0: self.verifyStartDate(newDate,check) oldSdate = self.getStartDate() try: tz = str(self.getStartDate().tzinfo) except: tz = 'UTC' diff = newDate - oldSdate self.startDate=copy.copy(newDate) if moveEntries == 1 and diff is not None and diff != timedelta(0): # If the start date changed, we move entries inside the timetable newDateTz = newDate.astimezone(timezone(tz)) if oldSdate.astimezone(timezone(tz)).date() != newDateTz.date(): entries = self.getSchedule().getEntries()[:] else: entries = self.getSchedule().getEntriesOnDay(newDateTz)[:] self.getSchedule().moveEntriesBelow(diff, entries) if moveEntries != 0 and self.getConference() and \ not self.getConference().getEnableSessionSlots() and \ self.getSlotList() != [] and \ self.getSlotList()[0].getStartDate() != newDate: self.getSlotList()[0].startDate = newDate if check == 1: self._checkInnerSchedule() self.notifyModification() def _checkInnerSchedule( self ): self.getSchedule().checkSanity() def getEndDate(self): return self.startDate+self.duration #################################### # Fermi timezone awareness # #################################### def getAdjustedEndDate(self,tz=None): return self.getAdjustedStartDate(tz) + self.duration #################################### # Fermi timezone awareness(end) # #################################### def verifyEndDate(self, edate,check=1): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates """ try: tz = timezone(self.getConference().getTimezone()) except: tz = timezone('UTC') # compare end date with start date if edate<=self.getStartDate(): if check == 1: raise MaKaCError( _("End date cannot be prior to the Start date"), _("Session")) if check == 2: self.setStartDate(edate) # check conference dates if (self.getConference()): conf=self.getConference() confStartDate = conf.getSchedule().getStartDate() confEndDate = conf.getSchedule().getEndDate() if conf is not None and (edate>confEndDate or edate<=confStartDate): if check==1: raise ParentTimingError( _("The end date has to be between the event dates (%s - %s)")%\ (confStartDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ confEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\ _("Session")) if check==2: if edate>confEndDate: ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED", self.getConference(), edate.astimezone(tz))) self.getConference().setEndDate(edate) if edate<=confStartDate: ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED", self.getConference(), edate.astimezone(tz))) self.getConference().setStartDate(edate) # check inner schedule if len(self.getSlotList()) != 0 and self.getSlotList()[-1].getSchedule().hasEntriesAfter(edate): raise TimingError( _("Cannot change end date: some entries in the session schedule end after the new date"), _("Session")) def setEndDate(self,newDate,check=2): if not newDate.tzname(): raise MaKaCError("date should be timezone aware") if check != 0: self.verifyEndDate(newDate,check) self.duration=newDate-self.getStartDate() # A session is not always linked to a conference (for eg. at creation time) #if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSlotList()[0].getEndDate() != newDate: # self.getSlotList()[0].duration = self.duration self.notifyModification() def setDates(self,sDate,eDate,check=1,moveEntries=0): if eDate<=sDate: tz = timezone(self.getConference().getTimezone()) raise MaKaCError(_("The end date (%s) cannot be prior to the start date (%s)") % (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),_("Session")) self.setStartDate(sDate,check,moveEntries) self.setEndDate(eDate,check) self._checkInnerSchedule() def getDuration( self ): return self.duration def setDuration(self,hours=0,minutes=15,dur=0): if dur==0: dur = timedelta(hours=int(hours),minutes=int(minutes)) if dur.seconds <= 0: raise MaKaCError( _("The duration cannot be less than zero"), _("Session")) self.duration = dur self.verifyEndDate(self.getEndDate()) self.notifyModification() def getStartOnDay(self, day, tz=None): if not tz: tz = self.getConference().getTimezone() if type(day) is datetime: day = day.astimezone(timezone(tz)) if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() : return None minTime = self.getEndDate() for e in self.getSchedule().getEntriesOnDay(day) : if e.getStartDate() < minTime : minTime = e.getStartDate() if minTime == self.getEndDate() : minTime = day.replace(hour=8, minute=0)#datetime.combine(day,time(hour=8, minute=0)) if minTime < self.getStartDate() : return self.getStartDate() return minTime def getEndOnDay(self, day, tz=None): if not tz: tz = self.getConference().getTimezone() if type(day) is datetime: day = day.astimezone(timezone(tz)) if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() : return None maxTime = self.getStartDate(); for e in self.getSchedule().getEntriesOnDay(day) : if e.getEndDate() > maxTime : maxTime = e.getEndDate() if maxTime == self.getStartDate() : maxTime = day.replace(hour=19, minute=0)#datetime.combine(day,time(19,0)) if maxTime > self.getEndDate() : return self.getEndDate() return maxTime def getLocationParent( self ): """ Returns the object from which the room/location information should be inherited """ return self.getConference() def getLocation( self ): if self.getOwnLocation(): return self.getOwnLocation() return self.getInheritedLocation() def getInheritedLocation(self): return self.getLocationParent().getLocation() def getOwnLocation( self ): if len(self.places)>0: return self.places[0] return None def setLocation( self, newLocation ): if newLocation == None: if len(self.places)>0: del self.places[0] elif len(self.places)>0: self.places[0] = newLocation else: self.places.append( newLocation ) self.notifyModification() def getRoom( self ): if self.getOwnRoom(): return self.getOwnRoom() return self.getInheritedRoom() def getInheritedRoom(self): return self.getLocationParent().getRoom() def getOwnRoom( self ): if len(self.rooms)>0: return self.rooms[0] return None def setRoom( self, newRoom ): if newRoom == None: if len(self.rooms)>0: del self.rooms[0] elif len(self.rooms)>0: self.rooms[0] = newRoom else: self.rooms.append( newRoom ) self.notifyModification() def getLocationList(self): """Method returning a list of "location" objects which contain the information about the different places the conference is gonna happen """ return self.places def addLocation(self, newPlace): self.places.append( newPlace ) self.notifyModification() def _resetConveners(self): try: if self._conveners: return except AttributeError: self._conveners=[] for oc in self.conveners: newConv=SessionChair() newConv.setDataFromAvatar(oc) self._addConvener(newConv) def getConvenerList(self): self._resetConveners() return self._conveners def _addConvener(self,newConv): if newConv in self._conveners: return try: if self._convenerGen: pass except AttributeError: self._convenerGen=Counter() id = newConv.getId() if id == "": id=int(self._convenerGen.newCount()) newConv.includeInSession(self,id) self._conveners.append(newConv) self.notifyModification() def addConvener(self,newConv): self._resetConveners() self._addConvener(newConv) if isinstance(newConv, MaKaC.user.Avatar): conv.unlinkTo(self, "convener") def removeConvener(self,conv): self._resetConveners() if conv not in self._conveners: return #--Pending queue: remove pending Convener waiting to became manager if anything self.getConference().getPendingQueuesMgr().removePendingManager(conv) #-- #--Pending queue: remove pending Convener waiting to became coordinator if anything self.getConference().getPendingQueuesMgr().removePendingCoordinator(conv) #-- self._conveners.remove(conv) if isinstance(conv, MaKaC.user.Avatar): conv.linkTo(self, "convener") conv.delete() self.notifyModification() def recoverConvener(self, con): self.addConvener(con) con.recover() def getConvenerById(self,id): id=int(id) for conv in self._conveners: if conv.getId()==id: return conv return None def getConvenerText( self ): #to be removed try: if self.convenerText: pass except AttributeError, e: self.convenerText = "" return self.convenerText def setConvenerText( self, newText ): self.convenerText = newText.strip() def appendConvenerText( self, newText ): self.setConvenerText( "%s, %s"%(self.getConvenerText(), newText.strip()) ) def addContribution(self, newContrib, id=None): """Registers the contribution passed as parameter within the session assigning it a unique id. """ if self.hasContribution(newContrib): return self.getConference().addContribution(newContrib,id) self.contributions[newContrib.getId()]=newContrib newContrib.setSession(self) self.notifyModification() def hasContribution(self,contrib): return contrib.getSession()==self and \ self.contributions.has_key(contrib.getId()) def removeContribution(self,contrib): """Removes the indicated contribution from the session """ if not self.hasContribution(contrib): return if contrib.isScheduled(): # unschedule the contribution sch=contrib.getSchEntry().getSchedule() sch.removeEntry(contrib.getSchEntry()) del self.contributions[contrib.getId()] contrib.setSession(None) self.notifyModification() def newContribution( self, params = None, id=None ): c = Contribution() if params: c.setValues(params) self.addContribution( c, id ) return c def getContributionById(self,id): id=str(id).strip() if self.contributions.has_key( id ): return self.contributions[ id ] return None def getContributionList( self ): return self.contributions.values() def canIPAccess( self, ip ): try: return self._v_canipaccess[ip] except AttributeError: self._v_canipaccess = {} except KeyError: pass if not self.__ac.canIPAccess( ip ): self._v_canipaccess[ip] = False return self._v_canipaccess[ip] if self.getOwner() != None: self._v_canipaccess[ip] = self.getOwner().canIPAccess(ip) return self._v_canipaccess[ip] self._v_canipaccess[ip] = True return self._v_canipaccess[ip] def isProtected( self ): # tells if a session is protected or not return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0 def getAccessProtectionLevel( self ): return self.__ac.getAccessProtectionLevel() def isItselfProtected( self ): return self.__ac.isItselfProtected() def hasAnyProtection( self ): """Tells whether a session has any kind of protection over it: access or domain protection. """ if self.__ac.isProtected(): return True if self.getDomainList(): return True if self.getAccessProtectionLevel() == -1: return False return self.getOwner().hasAnyProtection() def hasProtectedOwner( self ): if self.getOwner() != None: return self.getOwner().isProtected() return False def setProtection( self, private ): self.__ac.setProtection( private ) self.updateFullyPublic() def grantAccess( self, prin ): self.__ac.grantAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "access") self.resetAccessCache() def revokeAccess( self, prin ): self.__ac.revokeAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "access") self.resetAccessCache() def canView( self, aw ): """tells whether the specified user has access to the current object or any of its sub-objects """ if self.canAccess( aw ): return True for contrib in self.getContributionList(): if contrib.canView( aw ): return True return False def isAllowedToAccess( self, user ): try: return self._v_isallowedtoaccess[user] except AttributeError: self._v_isallowedtoaccess = {} except KeyError: pass if not user: return False if user in self.getCoordinatorList() or self.__ac.canUserAccess( user ) \ or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess(user)): self._v_isallowedtoaccess[user] = True return True self._v_isallowedtoaccess[user] = False return False def canAccess( self, aw ): try: return self._v_canaccess[aw] except AttributeError: self._v_canaccess = {} except KeyError: pass # Allow harvesters (Invenio, offline cache) to access # protected pages if self.__ac.isHarvesterIP(aw.getIP()): self._v_canaccess[aw] = True return True ##################################################### if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ): self._v_canaccess[aw] = False return False if not self.isProtected(): self._v_canaccess[aw] = True return True flag = self.isAllowedToAccess( aw.getUser() ) self._v_canaccess[aw] = flag or self.conference.canKeyAccess( aw ) return self._v_canaccess[aw] def resetAccessCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canaccess"): del self._v_canaccess if hasattr(self,"_v_isallowedtoaccess"): del self._v_isallowedtoaccess if hasattr(self,"_v_canipaccess"): del self._v_canipaccess if UP: self.getConference().resetAccessCache(True, False) if DOWN: for cont in self.getContributionList(): cont.resetModifyCache(False, True) for mat in self.getMaterialList(): mat.resetAccessCache(False, True) def resetModifyCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canmodify"): del self._v_canmodify if hasattr(self,"_v_canusermodify"): del self._v_canusermodify if UP and DOWN: self.resetAccessCache(UP, DOWN) if UP: self.getConference().resetModifyCache(True, False) if DOWN: for cont in self.getContributionList(): cont.resetModifyCache(False, True) for mat in self.getMaterialList(): mat.resetModifyCache(False, True) def grantModification( self, sb, sendEmail=True ): if isinstance(sb, SessionChair): ah = AvatarHolder() results=ah.match({"email":sb.getEmail()}, exact=1) r=None for i in results: if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]: r=i break if r is not None and r.isActivated(): self.__ac.grantModification( r ) r.linkTo(self, "manager") self.resetModifyCache() elif sb.getEmail() != "": self.__ac.grantModificationEmail(sb.getEmail()) #send email once try : self._v_emailSent except: self._v_emailSent = [] if sendEmail and not sb.getEmail() in self._v_emailSent: self._v_emailSent.append(sb.getEmail()) notif = pendingQueues._PendingManagerNotification( [sb] ) mail.GenericMailer.sendAndLog( notif, self.getConference() ) else: self.__ac.grantModification( sb ) if isinstance(sb, MaKaC.user.Avatar): sb.linkTo(self, "manager") self.resetModifyCache() def revokeModification( self, prin ): self.__ac.revokeModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "manager") self.resetModifyCache() def canModify( self, aw ): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw ) return self._v_canmodify[aw] def canUserModify( self, av ): """Tells whether a user is allowed to modify the current session: only if the user is granted to modify the session or the user can modify the corresponding conference. """ try: return self._v_canusermodify[av] except AttributeError: self._v_canusermodify = {} except KeyError: pass self._v_canusermodify[av] = self.getConference().canUserModify( av ) or self.__ac.canModify( av ) return self._v_canusermodify[av] def getManagerList( self ): return self.__ac.getModifierList() def getAllowedToAccessList( self ): return self.__ac.getAccessList() def addMaterial( self, newMat ): newMat.setId( str(self.__materialGenerator.newCount()) ) newMat.setOwner( self ) self.materials[ newMat.getId() ] = newMat self.notifyModification() def removeMaterial( self, mat ): if mat.getId() in self.materials.keys(): self.materials[mat.getId()].setOwner(None) del self.materials[ mat.getId() ] mat.delete() self.notifyModification() return "done: %s"%mat.getId() elif mat.getId().lower() == 'minutes': self.removeMinutes() return "done: %s"%mat.getId() return "not done: %s"%mat.getId() def recoverMaterial(self, recMat): # Id must already be set in recMat. recMat.setOwner( self ) self.materials[ recMat.getId() ] = recMat recMat.recover() self.notifyModification() def getMaterialRegistry(self): """ Return the correct material registry for this type """ from MaKaC.webinterface.materialFactories import SessionMFRegistry return SessionMFRegistry def getMaterialById( self, matId ): if matId.lower() == 'minutes': return self.getMinutes() elif self.materials.has_key(matId): return self.materials[ matId ] return None def getMaterialList( self ): return self.materials.values() def getAllMaterialList( self ): l = self.getMaterialList() if self.getMinutes(): l.append( self.getMinutes() ) l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle())) return l def _setSchedule(self): self.__schedule=SessionSchedule(self) sl=self.getSlotList() for slot in self.getSlotList(): self.__schedule.addEntry(slot.getSchEntry()) def getSchedule( self ): try: if self.__schedule is None or not isinstance(self.__schedule,SessionSchedule): self._setSchedule() except AttributeError, e: self._setSchedule() return self.__schedule def getMasterSchedule( self ): return self.getOwner().getSchedule() def requireDomain( self, dom ): self.__ac.requireDomain( dom ) self.resetAccessCache() def freeDomain( self, dom ): self.__ac.freeDomain( dom ) self.resetAccessCache() def getDomainList( self ): return self.__ac.getRequiredDomainList() def setComments(self,comm): self._comments = comm.strip() def getComments(self): try: if self._comments: pass except AttributeError,e: self._comments="" return self._comments def createMinutes( self ): if self.getMinutes() != None: raise MaKaCError( _("The minutes for this session have already been created"), _("Session")) self.minutes = Minutes() self.minutes.setOwner( self ) self.notifyModification() return self.minutes def removeMinutes( self ): if self.minutes is None: return self.minutes.delete() self.minutes.setOwner( None ) self.minutes = None self.notifyModification() def recoverMinutes(self, min): self.removeMinutes() # To ensure that the current minutes are put in # the trash can. self.minutes = min self.minutes.setOwner( self ) min.recover() self.notifyModification() return self.minutes def getMinutes( self ): #To be removed try: if self.minutes: pass except AttributeError, e: self.minutes = None return self.minutes def _addCoordinator(self, av): if av is None or self._coordinators.has_key(av.getId()): return self._coordinators[av.getId()]=av if self.getConference() is not None: self.getConference().addSessionCoordinator(self,av) self.resetModifyCache() def getCoordinatorEmailList(self): try: return self._coordinatorsEmail except: self._coordinatorsEmail = [] return self._coordinatorsEmail def _addCoordinatorEmail(self, email): if not email in self.getCoordinatorEmailList(): self.getCoordinatorEmailList().append(email) def removeCoordinatorEmail(self, email): if email in self.getCoordinatorEmailList(): if email in self.getCoordinatorEmailList(): self.getCoordinatorEmailList().remove(email) self._p_changed = 1 def addCoordinator( self, sb, sendEmail=True ): """Grants coordination privileges to user. Arguments: sb -- It can be either: (MaKaC.user.Avatar) the user to which coordination privileges must be granted. or: (MaKaC.conference.SessionChair) a non-existing which has to become indico user before to be granted with privileges. """ try: if self._coordinators: pass except AttributeError, e: self._coordinators=OOBTree() if isinstance(sb, SessionChair): ah = AvatarHolder() results=ah.match({"email":sb.getEmail()}, exact=1) r=None for i in results: if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]: r=i break if r is not None and r.isActivated(): self._addCoordinator(r) r.linkTo(self, "coordinator") else: self.getConference().getPendingQueuesMgr().addPendingCoordinator(sb) else: self._addCoordinator(sb) if isinstance(sb, MaKaC.user.Avatar): sb.linkTo(self, "coordinator") def removeCoordinator( self, av ): """Revokes coordination privileges to user. Arguments: av -- (MaKaC.user.Avatar) user for which coordination privileges must be revoked """ try: if self._coordinators: pass except AttributeError, e: self._coordinators=OOBTree() if av is None or not self._coordinators.has_key(av.getId()): return del self._coordinators[av.getId()] if isinstance(av, MaKaC.user.Avatar): av.unlinkTo(self, "coordinator") if self.getConference() is not None: self.getConference().removeSessionCoordinator(self,av) self.resetModifyCache() def isCoordinator( self, av ): """Tells whether the specified user is a coordinator of the session. Arguments: av -- (MaKaC.user.Avatar) user to be checked Return value: (boolean) """ try: if self._coordinators: pass except AttributeError, e: self._coordinators=OOBTree() if (av is not None) and self._coordinators.has_key(av.getId()): return True ret = False if isinstance(av, MaKaC.user.Avatar): for email in av.getEmails(): if email in self.getCoordinatorEmailList(): self.addCoordinator(av) self.removeCoordinatorEmail(email) ret = True return ret def getCoordinatorList( self ): """Return all users which have privileges to coordinate the session. Return value: (list) """ try: if self._coordinators: pass except AttributeError, e: self._coordinators=OOBTree() return self._coordinators.values() def canCoordinate(self,aw, right=""): """Tells if a user has coordination privileges. Only session coordinators have coordination privileges over a session. Params: aw -- (MaKaC.accessControl.AccessWrapper) User access information for which the coordination privileges must be checked. Return value: (boolean) """ if right != "": return self.isCoordinator(aw.getUser()) and self.getConference().hasSessionCoordinatorRight(right) return self.isCoordinator(aw.getUser()) def getScheduleType(self): try: if self._ttType: pass except AttributeError: self._ttType=SlotSchTypeFactory.getDefaultId() return self._ttType def setScheduleType(self,t): try: if self._ttType: pass except AttributeError: self._ttType=SlotSchTypeFactory.getDefaultId() t=str(t).strip().lower() if t not in SlotSchTypeFactory.getIdList() or t==self._ttType: return self._ttType=t for slot in self.getSlotList(): slot.setScheduleType(t) def getAccessController(self): return self.__ac def _cmpTitle( s1, s2 ): s1=s1.getTitle().lower().strip() s2=s2.getTitle().lower().strip() return cmp( s1, s2 ) _cmpTitle=staticmethod(_cmpTitle) class SessionSlot(Persistent, Fossilizable): fossilizes(ISessionSlotFossil) def __init__(self,session,**sessionSlotData): self.session = session self.id = "not assigned" self.title = "" self.startDate=None self.duration = timedelta(minutes=1) self.places = [] self.rooms = [] self._conveners = [] self._convenerGen=Counter() self._schedule=SlotSchTypeFactory.getDefaultKlass()(self) self._sessionSchEntry=LinkedTimeSchEntry(self) self._confSchEntry=LinkedTimeSchEntry(self) self._contributionDuration = None def getTimezone( self ): return self.getConference().getTimezone() def getLogInfo(self): data = {} data["id"] = self.id data["title"] = self.title data["session"] = self.session.getTitle() data["start date"] = self.startDate data["duration"] = self.duration i = 0 for p in self.places : data["place %s"%i] = p.getName() i+=1 i = 0 for r in self.rooms : data["room %s"%i] = r.getName() i+=1 for c in self._conveners : data["convener %s"%c.getId()] = c.getFullName() return data def clone(self,session, options): slot = SessionSlot(session) slot.session = session slot.setTitle(self.getTitle()) timeDifference = session.getConference().getStartDate() - self.getSession().getConference().getStartDate() slot.setStartDate(self.getStartDate() + timeDifference) slot.setDuration(dur=self.getDuration(), check=2) #places if self.getOwnLocation() is not None: slot.setLocation(self.getOwnLocation().clone()) #rooms if self.getOwnRoom() is not None: slot.setRoom(self.getOwnRoom().clone()) #chairs = conveners for ch in self.getOwnConvenerList() : slot.addConvener(ch.clone()) #populate the timetable if options.get("contributions", False) : for entry in self.getEntries() : if isinstance(entry, BreakTimeSchEntry) : newentry = entry.clone(slot) slot.getSchedule().addEntry(newentry,0) elif isinstance(entry, ContribSchEntry) : contrib = entry.getOwner() newcontrib = contrib.clone(session, options, timeDifference) slot.getSchedule().addEntry(newcontrib.getSchEntry(),0) slot.setContribDuration(0, 0, self.getContribDuration()) slot.notifyModification() return slot def fit( self ): """ sets the start date of the slot to the start date of the first son and the end date to the end date of the last son """ sch = self.getSchedule() entries = sch.getEntries() if len(entries) > 0: self.setStartDate(entries[0].getStartDate(),0,0) self.setEndDate(sch.calculateEndDate(), check=0) def recalculateTimes( self, type, diff ): """ recalculate and reschedule the contributions of the session slot with a time "diff" of separation. """ if type=="duration": entries = self.getSchedule().getEntries()[:] i=0 while i0: entry=old_sch.getEntries()[0] old_sch.removeEntry(entry) self.notifyModification() def getSchedule(self): return self._schedule def getMasterSchedule( self ): return self.getOwner().getSchedule() def getConfSchEntry( self ): try: if self._confSchEntry: pass except AttributeError: self._confSchEntry=LinkedTimeSchEntry(self) return self._confSchEntry def getSessionSchEntry( self ): try: if self._sessionSchEntry: pass except AttributeError: self._sessionSchEntry=self._schEntry return self._sessionSchEntry def setId( self, newId ): self.id=str(newId) self.notifyModification() def getId( self ): return self.id def setTitle( self, newTitle ): self.title=newTitle self.notifyModification() def getTitle( self ): try: if self.title: pass except AttributeError,e: self.title="" return self.title def getName(self): return "slot %s"%self.getId() def getDescription(self): return self.getSession().getDescription() def setDates(self,sDate,eDate,check=2,moveEntries=0): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" if sDate>eDate: raise MaKaCError(_("End date cannot be prior to Start date"),_("Slot")) self.setStartDate(sDate, check, moveEntries, checkDuration=False) self.setDuration(0, 0, 0, eDate-sDate, check) self.notifyModification() def getEntries(self): entriesList = self.getSchedule().getEntries() return entriesList def move(self, sDate): diff=sDate-self.startDate self.startDate = sDate for slotEntry in self.getSchedule().getEntries(): if isinstance(slotEntry, BreakTimeSchEntry): slotEntry.startDate = slotEntry.getStartDate() + diff else: se = slotEntry.getOwner() se.startDate = se.getStartDate() + diff self.getSchedule().reSchedule() def verifyStartDate(self, sDate,check=2): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" tz = timezone(self.getConference().getTimezone()) if sDate < self.getSession().getStartDate(): if check == 1: raise ParentTimingError(_("The slot \"%s\" cannot start (%s) before its parent session starts (%s)")%\ (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ self.getSession().getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\ _("Slot")) elif check == 2: self.getSession().setStartDate(sDate, check, 0) def setStartDate(self,sDate,check=2,moveEntries=0,checkDuration=True): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" if sDate is None: return if not sDate.tzname(): raise MaKaCError("date should be timezone aware") if check != 0: #If not using .fit() at the end of this method, comment it out #if self.getSession().getStartDate() > sDate: # self.getSession().duration += self.getSession().getStartDate() - sDate self.verifyStartDate(sDate,check) # calculate the difference betwwen old and new date difference = None if self.startDate is not None: difference = sDate - self.getStartDate() self.startDate=copy.copy(sDate) if difference != None and difference != timedelta(0) and moveEntries: ContextManager.get('autoOps').append((self, "ENTRIES_MOVED", self, sDate.astimezone(timezone(self.getTimezone())))) self.getSchedule().moveEntriesBelow(difference,self.getSchedule().getEntries()[:]) if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getStartDate() != sDate: self.getSession().setStartDate(sDate, check, 0) if check != 0 and self.getSession() and checkDuration: self.verifyDuration(self.getDuration(), check=check) # synchronize with other timetables self.getSessionSchEntry().synchro() self.getConfSchEntry().synchro() self.getSession().fit() self.notifyModification() def setEndDate(self,eDate,check=2): if not eDate.tzname(): raise MaKaCError("date should be timezone aware") if check != 0: self.verifyDuration(eDate-self.startDate, check) self.setDuration(dur=eDate-self.startDate,check=check) if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getEndDate() != eDate: self.getSession().setEndDate(eDate, check) self.getSession().fit() self.notifyModification() def getStartDate( self ): return self.startDate def getAdjustedStartDate(self,tz=None): if not tz: tz = self.getConference().getTimezone() if tz not in all_timezones: tz = 'UTC' return self.startDate.astimezone(timezone(tz)) def getEndDate( self ): if self.startDate is None: return None return self.startDate+self.duration def getAdjustedEndDate( self, tz=None ): if not tz: tz = self.getConference().getTimezone() if tz not in all_timezones: tz = 'UTC' if self.getEndDate(): return self.getEndDate().astimezone(timezone(tz)) return None def getDuration( self ): return self.duration def isMoreThanDay(self): if self.getDuration() >= timedelta(days=1): return True return False def verifyDuration(self, dur, check=1): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" tz = timezone(self.getConference().getTimezone()) if dur <= timedelta(0): raise MaKaCError( _("The duration cannot be less than zero"), _("Slot")) if dur.days > 1: raise MaKaCError( _("The duration cannot be more than one day"), _("Slot")) if self.startDate is not None: sessionStartDate = self.getSession().getStartDate() sessionEndDate = self.getSession().getEndDate() # end date has to be between the session dates eDate = self.startDate + dur if eDate > sessionEndDate: if check==1: raise EntryTimingError(_("The session slot cannot end (%s) after its parent session (%s)") \ % (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ sessionEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\ _("Slot")) elif check==2: ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED", self.getSession(), eDate.astimezone(tz))) self.getSession().setEndDate(eDate,check) if eDate.astimezone(tz).date() > self.startDate.astimezone(tz).date(): raise TimingError( _("The time slot must end on the same day it has started"), _("Slot")) # do not modify if slot entries will be affected sch = self.getSchedule() entries = sch.getEntries() if entries != []: if eDate < sch.calculateEndDate(): raise TimingError(_("The session slot cannot end at (%s) because there is a contribution (%s) ending after that time. ")%\ (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ sch.calculateEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\ _("Slot")) def setDuration(self, days=0,hours=0,minutes=0,dur=0,check=1): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" if dur==0: dur = timedelta(days=int(days),hours=int(hours),minutes=int(minutes)) if dur==0 and check==2: ContextManager.get('autoOps').append((self, "DURATION_SET", self, 1)) dur = timedelta(minutes=1) if dur > timedelta(days=1) and check==2: pass#dur = timedelta(days=1) if check != 0: self.verifyDuration(dur, check) self.duration = dur self.getSessionSchEntry().synchro() self.getConfSchEntry().synchro() self.getSession().fit() self.notifyModification() def getLocationParent( self ): """ Returns the object from which the room/location information should be inherited """ return self.session def getLocation( self ): if self.getOwnLocation(): return self.getOwnLocation() return self.getInheritedLocation() def getInheritedLocation(self): return self.getLocationParent().getLocation() def getOwnLocation( self ): if len(self.places)>0: return self.places[0] return None def setLocation( self, newLocation ): if newLocation == None: if len(self.places)>0: del self.places[0] elif len(self.places)>0: self.places[0] = newLocation else: self.places.append( newLocation ) self.notifyModification() def getRoom( self ): if self.getOwnRoom(): return self.getOwnRoom() return self.getInheritedRoom() def getInheritedRoom(self): return self.getLocationParent().getRoom() def getOwnRoom( self ): if len(self.rooms)>0: return self.rooms[0] return None def setRoom( self, newRoom ): if newRoom == None: if len(self.rooms)>0: del self.rooms[0] elif len(self.rooms)>0: self.rooms[0] = newRoom else: self.rooms.append( newRoom ) self.notifyModification() def delete(self): self.getSchedule().clear() if self.getSession() is not None: self.getSession().removeSlot(self) self.session=None TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def canAccess(self,aw): return self.getSession().canAccess(aw) def canView(self,aw): return self.getSession().canView(aw) def setScheduleType(self,id): id=str(id).strip().lower() currentId=SlotSchTypeFactory.getId(self.getSchedule()) if id not in SlotSchTypeFactory.getIdList() or id==currentId: return self._setSchedule(SlotSchTypeFactory.getScheduleKlass(id)) def getConvenerList(self): try: if self._conveners: pass except AttributeError: self._conveners = [] if self._conveners == []: return self.getSession().getConvenerList() return self._conveners def addConvener(self,newConv): if newConv in self._conveners: return try: if self._convenerGen: pass except AttributeError: self._convenerGen=Counter() id = newConv.getId() if id == "": id=int(self._convenerGen.newCount()) newConv.includeInSlot(self,id) self._conveners.append(newConv) self.notifyModification() def removeConvener(self,conv): if conv not in self._conveners: return self._conveners.remove(conv) conv.delete() self.notifyModification() def recoverConvener(self, con): self.addConvener(con) con.recover() def getConvenerById(self,id): id=int(id) for conv in self._conveners: if conv.getId()==id: return conv return None def getOwnConvenerList(self): try: if self._conveners: pass except AttributeError: self._conveners = [] return self._conveners def clearConvenerList(self): while len(self.getOwnConvenerList()) > 0: self._conveners.pop() self.notifyModification() def getColor(self): res="" if self.getSession() is not None: res=self.getSession().getColor() return res def getTextColor(self): res="" if self.getSession() is not None: res=self.getSession().getTextColor() return res class ContributionParticipation(Persistent, Fossilizable): fossilizes(IContributionParticipationFossil, IContributionParticipationMinimalFossil,\ IContributionParticipationTTDisplayFossil,\ IContributionParticipationTTMgmtFossil) def __init__( self ): self._contrib = None self._id = "" self._firstName = "" self._surName = "" self._email = "" self._affiliation = "" self._address = "" self._phone = "" self._title = "" self._fax = "" def _notifyModification( self ): if self._contrib != None: self._contrib.notifyModification() def setValues(self, data): self.setFirstName(data.get("firstName", "")) self.setFamilyName(data.get("familyName","")) self.setAffiliation(data.get("affilation","")) self.setAddress(data.get("address","")) self.setEmail(data.get("email","")) self.setFax(data.get("fax","")) self.setTitle(data.get("title","")) self.setPhone(data.get("phone","")) self._notifyModification() def getValues(self): data={} data["firstName"]=self.getFirstName() data["familyName"]=self.getFamilyName() data["affilation"]=self.getAffiliation() data["address"]=self.getAddress() data["email"]=self.getEmail() data["fax"]=self.getFax() data["title"]=self.getTitle() data["phone"]=self.getPhone() return data def clone(self): part = ContributionParticipation() part.setValues(self.getValues()) return part def setDataFromAvatar(self,av): # av is an Avatar object. if av is None: return self.setFirstName(av.getName()) self.setFamilyName(av.getSurName()) self.setEmail(av.getEmail()) self.setAffiliation(av.getOrganisation()) self.setAddress(av.getAddress()) self.setPhone(av.getTelephone()) self.setTitle(av.getTitle()) self.setFax(av.getFax()) self._notifyModification() def setDataFromOtherCP(self,cp): # cp is a ContributionParticipation object. if cp is None: return self.setFirstName(cp.getFirstName()) self.setFamilyName(cp.getFamilyName()) self.setEmail(cp.getEmail()) self.setAffiliation(cp.getAffiliation()) self.setAddress(cp.getAddress()) self.setPhone(cp.getPhone()) self.setTitle(cp.getTitle()) self.setFax(cp.getFax()) self._notifyModification() def includeInContribution( self, contrib, id ): if self.getContribution() == contrib and self.getId()==id.strip(): return self._contrib = contrib self._id = id def delete( self ): self._contrib = None TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def setId(self, newId): self._id = newId def getId( self ): return self._id def getContribution( self ): return self._contrib def getConference(self): return self._contrib.getConference() def getLocator(self): if self.getContribution() is None: return None loc=self.getContribution().getLocator() loc["authId"]=self.getId() return loc def _unindex(self): contrib=self.getContribution() if contrib is not None: conf=contrib.getConference() if conf is not None: conf.unindexAuthor(self) conf.unindexSpeaker(self) def _index(self): contrib=self.getContribution() if contrib is not None: conf=contrib.getConference() if conf is not None: conf.indexAuthor(self) conf.indexSpeaker(self) @Updates ('MaKaC.conference.ContributionParticipation', 'firstName') def setFirstName( self, newName ): tmp=newName.strip() if tmp==self._firstName: return self._unindex() self._firstName=tmp self._index() self._notifyModification() def getFirstName( self ): return self._firstName def getName( self ): return self._firstName @Updates ('MaKaC.conference.ContributionParticipation', 'familyName') def setFamilyName( self, newName ): tmp=newName.strip() if tmp==self._surName: return self._unindex() self._surName=tmp self._index() self._notifyModification() def getFamilyName( self ): return self._surName def getSurName( self ): return self._surName @Updates ('MaKaC.conference.ContributionParticipation', 'email') def setEmail( self, newMail ): tmp=newMail.strip() if tmp==self._email: return self._unindex() self._email=newMail.strip() self._index() self._notifyModification() def getEmail( self ): return self._email @Updates ('MaKaC.conference.ContributionParticipation', 'affiliation') def setAffiliation( self, newAffil ): self._affiliation = newAffil.strip() self._notifyModification() def getAffiliation( self ): if self._affiliation.lower() == "unknown": return "" return self._affiliation @Updates ('MaKaC.conference.ContributionParticipation', 'address') def setAddress( self, newAddr ): self._address = newAddr.strip() self._notifyModification() def getAddress( self ): return self._address @Updates ('MaKaC.conference.ContributionParticipation', 'telephone') def setPhone( self, newPhone ): self._phone = newPhone.strip() self._notifyModification() def getPhone( self ): return self._phone @Updates ('MaKaC.conference.ContributionParticipation', 'title') def setTitle( self, newTitle ): self._title = newTitle.strip() self._notifyModification() def getTitle( self ): return self._title @Updates ('MaKaC.conference.ContributionParticipation', 'fax') def setFax( self, newFax ): self._fax = newFax.strip() self._notifyModification() def getFax( self ): try: if self._fax: pass except AttributeError: self._fax="" return self._fax def getDirectFullName( self ): res = "%s %s"%( self.getFirstName(), self.getFamilyName().upper() ) res=res.strip() if self.getTitle() != "": res = "%s %s"%( self.getTitle(), res ) return res def getFullName( self ): res = self.getFamilyName().upper() if self.getFirstName() != "": if res.strip() != "": res = "%s, %s"%( res, self.getFirstName() ) else: res = self.getFirstName() if self.getTitle() != "": res = "%s %s"%( self.getTitle(), res ) return res def getFullNameNoTitle( self ): res = self.getFamilyName().upper() if self.getFirstName() != "": if res.strip() != "": res = "%s, %s"%( res, self.getFirstName() ) else: res = self.getFirstName() return res def getAbrName(self): res = self.getFamilyName() if self.getFirstName() != "": if res != "": res = "%s, "%res res = "%s%s."%(res, self.getFirstName()[0].upper()) return res def isPendingSubmitter(self): if self.getContribution() is None: return False if self.getContribution().getConference() is None: return False return self.getContribution().getConference().getPendingQueuesMgr().isPendingSubmitter(self) def _cmpFamilyName( cp1, cp2 ): o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName()) o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName()) o1=o1.lower().strip() o2=o2.lower().strip() return cmp( o1, o2 ) _cmpFamilyName=staticmethod(_cmpFamilyName) class AuthorIndex(Persistent): def __init__(self): self._idx=OOBTree() def _getKey(self,author): k = "%s %s %s"%(author.getFamilyName().lower(),author.getFirstName().lower(),author.getEmail().lower()) return k.strip() def index(self,author): key=self._getKey(author) if not self._idx.has_key(key): self._idx[key]=[] l = self._idx[key] l.append(author) self._idx[key] = l self.notifyModification() def unindex(self,author): key=self._getKey(author) if self._idx.has_key(key): if author in self._idx[key]: l = self._idx[key] l.remove(author) self._idx[key] = l if len(self._idx[key])<=0: del self._idx[key] self.notifyModification() def getParticipations(self): return self._idx.values() def getById(self, id): return self._idx.get(id,None) def getParticipationKeys(self): return self._idx.keys() def notifyModification(self): self._idx._p_changed = 1 self._p_changed = 1 def match(self, criteria, exact=0): self._options = ['organisation', 'surName', 'name', 'email'] l = [] for item in self.getParticipations(): if len(item)>0: ok = [] for f,v in criteria.items(): if f == 'organisation' and v != '': if (exact == 0 and item[0].getAffiliation().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getAffiliation().lower() != v.lower()): ok.append(False) else: ok.append(True) if f == 'surName' and v!= '': if (exact == 0 and item[0].getSurName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getSurName().lower() != v.lower()): ok.append(False) else: ok.append(True) if f == 'name' and v!= '': if (exact == 0 and item[0].getName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getName().lower() != v.lower()): ok.append(False) else: ok.append(True) if f == 'email' and v!= '': if (exact == 0 and item[0].getEmail().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getEmail().lower() != v.lower()): ok.append(False) else: ok.append(True) if len(ok) > 0 and not False in ok: l.append(item[0]) return l class _AuthIdx(Persistent): def __init__(self,conf): self._conf=conf self._idx=OOBTree() def _getKey(self,auth): return "%s %s"%(auth.getFamilyName().lower(),auth.getFirstName().lower()) def index(self,auth): if auth.getContribution() is None: raise MaKaCError( _("Cannot index an author of a contribution which has not been included in a Conference"), _("Author Index")) if auth.getContribution().getConference()!=self._conf: raise MaKaCError( _("cannot index an author of a contribution which does not belong to this Conference"), _("Author Index")) key=self._getKey(auth) contribId=str(auth.getContribution().getId()) if not self._idx.has_key(key): self._idx[key]=OIBTree() if not self._idx[key].has_key(contribId): self._idx[key][contribId]=0 self._idx[key][contribId]+=1 def unindex(self,auth): if auth.getContribution() is None: raise MaKaCError( _("Cannot unindex an author of a contribution which is not included in a conference"), _("Author Index")) if auth.getContribution().getConference()!=self._conf: raise MaKaCError( _("Cannot unindex an author of a contribution which does not belong to this conference"), _("Author Index")) key=self._getKey(auth) if not self._idx.has_key(key): return contribId=str(auth.getContribution().getId()) self._idx[key][contribId]-=1 if self._idx[key][contribId]<=0: del self._idx[key][contribId] if len(self._idx[key])<=0: del self._idx[key] def match(self,query): query=query.lower().strip() res=OISet() for k in self._idx.keys(): if k.find(query)!=-1: res=union(res,self._idx[k]) return res class _PrimAuthIdx(_AuthIdx): def __init__(self,conf): _AuthIdx.__init__(self,conf) for contrib in self._conf.getContributionList(): for auth in contrib.getPrimaryAuthorList(): self.index(auth) class Contribution(Persistent, Fossilizable, CommonObjectBase): """This class implements a conference contribution, being the concrete contributes of the conference participants. The class contains necessary attributes to store contribution basic meta data and provides the useful operations to access and manage them. A contribution can be attached either to a session or to a conference. """ fossilizes(IContributionFossil, IContributionWithSpeakersFossil,\ IContributionWithSubContribsFossil) def __init__(self,**contribData): self.parent = None self._session=None self.id = "" self.title = "" self._fields = {} self.description = "" self.startDate=None self.duration = timedelta(0) self.speakers = [] self.speakerText = "" self.place = None self.room = None self._boardNumber="" self._resetSchEntry() self.__ac = AccessController() self.materials = {} self.__materialGenerator = Counter() self._subConts = [] self.__subContGenerator = Counter() self.paper = None self.slides = None self.video = None self.poster = None self.minutes = None self.reviewing = None self._authorGen = Counter() self._authors = OOBTree() self._primaryAuthors = [] self._coAuthors = [] self._speakers = [] self._track = None self._type = None self._status=ContribStatusNotSch(self) #List of allowed users to submit material self._submitters=[] self._submittersEmail=[] self._modificationDS = nowutc() self._OAImodificationDS = self._modificationDS self._keywords = "" self._reviewManager = ReviewManager(self) def getTimezone( self ): return self.getConference().getTimezone() def getReviewManager(self): if not hasattr(self, "_reviewManager"): self._reviewManager = ReviewManager(self) return self._reviewManager def isFullyPublic( self ): if hasattr(self, "_fullyPublic"): return self._fullyPublic else: self.setFullyPublic() return self._fullyPublic def setFullyPublic( self ): if self.isProtected(): self._fullyPublic = False self._p_changed = 1 return for res in self.getAllMaterialList(): if not res.isFullyPublic(): self._fullyPublic = False self._p_changed = 1 return for res in self.getSubContributionList(): if not res.isFullyPublic(): self._fullyPublic = False self._p_changed = 1 return self._fullyPublic = True self._p_changed = 1 def updateFullyPublic( self ): self.setFullyPublic() self.getOwner().updateFullyPublic() def getKeywords(self): try: return self._keywords except: self._keywords = "" return "" def setKeywords(self, keywords): if type(keywords) is list: self._keywords = keywords[0] else: self._keywords = keywords self.notifyModification() def getFields( self ): try: return self._fields except: self._fields = {} try: if self.summary != "": self._fields["summary"] = self.summary del self.summary except: pass return self._fields def removeField( self, field ): if self.getFields().has_key(field): del self.getFields()[field] self.notifyModification() def setField( self, field, value ): try: self.getFields()[field] = value self.notifyModification() except: pass def getField( self, field ): if self.getFields().has_key(field): value = self.getFields()[field] if type(value) is list: return "".join(value) elif value is None: return "" else: return value else: return "" def getLogInfo(self): data = {} data["subject"] = self.getTitle() data["id"] = self.id data["title"] = self.title data["parent title"] = self.parent.getTitle() if self._session is not None : data["session title"] = self._session.getTitle() data["description"] = self.description if self.getConference(): afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr() for f in afm.getFields(): id = f.getId() data[id] = self.getField(id) data["start date"] = "%s"%self.startDate data["duration"] = "%s"%self.duration if self._track is not None : data["track"] = self._track.getTitle() if self._type is not None : data["type"] = self._type data["speaker text"] = self.speakerText if self.place is not None : data["place"] = self.place.getName() if self.room is not None : data["room"] = self.room.getName() data["board number"] = self._boardNumber for sc in self.getSubContributionList() : data["subcontribution %s"%sc.getId()] = sc.getTitle() for pa in self._primaryAuthors : data["primary author %s"%pa.getId()] = pa.getFullName() for ca in self._coAuthors : data["co-author %s"%ca.getId()] = ca.getFullName() for sp in self._speakers : data["speaker %s"%sp.getId()] = sp.getFullName() for s in self._submitters : if isinstance(s, MaKaC.user.Avatar): data["submitter"] = s.getFullName() else: data["submitter"] = s.getName() return data def setValues( self, data, check=2, moveEntriesBelow=0): """Sets all the values of the current contribution object from a dictionary containing the following key-value pairs: title-(str) description-(str) locationName-(str) => name of the location, if not specified it will be set to the parent location name. locationAddress-(str) roomName-(str) => name of the room, if not specified it will be set to the parent room name. year, month, day, sHour, sMinute - (str) => components of the starting date of the session, if not specified it will be set to now. durationHours, durationMinutes - (str) speakers - (str) check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates moveEntries: 0: no move 1: moveEntries below the contribution Please, note that this method sets ALL values which means that if the given dictionary doesn't contain any of the keys the value will set to a default value. """ # In order to move the entries below, it is needed to know the diff (we have to move them) # and the list of entries to move. It's is needed to take those datas in advance because they # are going to be modified before the moving. if moveEntriesBelow == 1: oldStartDate=copy.copy(self.getStartDate()) oldDuration=copy.copy(self.getDuration()) i=self.getSchEntry().getSchedule().getEntries().index(self.getSchEntry())+1 entriesList = self.getSchEntry().getSchedule().getEntries()[i:] if data.has_key("title"): self.setTitle(data["title"]) if data.has_key("keywords"): self.setKeywords(data["keywords"]) if data.has_key("description"): self.setDescription(data["description"]) if data.has_key("type") and self.getConference(): self.setType(self.getConference().getContribTypeById(data["type"])) if self.getConference(): afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr() for f in afm.getFields(): id = f.getId() if data.has_key("f_%s"%id): self.setField(id, data["f_%s"%id]) if "locationName" in data: loc=self.getOwnLocation() if not loc: loc=CustomLocation() self.setLocation(loc) loc.setName(data["locationName"]) loc.setAddress(data.get("locationAddress", "")) else: self.setLocation(None) #same as for the location if "roomName" in data: room=self.getOwnRoom() if not room: room=CustomRoom() self.setRoom(room) room.setName(data["roomName"]) else: self.setRoom(None) tz = 'UTC' if self.getConference(): tz = self.getConference().getTimezone() if data.get("targetDay","")!="" and data.get("sHour","")!="" and data.get("sMinute","")!="" and check==2: ############################################ # Fermi timezone awareness # ############################################ me = timezone(tz).localize(datetime(int(data["targetDay"][0:4]), \ int(data["targetDay"][5:7]),int(data["targetDay"][8:]))) sdate = timezone(tz).localize(datetime(me.year,me.month, \ me.day,int(data["sHour"]),int(data["sMinute"]))) self.setStartDate(sdate.astimezone(timezone('UTC')),check=2) if data.get("sYear","")!="" and data.get("sMonth","")!="" and \ data.get("sDay","")!="" and data.get("sHour","")!="" and \ data.get("sMinute","")!="": self.setStartDate(timezone(tz).localize(datetime(int(data["sYear"]), int(data["sMonth"]), int(data["sDay"]), int(data["sHour"]), int(data["sMinute"]))).astimezone(timezone('UTC')), check=2) ############################################ # Fermi timezone awareness(end) # ############################################ if data.get("durTimedelta", "") != "": self.setDuration(check=check, dur=data["durTimedelta"]) elif data.get("durHours","")!="" and data.get("durMins","")!="": self.setDuration(data["durHours"],data["durMins"],check) else: h=data.get("durHours","").strip() m=data.get("durMins","").strip() if h!="" or m!="": h=h or "0" m=m or "0" if h!="0" or m!="0": self.setDuration(int(h), int(m),check) if data.has_key("boardNumber"): self.setBoardNumber(data.get("boardNumber","")) if moveEntriesBelow == 1: diff = (self.getStartDate() - oldStartDate) + (self.getDuration() - oldDuration) self.getConference().getSchedule().moveEntriesBelow(diff, entriesList) self.notifyModification() def clone(self, parent, options, deltaTime = 0): cont = Contribution() parent.addContribution(cont) cont.setTitle( self.getTitle() ) cont.setDescription( self.getDescription() ) for k in self.getFields().keys(): cont.setField(k, self.getField(k)) cont.setKeywords( self.getKeywords() ) if deltaTime == 0 : deltaTime = parent.getStartDate() - self.getOwner().getStartDate() startDate = None if self.startDate is not None : startDate = self.getStartDate() + deltaTime cont.setStartDate( startDate ) cont.setDuration( dur=self.getDuration() ) if self.getOwnLocation() is not None: cont.setLocation(self.getOwnLocation().clone()) if self.getOwnRoom() is not None: cont.setRoom(self.getOwnRoom().clone()) cont.setBoardNumber(self.getBoardNumber()) cont.setReportNumberHolder(self.getReportNumberHolder().clone(self)) cont.setStatus(self.getCurrentStatus()) if self.getType() is not None : for ct in cont.getConference().getContribTypeList() : if ct.getName() == self.getType().getName() : cont.setType(ct) break if options.get("tracks", False) : if self.getTrack() is not None : for tr in cont.getConference().getTrackList() : if tr.getTitle() == self.getTrack().getTitle() : cont.setTrack(tr) break else : cont.setTrack(None) if options.get("access", False) : cont.setProtection(self.isItselfProtected()) for u in self.getAllowedToAccessList() : cont.grantAccess(u) for mgr in self.getManagerList() : cont.grantModification(mgr) for sub in self.getSubmitterList() : cont.grantSubmission(sub) for domain in self.getDomainList(): cont.requireDomain(domain) if options.get("authors", False) : for a in self.getPrimaryAuthorList() : cont.addPrimaryAuthor(a.clone()) for ca in self.getCoAuthorList() : cont.addCoAuthor(ca.clone()) for sp in self.getSpeakerList(): cont.newSpeaker(sp.clone()) cont.setSpeakerText(self.getSpeakerText()) if options.get("materials", False) : for m in self.getMaterialList() : cont.addMaterial(m.clone(cont)) if self.getPaper() is not None: cont.setPaper(self.getPaper().clone(cont)) if self.getSlides() is not None: cont.setSlides(self.getSlides().clone(cont)) if self.getVideo() is not None: cont.setVideo(self.getVideo().clone(cont)) if self.getPoster() is not None: cont.setPoster(self.getPoster().clone(cont)) if self.getMinutes() is not None: cont.setMinutes(self.getMinutes().clone(cont)) if self.getReviewing() is not None: cont.setReviewing(self.getReviewing().clone(cont)) if options.get("subcontribs", False) : for sc in self.getSubContributionList() : cont.addSubContribution(sc.clone(cont, self, options)) return cont def notifyModification( self, date=None, oai=True): if not date: date = nowutc() self._modificationDS = date if oai: self.notifyOAIModification(date=date) parent = self.getParent() if parent: parent.notifyModification() self._p_changed = 1 def notifyOAIModification(self, date=None):#, updateChildren=False):#, force=False): self.getOAIModificationDate() #init _OAImodificationDS value if it don't exist idxPu = indexes.IndexesHolder().getById("OAIContributionModificationDate") idxPr = indexes.IndexesHolder().getById("OAIPrivateContributionModificationDate") if self.hasAnyProtection(): if self in idxPu.getContributions(self._OAImodificationDS.strftime("%Y-%m-%d"), self._OAImodificationDS.strftime("%Y-%m-%d")): #The contribution was public and is now private idxPu.unindexContribution(self) for subContrib in self.getSubContributionList(): idxPu.unindexContribution(subContrib) if not date: date = nowutc() self._OAImodificationDS = date self._p_changed=1 idxPr.indexContribution(self) for subContrib in self.getSubContributionList(): idxPr.indexContribution(subContrib) elif self in idxPr.getContributions(self._OAImodificationDS.strftime("%Y-%m-%d"), self._OAImodificationDS.strftime("%Y-%m-%d")): #The contribution is already indexed in private # if force: idxPr.unindexContribution(self) for subContrib in self.getSubContributionList(): idxPr.unindexContribution(subContrib) if not date: date = nowutc() self._OAImodificationDS = date idxPr.indexContribution(self) for subContrib in self.getSubContributionList(): idxPr.indexContribution(subContrib) else: #The contribution wasn't indexed before and is private if not date: date = nowutc() self._OAImodificationDS = date self._p_changed=1 idxPr.indexContribution(self) for subContrib in self.getSubContributionList(): idxPr.indexContribution(subContrib) else: if self in idxPr.getContributions(self.getOAIModificationDate().strftime("%Y-%m-%d"), self.getOAIModificationDate().strftime("%Y-%m-%d")): #The contribution was private and is now public idxPr.unindexContribution(self) for subContrib in self.getSubContributionList(): idxPr.unindexContribution(subContrib) if not date: date = nowutc() self._OAImodificationDS = date idxPu.indexContribution(self) for subContrib in self.getSubContributionList(): idxPu.indexContribution(subContrib) elif self in idxPu.getContributions(self.getOAIModificationDate().strftime("%Y-%m-%d"), self.getOAIModificationDate().strftime("%Y-%m-%d")): #The contribution is already indexed in public, reIndex it with new date idxPu.unindexContribution(self) for subContrib in self.getSubContributionList(): idxPu.unindexContribution(subContrib) if not date: date = nowutc() self._OAImodificationDS = date idxPu.indexContribution(self) for subContrib in self.getSubContributionList(): idxPu.indexContribution(subContrib) else: #The contribution wasn't indexed before and is public if not date: date = nowutc() self._OAImodificationDS = date idxPu.indexContribution(self) for subContrib in self.getSubContributionList(): idxPu.indexContribution(subContrib) def getOAIModificationDate(self): try: return self._OAImodificationDS except: self._OAImodificationDS = self._modificationDS return self._OAImodificationDS def getCategoriesPath(self): return self.getConference().getCategoriesPath() def getModifKey( self ): return self.getConference().getModifKey() def getAccessKey( self ): return self.getConference().getAccessKey() def getLocator( self ): """Gives back a globaly unique identification encapsulated in a Locator object for the contribution instance """ if self.getConference() == None: return Locator() lconf = self.getConference().getLocator() if self.getSession() is not None: lconf["sessionId"] = self.getSession().getId() lconf["contribId"] = self.getId() return lconf def _setConference( self, conf ): self.parent = conf def _setId( self, id ): self.id = id def includeInConference( self, conf, id ): """sets the conference of a contribution """ if self.getConference() is not None: #raise MaKaCError("the contribution is already included in a conference") pass else: self._setConference( conf ) self._setId( id ) def unindex( self ): indexes.IndexesHolder().getById("OAIContributionModificationDate").unindexContribution(self) indexes.IndexesHolder().getById("OAIPrivateContributionModificationDate").unindexContribution(self) def delete( self ): """deletes a contribution and all of its subitems """ self.unindex() if self.getConference() is not None: #index a DeletedObject to keep track of the contribution after the deletion DeletedObjectHolder().add(DeletedObject(self)) self.setTrack(None) self.setSession(None) for mat in self.getMaterialList(): self.removeMaterial(mat) self.removePaper() self.removeSlides() self.removeVideo() self.removePoster() self.removeMinutes() self.removeReviewing() while len(self.getSubContributionList()) > 0: sc = self.getSubContributionList()[0] self.removeSubContribution(sc) # delete it from parent session (if it exists) if self.getOwner() != self.getConference(): self.getOwner().removeContribution( self ) # (always) delete it from the parent conference self.getConference().removeContribution( self, callDelete=False ) self._setConference( None ) self.setStatus(ContribStatusNone(self)) TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def setId( self, newId ): self._setId(newId) def getId( self ): return self.id def getUniqueId( self ): """returns (string) the unique identifier of the item""" """used mainly in the web session access key table""" return "%st%s" % (self.getConference().getUniqueId(),self.id) def setTitle( self, newTitle ): self.title = newTitle.strip() self.notifyModification() def getTitle( self ): if self.title.strip() == "": return "(no title)" return self.title #def setDescription( self, newDesc ): # self.description = newDesc.strip() # self.notifyModification() # #def getDescription( self ): # return self.description # def getDescription(self): return self.getField("content") def setDescription(self, desc): self.setField("content", desc) def setParent(self,parent): self.parent=parent self.notifyModification() if self.parent==None: return def getParent( self ): if self.getSession() is not None: return self.getSession() return self.getConference() def getOwner( self ): return self.getParent() def setOwner(self, owner): self.setParent(owner) def getConference( self ): return self.parent def getSession( self ): try: if self._session: pass except AttributeError: self._session=None return self._session def setSession(self,session): if self.getSession()==session: return if self.isScheduled(): schEntry=self.getSchEntry() schEntry.getSchedule().removeEntry(schEntry) oldSession=self.getSession() if oldSession is not None: oldSession.removeContribution(self) self._session=session if session is not None: session.addContribution(self) def getContribution(self): return self def _resetSchEntry(self): self.__schEntry=ContribSchEntry(self) def getSchEntry(self): if self.__schEntry is None or \ not isinstance(self.__schEntry,ContribSchEntry): self._resetSchEntry() return self.__schEntry def isScheduled(self): #For the moment we do it like this return self.getSchEntry().getSchedule() is not None def isWithdrawn(self): return isinstance(self.getCurrentStatus(), ContribStatusWithdrawn) def getLocationParent( self ): """ Returns the object from which the room/location information should be inherited """ if not self.getConference().getEnableSessionSlots() and self.getSession(): return self.getSession() if self.isScheduled(): return self.getSchEntry().getSchedule().getOwner() return self.getOwner() def getLocation( self ): if self.getOwnLocation(): return self.getOwnLocation() return self.getInheritedLocation() def getInheritedLocation(self): return self.getLocationParent().getLocation() def getOwnLocation( self ): return self.place def setLocation( self, newLocation ): self.place = newLocation self.notifyModification() def getRoom( self ): if self.getOwnRoom(): return self.getOwnRoom() return self.getInheritedRoom() def getInheritedRoom(self): return self.getLocationParent().getRoom() def getOwnRoom( self ): return self.room def setRoom( self, newRoom ): self.room = newRoom self.notifyModification() def setBoardNumber(self,newBoardNum): self._boardNumber=str(newBoardNum).strip() def getBoardNumber(self): try: if self._boardNumber: pass except AttributeError: self._boardNumber="" return self._boardNumber def verifyStartDate(self, sDate, check=2): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" tz = timezone(self.getConference().getTimezone()) if self.getSchEntry().getSchedule(): owner = self.getSchEntry().getSchedule().getOwner() else: owner = self.getOwner() if sDate < owner.getStartDate(): if check == 1: raise ParentTimingError(_("The contribution \"%s\" cannot start before (%s) its parent (%s)") %\ (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\ _("Contribution")) if check == 2: ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED", owner, sDate.astimezone(tz))) owner.setDates(sDate,owner.getEndDate(), check) if sDate > owner.getEndDate(): if check == 1: raise ParentTimingError(_("The contribution \"%s\" cannot start after (%s) its parent end date(%s)") %\ (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\ _("Contribution")) if check == 2: owner.setEndDate(sDate+self.getDuration(),check) # Check that after modifying the start date, the end date is still within the limits of the slot if self.getDuration() and sDate + self.getDuration() > owner.getEndDate(): if check==1: raise ParentTimingError("The contribution cannot end after (%s) its parent ends (%s)"%\ (self.getAdjustedEndDate().strftime('%Y-%m-%d %H:%M'),\ owner.getAdjustedEndDate().strftime('%Y-%m-%d %H:%M')),\ _("Contribution")) elif check==2: # update the schedule owner.setEndDate(sDate + self.getDuration(),check) ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED", owner, owner.getAdjustedEndDate())) def setStartDate(self, newDate, check=2, moveEntries=0): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" if newDate == None: self.startDate=None return if not newDate.tzname(): raise MaKaCError("date should be timezone aware") if newDate != None and check != 0: self.verifyStartDate(newDate, check) self.startDate=copy.copy(newDate) self.getSchEntry().synchro() self.notifyModification() def getStartDate( self ): return self.startDate def getAdjustedStartDate(self,tz=None): if self.getStartDate() is None: return None if not tz: tz = self.getConference().getTimezone() if tz not in all_timezones: tz = 'UTC' return self.getStartDate().astimezone(timezone(tz)) def getEndDate( self ): if self.getStartDate() is None: return None return self.getStartDate()+self.getDuration() def getAdjustedEndDate(self,tz=None): if not tz: tz = self.getConference().getTimezone() if tz not in all_timezones: tz = 'UTC' if self.getEndDate(): return self.getEndDate().astimezone(timezone(tz)) return None def getDuration( self ): return self.duration def verifyDuration(self, check=2): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" tz = timezone(self.getConference().getTimezone()) endDate = self.getEndDate() if self.getSchEntry().getSchedule() is not None: owner = self.getSchEntry().getSchedule().getOwner() if endDate > owner.getEndDate(): if check==1: raise ParentTimingError(_("The contribution \"%s\" ending date (%s) has to fit between its parent's dates (%s - %s)") %\ (self.getTitle(), endDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M'),\ owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\ _("Contribution")) elif check==2: ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED", owner, self.getAdjustedEndDate())) owner.setEndDate(endDate, check) def setDuration(self,hours=0,minutes=15,check=2,dur=0): """check parameter: 0: no check at all 1: check and raise error in case of problem 2: check and adapt the owner dates""" if dur!=0: self.duration=dur else: self.duration=timedelta(hours=int(hours),minutes=int(minutes)) if check != 0: self.verifyDuration(check) self.getSchEntry().synchro() self.notifyModification() def _addAuthor( self, part ): """ """ try: if self._authors: pass except AttributeError: self._authors = OOBTree() try: if self._authorGen: pass except AttributeError: self._authorGen=Counter() newId = part.getId() if newId == "": newId = str( self._authorGen.newCount() ) self._authors[newId] = part part.includeInContribution( self, newId ) def _removeAuthor( self, part ): """ """ try: if self._authors: pass except AttributeError: self._authors = OOBTree() if not self._authors.has_key( part.getId() ): return del self._authors[ part.getId() ] part.delete() def addPrimaryAuthor( self, part ): """ """ try: if self._primaryAuthors: pass except AttributeError: self._primaryAuthors = [] self._addAuthor( part ) self._primaryAuthors.append( part ) if self.getConference() is not None: self.getConference().indexAuthor(part) self.notifyModification() def removePrimaryAuthor( self, part, removeSpeaker=1, removePendingSubm=True): """ """ try: if self._primaryAuthors: pass except AttributeError: self._primaryAuthors = [] if part not in self._primaryAuthors: return if self.getConference() is not None: self.getConference().unindexAuthor(part) self._primaryAuthors.remove( part ) if removeSpeaker: self.removeSpeaker( part ) self._removeAuthor( part ) if removePendingSubm: #--Pending queue: remove pending participant waiting to became submitter if anything self.getConference().getPendingQueuesMgr().removePendingSubmitter(part) #-- self.notifyModification() def recoverPrimaryAuthor(self, pa, isPendingSubmitter): self.addPrimaryAuthor(pa) pa.recover() if isPendingSubmitter: self.getConference().getPendingQueuesMgr().addPendingSubmitter(pa, False) def isPrimaryAuthor( self, part ): """ """ try: if self._primaryAuthors: pass except AttributeError: self._primaryAuthors = [] return part in self._primaryAuthors def upPrimaryAuthor(self,part): """ """ try: if self._primaryAuthors: pass except AttributeError: self._primaryAuthors=[] try: idx=self._primaryAuthors.index(part) except ValueError: return if idx==0: return self._primaryAuthors.remove(part) self._primaryAuthors.insert(idx-1,part) self.notifyModification() def downPrimaryAuthor(self,part): """ """ try: if self._primaryAuthors: pass except AttributeError: self._primaryAuthors=[] try: idx=self._primaryAuthors.index(part) except ValueError: return if idx>len(self._primaryAuthors): return self._primaryAuthors.remove(part) self._primaryAuthors.insert(idx+1,part) self.notifyModification() def upCoAuthor(self,part): """ """ try: if self._coAuthors: pass except AttributeError: self._coAuthors=[] try: idx=self._coAuthors.index(part) except ValueError: return if idx==0: return self._coAuthors.remove(part) self._coAuthors.insert(idx-1,part) self.notifyModification() def downCoAuthor(self,part): """ """ try: if self._coAuthors: pass except AttributeError: self._coAuthors=[] try: idx=self._coAuthors.index(part) except ValueError: return if idx>len(self._coAuthors): return self._coAuthors.remove(part) self._coAuthors.insert(idx+1,part) self.notifyModification() def getPrimaryAuthorList( self ): """ """ try: if self._primaryAuthors: pass except AttributeError: self._primaryAuthors = [] return self._primaryAuthors getPrimaryAuthorsList = getPrimaryAuthorList def getAuthorList( self ): """ """ try: if self._authors: pass except AttributeError: self._authors = OOBTree() return self._authors.values() def addCoAuthor( self, part ): """ """ try: if self._coAuthors: pass except AttributeError: self._coAuthors = [] self._addAuthor( part ) self._coAuthors.append( part ) if self.getConference() is not None: self.getConference().indexAuthor(part) self.notifyModification() def removeCoAuthor( self, part, removeSpeaker=1, removePendingSubm=True): """ """ try: if self._coAuthors: pass except AttributeError: self._coAuthors = [] if part not in self._coAuthors: return if self.getConference() is not None: self.getConference().unindexAuthor(part) self._coAuthors.remove( part ) if removeSpeaker: self.removeSpeaker( part ) self._removeAuthor( part ) if removePendingSubm: #--Pending queue: remove pending participant waiting to became submitter if anything self.getConference().getPendingQueuesMgr().removePendingSubmitter(part) #-- self.notifyModification() def recoverCoAuthor(self, ca, isPendingSubmitter): self.addCoAuthor(ca) ca.recover() if isPendingSubmitter: self.getConference().getPendingQueuesMgr().addPendingSubmitter(ca, False) def isCoAuthor( self, part ): """ """ try: if self._primaryAuthors: pass except AttributeError: self._primaryAuthors = [] return part in self._coAuthors def getCoAuthorList( self ): """ """ try: if self._coAuthors: pass except AttributeError: self._coAuthors = [] return self._coAuthors def getAuthorById( self, id ): """ """ try: if self._authors: pass except AttributeError: self._authors = OOBTree() return self._authors.get( id.strip(), None ) def isAuthor( self, part ): """ """ try: if self._authors: pass except AttributeError: self._authors = OOBTree() return self._authors.has_key( part.getId() ) def getSpeakerById( self, id ): """ """ try: if self._speakers: pass except AttributeError: self._speakers = [] for spk in self._speakers: if spk.getId() == id: return spk return None def addSpeaker( self, part ): """ Adds a speaker (ContributionParticipation object) to the contribution forcing it to be one of the authors of the contribution """ try: if self._speakers: pass except AttributeError: self._speakers = [] if not self.isAuthor( part ): raise MaKaCError( _("The Specified speaker is not the Author"), _("Contribution")) self._speakers.append( part ) if self.getConference() is not None: self.getConference().indexSpeaker(part) self.notifyModification() def newSpeaker( self, part ): """ Adds a new speaker (ContributionParticipation object) to the contribution setting the speakers ID and the fact it belongs to that contribution """ try: if self._speakers: pass except AttributeError: self._speakers = [] try: if self._authorGen: pass except AttributeError: self._authorGen=Counter() self._speakers.append( part ) newId = part.getId() if newId == "": newId = str( self._authorGen.newCount() ) part.includeInContribution(self, newId) if self.getConference() is not None: self.getConference().indexSpeaker(part) self.notifyModification() def removeSpeaker( self, part ): """ """ try: if self._speakers: pass except AttributeError: self._speakers = [] if part not in self._speakers: return self._speakers.remove( part ) if self.getConference() is not None: self.getConference().unindexSpeaker(part) if part not in self.getAuthorList(): part.delete() #--Pending queue: remove pending participant waiting to became submitter if anything self.getConference().getPendingQueuesMgr().removePendingSubmitter(part) #-- self.notifyModification() def recoverSpeaker(self, spk, isPendingSubmitter): self.newSpeaker(spk) spk.recover() if isPendingSubmitter: self.getConference().getPendingQueuesMgr().addPendingSubmitter(spk, False) def isSpeaker( self, part ): """ """ try: if self._speakers: pass except AttributeError: self._speakers = [] return part in self._speakers def getSpeakerList ( self ): """ """ try: if self._speakers: pass except AttributeError: self._speakers = [] return self._speakers def getSpeakerText( self ): #to be removed try: if self.speakerText: pass except AttributeError, e: self.speakerText = "" return self.speakerText def setSpeakerText( self, newText ): self.speakerText = newText.strip() def appendSpeakerText( self, newText ): self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) ) def canIPAccess( self, ip ): try: return self._v_canipaccess[ip] except AttributeError: self._v_canipaccess = {} except KeyError: pass if not self.__ac.canIPAccess( ip ): self._v_canipaccess[ip] = False return self._v_canipaccess[ip] if self.getOwner() != None: self._v_canipaccess[ip] = self.getOwner().canIPAccess(ip) return self._v_canipaccess[ip] self._v_canipaccess[ip] = True return self._v_canipaccess[ip] def isProtected( self ): # tells if a contribution is protected or not return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0 def getAccessProtectionLevel( self ): return self.__ac.getAccessProtectionLevel() def isItselfProtected( self ): return self.__ac.isItselfProtected() def hasAnyProtection( self ): """Tells whether a contribution has any kind of protection over it: access or domain protection. """ if self.__ac.isProtected(): return True if self.getDomainList(): return True if self.getAccessProtectionLevel() == -1: return False if self.getOwner(): return self.getOwner().hasAnyProtection() else: return False def hasProtectedOwner( self ): if self.getOwner() != None: return self.getOwner().isProtected() return False def setProtection( self, private ): self.__ac.setProtection( private ) self.updateFullyPublic() self.notifyOAIModification() def grantAccess( self, prin ): self.__ac.grantAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "access") self.resetAccessCache() def revokeAccess( self, prin ): self.__ac.revokeAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "access") self.resetAccessCache() def canView( self, aw ): """tells whether the specified user has access to the current object or any of its sub-objects """ if self.canAccess( aw ): return True for sc in self.getSubContributionList(): if sc.canView( aw ): return True return False def isAllowedToAccess( self, user ): if not user: return False try: return self._v_isallowedtoaccess[user] except AttributeError: self._v_isallowedtoaccess = {} except KeyError: pass self._v_isallowedtoaccess[user] = (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or\ self.__ac.canUserAccess( user ) or\ self.canUserModify( user ) or \ self.canUserSubmit(user) return self._v_isallowedtoaccess[user] def canAccess( self, aw ): try: return self._v_canaccess[aw] except AttributeError: self._v_canaccess = {} except KeyError: pass # Allow harvesters (Invenio, offline cache) to access # protected pages if self.__ac.isHarvesterIP(aw.getIP()): self._v_canaccess[aw] = True return True ##################################################### if self.canModify(aw): self._v_canaccess[aw] = True return True if not self.canIPAccess(aw.getIP()) and not self.isAllowedToAccess( aw.getUser() ): self._v_canaccess[aw] = False return False if not self.isProtected(): self._v_canaccess[aw] = True return True flag = self.isAllowedToAccess( aw.getUser() ) self._v_canaccess[aw] = flag or self.getConference().canKeyAccess(aw) return self._v_canaccess[aw] def resetAccessCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canaccess"): del self._v_canaccess if hasattr(self,"_v_isallowedtoaccess"): del self._v_isallowedtoaccess if hasattr(self,"_v_canipaccess"): del self._v_canipaccess if UP: self.getParent().resetAccessCache(True, False) if DOWN: for subc in self.getSubContributionList(): subc.resetAccessCache(False, True) for mat in self.getMaterialList(): mat.resetAccessCache(False, True) def resetModifyCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canmodify"): del self._v_canmodify if hasattr(self,"_v_canusermodify"): del self._v_canusermodify if UP and DOWN: self.resetAccessCache(UP, DOWN) if UP: self.getParent().resetModifyCache(True, False) if DOWN: for subc in self.getSubContributionList(): subc.resetAccessCache(False, True) for mat in self.getMaterialList(): mat.resetModifyCache(False, True) def grantModification( self, prin ): self.__ac.grantModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "manager") self.resetModifyCache() def revokeModification( self, prin ): self.__ac.revokeModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "manager") self.resetModifyCache() def canModify( self, aw ): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw ) return self._v_canmodify[aw] def canUserModify( self, av ): """Tells whether a user is allowed to modify the current contribution: only if the user is granted to modify the contribution or the user can modify any of its upper objects (i.e. conference or session). """ try: return self._v_canusermodify[av] except AttributeError: self._v_canusermodify = {} except KeyError: pass self._v_canusermodify[av] = self.getParent().canUserModify( av ) or self.__ac.canModify( av ) return self._v_canusermodify[av] def getManagerList( self ): return self.__ac.getModifierList() def getAllowedToAccessList( self ): return self.__ac.getAccessList() def addMaterial( self, newMat ): newMat.setId( str(self.__materialGenerator.newCount()) ) newMat.setOwner( self ) self.materials[ newMat.getId() ] = newMat self.notifyModification() def removeMaterial( self, mat ): if mat.getId() in self.materials.keys(): self.materials[mat.getId()].setOwner(None) del self.materials[ mat.getId() ] mat.delete() self.notifyModification() elif mat.getId().lower() == 'paper': self.removePaper() self.notifyModification() elif mat.getId().lower() == 'slides': self.removeSlides() self.notifyModification() elif mat.getId().lower() == 'minutes': self.removeMinutes() self.notifyModification() elif mat.getId().lower() == 'video': self.removeVideo() self.notifyModification() elif mat.getId().lower() == 'poster': self.removePoster() self.notifyModification() elif mat.getId().lower() == 'reviewing': self.removeReviewing() self.notifyModification() def recoverMaterial(self, recMat): # Id must already be set in recMat. recMat.setOwner( self ) self.materials[ recMat.getId() ] = recMat recMat.recover() self.notifyModification() def getMaterialRegistry(self): """ Return the correct material registry for this type """ from MaKaC.webinterface.materialFactories import ContribMFRegistry return ContribMFRegistry def getMaterialById( self, matId ): if matId.lower() == 'paper': return self.getPaper() elif matId.lower() == 'slides': return self.getSlides() elif matId.lower() == 'video': return self.getVideo() elif matId.lower() == 'poster': return self.getPoster() elif matId.lower() == 'minutes': return self.getMinutes() elif matId.lower() == 'reviewing': return self.getReviewing() elif self.materials.has_key(matId): return self.materials[ matId ] return None def getMaterialList( self ): return self.materials.values() def getAllMaterialList( self ): l = self.getMaterialList() if self.getPaper(): l.append( self.getPaper() ) if self.getSlides(): l.append( self.getSlides() ) if self.getVideo(): l.append( self.getVideo() ) if self.getPoster(): l.append( self.getPoster() ) if self.getMinutes(): l.append( self.getMinutes() ) if self.getReviewing(): l.append( self.getReviewing() ) l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle())) return l def newSubContribution(self): newSub = SubContribution() self.addSubContribution(newSub) return newSub def addSubContribution( self, newSubCont ): newSubCont.setId(str( self.__subContGenerator.newCount()) ) newSubCont.setOwner( self ) self._subConts.append( newSubCont ) self.notifyModification() def removeSubContribution( self, subCont ): if subCont in self._subConts: subCont.delete() subCont.setOwner(None) self._subConts.remove(subCont) self.notifyModification() def recoverSubContribution( self, recSubCont ): # Id must already be set in recSubCont. recSubCont.setOwner( self ) self._subConts.append( recSubCont ) recSubCont.recover() self.notifyModification() def getSubContributionById(self, SCId): for sb in self._subConts: if sb.getId() == SCId: return sb def getSubContributionList(self): return self._subConts def upSubContribution(self, subcont): if subcont in self._subConts: if self._subConts.index(subcont) != 0: index = self._subConts.index(subcont) sb = self._subConts.pop(index) self._subConts.insert(index-1, sb) self.notifyModification() def downSubContribution(self, subCont): if subCont in self._subConts: if self._subConts.index(subCont) < len(self._subConts)-1: index = self._subConts.index(subCont) sb = self._subConts.pop(index) self._subConts.insert(index+1, sb) self.notifyModification() def setPaper( self, newPaper ): if self.getPaper() != None: raise MaKaCError( _("The paper for this contribution has already been set"), _("Contribution")) self.paper=newPaper self.paper.setOwner( self ) self.notifyModification() def removePaper( self ): if self.paper is None: return self.paper.delete() self.paper.setOwner(None) self.paper = None self.notifyModification() def recoverPaper(self, p): self.setPaper(p) p.recover() def getPaper( self ): return self.paper def setSlides( self, newSlides ): if self.getSlides() != None: raise MaKaCError( _("The slides for this contribution have already been set"), _("contribution")) self.slides=newSlides self.slides.setOwner( self ) self.notifyModification() def removeSlides( self ): if self.slides is None: return self.slides.delete() self.slides.setOwner( None ) self.slides= None self.notifyModification() def recoverSlides(self, s): self.setSlides(s) s.recover() def getSlides( self ): return self.slides def setVideo( self, newVideo ): if self.getVideo() != None: raise MaKaCError( _("the video for this contribution has already been set")) self.video=newVideo self.video.setOwner( self ) self.notifyModification() def removeVideo( self ): if self.getVideo() is None: return self.video.delete() self.video.setOwner(None) self.video = None self.notifyModification() def recoverVideo(self, v): self.setVideo(v) v.recover() def getVideo( self ): try: if self.video: pass except AttributeError: self.video = None return self.video def setPoster( self, newPoster ): if self.getPoster() != None: raise MaKaCError( _("the poster for this contribution has already been set")) self.poster=newPoster self.poster.setOwner( self ) self.notifyModification() def removePoster( self ): if self.getPoster() is None: return self.poster.delete() self.poster.setOwner(None) self.poster = None self.notifyModification() def recoverPoster(self, p): self.setPoster(p) p.recover() def getPoster( self ): try: if self.poster: pass except AttributeError: self.poster = None return self.poster def setMinutes( self, newMinutes ): if self.getMinutes() != None: raise MaKaCError( _("the Minutes for this contribution has already been set")) self.minutes=newMinutes self.minutes.setOwner( self ) self.notifyModification() def createMinutes( self ): if self.getMinutes() != None: raise MaKaCError( _("The minutes for this contribution have already been created"), _("Contribution")) self.minutes = Minutes() self.minutes.setOwner( self ) self.notifyModification() return self.minutes def removeMinutes( self ): if self.getMinutes() is None: return self.minutes.delete() self.minutes.setOwner( None ) self.minutes = None self.notifyModification() def recoverMinutes(self, min): self.removeMinutes() # To ensure that the current minutes are put in # the trash can. self.minutes = min self.minutes.setOwner( self ) min.recover() self.notifyModification() return self.minutes def getMinutes( self ): #To be removed try: if self.minutes: pass except AttributeError, e: self.minutes = None return self.minutes def setReviewing( self, newReviewing ): if self.getReviewing() != None: raise MaKaCError( _("The reviewing maretial for this contribution has already been set"), _("Contribution")) self.reviewing=newReviewing self.reviewing.setOwner( self ) self.notifyModification() def removeReviewing( self ): if self.reviewing is None: return self.reviewing.delete() self.reviewing.setOwner(None) self.reviewing = None self.notifyModification() def recoverReviewing(self, p): self.setReviewing(p) p.recover() def getReviewing( self ): return self.reviewing def getMasterSchedule( self ): return self.getOwner().getSchedule() def requireDomain( self, dom ): self.__ac.requireDomain( dom ) self.resetAccessCache() self.notifyOAIModification() def freeDomain( self, dom ): self.__ac.freeDomain( dom ) self.resetAccessCache() self.notifyOAIModification() def getDomainList( self ): return self.__ac.getRequiredDomainList() def getTrack( self ): try: if self._track: pass except AttributeError: self._track = None return self._track def setTrack( self, newTrack ): currentTrack = self.getTrack() if newTrack == currentTrack: return if currentTrack: currentTrack.removeContribution( self ) self._track = newTrack if self._track: self._track.addContribution( self ) def removeTrack(self, track): if track == self._track: self._track = None def setType( self, newType ): self._type = newType def getType( self ): try: if self._type: pass except AttributeError: self._type = None return self._type def getModificationDate( self ): """Returns the date in which the contribution was last modified""" try: return self._modificationDS except: if self.getConference(): self._modificationDS = self.getConference().getModificationDate() else: self._modificationDS = nowutc() return self._modificationDS def getCurrentStatus(self): try: if self._status: pass except AttributeError: self._status=ContribStatusNotSch(self) return self._status getStatus = getCurrentStatus def setStatus(self,newStatus): """ """ self._status=newStatus def withdraw(self,resp,comment): """ Remove or put a contribution in a conference """ if self.isWithdrawn(): #put back the authors in the author index for auth in self.getAuthorList(): self.getConference().getAuthorIndex().index(auth) for spk in self.getSpeakerList(): self.getConference().getSpeakerIndex().index(spk) #change the status of the contribution self._status=ContribStatusNotSch(self) else: #remove the authors from the author index if self.getConference() is not None: for auth in self.getAuthorList(): self.getConference().getAuthorIndex().unindex(auth) for spk in self.getSpeakerList(): self.getConference().unindexSpeaker(spk) #remove the contribution from any schedule it is included if self.isScheduled(): self.getSchEntry().getSchedule().removeEntry(self.getSchEntry()) self.getCurrentStatus().withdraw(resp,comment) def _initSubmissionPrivileges(self): """Initialises submission privileges list for a contribution. This is a temporary function used for creating the attribute in the case it does not exist into the DB """ try: if self._submitters: pass except AttributeError: self._submitters=[] #create the attribute self.notifyModification(oai=False) def _grantSubmission(self,av): if av not in self._submitters: self._submitters.append(av) if self.getConference() is not None: self.getConference().addContribSubmitter(self,av) if isinstance(av, MaKaC.user.Avatar): av.linkTo(self, "submission") self.notifyModification(oai=False) def _grantSubmissionEmail(self, email): if not email in self.getSubmitterEmailList(): self.getSubmitterEmailList().append(email.lower()) def revokeSubmissionEmail(self, email): if email in self.getSubmitterEmailList(): self.getSubmitterEmailList().remove(email) self._p_changed=1 def grantSubmission(self,sb, sendEmail=True): """Grants a user with submission privileges for the contribution - sb: can be an Avatar or an Author (primary author, co-author, speaker) """ self._initSubmissionPrivileges() if isinstance(sb, ContributionParticipation) or isinstance(sb, SubContribParticipation): ah = AvatarHolder() results=ah.match({"email":sb.getEmail()}, exact=1) r=None for i in results: if i.hasEmail(sb.getEmail()): r=i break if r is not None and r.isActivated(): self._grantSubmission(r) elif sb.getEmail() != "": self.getConference().getPendingQueuesMgr().addPendingSubmitter(sb, False) self._grantSubmissionEmail(sb.getEmail()) #send email once try : self._v_emailSent except: self._v_emailSent = [] if sendEmail and not sb.getEmail() in self._v_emailSent: self._v_emailSent.append(sb.getEmail()) notif = pendingQueues._PendingSubmitterNotification( [sb] ) mail.GenericMailer.sendAndLog( notif, self.getConference() ) if self.getConference() is not None: self.getConference()._getSubmitterIdx().indexEmail(sb.getEmail(),self) else: self._grantSubmission(sb) def _revokeSubmission(self,av): if av in self._submitters: self._submitters.remove(av) if self.getConference() is not None: self.getConference().removeContribSubmitter(self,av) if isinstance(av, MaKaC.user.Avatar): av.unlinkTo(self, "submission") self.notifyModification(oai=False) def revokeSubmission(self,av): """Removes submission privileges for the specified user """ self._initSubmissionPrivileges() self._revokeSubmission(av) def revokeAllSubmitters(self): self._submitters=[] self.notifyModification(oai=False) def getSubmitterList(self): """Gives the list of users granted with submission privileges """ self._initSubmissionPrivileges() return self._submitters def getSubmitterEmailList(self): try: return self._submittersEmail except: self._submittersEmail = [] return self._submittersEmail def canUserSubmit(self,av): """Tells whether a user can submit material for the current contribution """ if av is None: return False self._initSubmissionPrivileges() for principal in self._submitters: if principal != None and principal.containsUser( av ): return True ret = False #TODO: Remove this and use pending list if isinstance(av, MaKaC.user.Avatar): for email in av.getEmails(): if email.lower() in self.getSubmitterEmailList(): self.grantSubmission(av) self.revokeSubmissionEmail(email) ret = True return ret def getAccessController(self): return self.__ac def getReportNumberHolder(self): try: if self._reportNumberHolder: pass except AttributeError, e: self._reportNumberHolder=ReportNumberHolder(self) return self._reportNumberHolder def setReportNumberHolder(self, rnh): self._reportNumberHolder=rnh @classmethod def contributionStartDateForSort(cls, contribution): """ Function that can be used as "key" argument to sort a list of contributions by start date The contributions with no start date will be at the end with this sort """ if contribution.getStartDate(): return contribution.getStartDate() else: return maxDatetime() def getColor(self): res="" if self.getSession() is not None: res=self.getSession().getColor() return res def getTextColor(self): res="" if self.getSession() is not None: res=self.getSession().getTextColor() return res class AcceptedContribution( Contribution ): """This class represents a contribution which has been created from an abstract """ def __init__(self,abstract): Contribution.__init__(self) abstract.getConference().addContribution(self,abstract.getId()) self._abstract = abstract self.setTitle( abstract.getTitle() ) #self.setDescription(abstract.getField("content")) for key in abstract.getFields().keys(): #if key != "content": self.setField(key, abstract.getField(key)) if isinstance( abstract.getCurrentStatus(),review.AbstractStatusAccepted ): self.setTrack( abstract.getCurrentStatus().getTrack() ) self.setType( abstract.getCurrentStatus().getType() ) for auth in abstract.getAuthorList(): c_auth = ContributionParticipation() self._setAuthorValuesFromAbstract( c_auth, auth ) if abstract.isPrimaryAuthor( auth ): self.addPrimaryAuthor( c_auth ) else: self.addCoAuthor( c_auth ) if abstract.isSpeaker( auth ): self.addSpeaker( c_auth ) self._grantSubmission(self.getAbstract().getSubmitter().getUser()) def _setAuthorValuesFromAbstract( self, cAuth, aAuth ): cAuth.setTitle( aAuth.getTitle() ) cAuth.setFirstName( aAuth.getFirstName() ) cAuth.setFamilyName( aAuth.getSurName() ) cAuth.setEmail( aAuth.getEmail() ) cAuth.setAffiliation( aAuth.getAffiliation() ) cAuth.setAddress( aAuth.getAddress() ) cAuth.setPhone( aAuth.getTelephone() ) def getAbstract( self ): return self._abstract def setAbstract(self, abs): self._abstract = abs def _initSubmissionPrivileges(self): """Initialises submission privileges list for a contribution. In the case of an AcceptedContribution, the list of submitters must be initialised with the abstract's one. This is a temporary function used for creating the attribute in the case it does not exist into the DB """ try: if self._submitters: pass except AttributeError: self._submitters=[]#create the attribute self._grantSubmission(self.getAbstract().getSubmitter().getUser()) def delete( self ): """deletes a contribution and all of their subitems """ abs = self.getAbstract() if abs: cs=abs.getCurrentStatus() if isinstance(cs, review.AbstractStatusAccepted): if cs.getTrack() is not None: abs.addTrack(cs.getTrack()) abs.setCurrentStatus(review.AbstractStatusSubmitted(abs)) abs._setContribution(None) self.setAbstract(None) Contribution.delete(self) class ContribStatus(Persistent): """ """ def __init__(self,contribution,responsible): self._setContrib(contribution) self._setResponsible(responsible) self._setDate() def clone(self, contribution, responsible): cs = ContribStatus(contribution, responsible) cs.setDate(self.getDate()) return cs def _setContrib(self,newContrib): self._contrib=newContrib def getContrib(self): return self._contrib def _setResponsible(self,newResp): self._responsible=newResp def getResponsible(self): return self._responsible def _setDate(self): self._date=nowutc() def setDate(self, date): self._date = date def getDate(self): return self._date def withdraw(self,resp,comments=""): self._contrib.setStatus(ContribStatusWithdrawn(self.getContrib(),resp,comments)) class ContribStatusNotSch(ContribStatus): """ """ def __init__(self,contrib): ContribStatus.__init__(self,contrib,None) def clone(self, contribution): csns = ContribStatusNotSch(contribution) csns.setDate(self.getDate()) return csns ContribStatusSubmitted=ContribStatusNotSch class ContribStatusSch(ContribStatus): """ """ def __init__(self,contrib): ContribStatus.__init__(self,contrib,None) def clone(self, contribution): css = ContribStatusSch(contribution) css.setDate(self.getDate()) return css class ContribStatusWithdrawn(ContribStatus): """ """ def __init__(self,contrib,resp,comments): ContribStatus.__init__(self,contrib,resp) self._setComment(comments) def clone(self, contribution): csw = ContribStatusWithdrawn(contribution) csw.setDate(self.getDate()) csw.setComment(self.getComment()) return csw def _setComment(self,text): self._comment=text.strip() def getComment(self): return self._comment class ContribStatusNone(ContribStatus): # This is a special status we assign to contributions that are put in the trash can. def __init__(self,contrib): ContribStatus.__init__(self,contrib,None) def clone(self, contribution): csn = ContribStatusNone(contribution) csn.setDate(self.getDate()) return csn class SubContribParticipation(Persistent, Fossilizable): fossilizes(ISubContribParticipationFossil) def __init__( self ): self._subContrib = None self._id = "" self._firstName = "" self._surName = "" self._email = "" self._affiliation = "" self._address = "" self._phone = "" self._title = "" self._fax = "" def _notifyModification( self ): if self._subContrib != None: self._subContrib.notifyModification() def setValues(self, data): self.setFirstName(data.get("firstName", "")) self.setFamilyName(data.get("familyName","")) self.setAffiliation(data.get("affilation","")) self.setAddress(data.get("address","")) self.setEmail(data.get("email","")) self.setFax(data.get("fax","")) self.setTitle(data.get("title","")) self.setPhone(data.get("phone","")) self._notifyModification() def getValues(self): data={} data["firstName"]=self.getFirstName() data["familyName"]=self.getFamilyName() data["affilation"]=self.getAffiliation() data["address"]=self.getAddress() data["email"]=self.getEmail() data["fax"]=self.getFax() data["title"]=self.getTitle() data["phone"]=self.getPhone() return data def clone(self): part = SubContribParticipation() part.setValues(self.getValues()) return part def setDataFromAvatar(self,av): # av is an Avatar object. if av is None: return self.setFirstName(av.getName()) self.setFamilyName(av.getSurName()) self.setEmail(av.getEmail()) self.setAffiliation(av.getOrganisation()) self.setAddress(av.getAddress()) self.setPhone(av.getTelephone()) self.setTitle(av.getTitle()) self.setFax(av.getFax()) self._notifyModification() def setDataFromAuthor(self,au): # au is a ContributionParticipation object. if au is None: return self.setFirstName(au.getFirstName()) self.setFamilyName(au.getFamilyName()) self.setEmail(au.getEmail()) self.setAffiliation(au.getAffiliation()) self.setAddress(au.getAddress()) self.setPhone(au.getPhone()) self.setTitle(au.getTitle()) self.setFax(au.getFax()) self._notifyModification() def setDataFromSpeaker(self,spk): # spk is a SubContribParticipation object. if spk is None: return self.setFirstName(spk.getFirstName()) self.setFamilyName(spk.getFamilyName()) self.setEmail(spk.getEmail()) self.setAffiliation(spk.getAffiliation()) self.setAddress(spk.getAddress()) self.setPhone(spk.getPhone()) self.setTitle(spk.getTitle()) self.setFax(spk.getFax()) self._notifyModification() def includeInSubContrib( self, subcontrib, id ): if self.getSubContrib() == subcontrib and self.getId()==id.strip(): return self._subContrib = subcontrib self._id = id def delete( self ): self._subContrib = None TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) @Updates ('MaKaC.conference.SubContribParticipation', 'id') def setId(self, newId): self._id = newId def getId( self ): return self._id def getSubContrib( self ): return self._subContrib def getContribution( self ): if self._subContrib is not None: return self._subContrib.getContribution() return None # def getLocator(self): # if self.getSubContrib() is None: # return None # loc=self.getSubContrib().getLocator() # loc["authId"]=self.getId() # return loc def _unindex(self): contrib=self.getContribution() if contrib is not None: conf=contrib.getConference() if conf is not None: conf.unindexAuthor(self) conf.unindexSpeaker(self) def _index(self): contrib=self.getContribution() if contrib is not None: conf=contrib.getConference() if conf is not None: conf.indexAuthor(self) conf.indexSpeaker(self) @Updates ('MaKaC.conference.SubContribParticipation', 'firstName') def setFirstName( self, newName ): tmp=newName.strip() if tmp==self._firstName: return self._unindex() self._firstName=tmp self._index() self._notifyModification() def getFirstName( self ): return self._firstName def getName( self ): return self._firstName @Updates ('MaKaC.conference.SubContribParticipation', 'familyName') def setFamilyName( self, newName ): tmp=newName.strip() if tmp==self._surName: return self._unindex() self._surName=tmp self._index() self._notifyModification() def getFamilyName( self ): return self._surName def getSurName( self ): return self._surName @Updates ('MaKaC.conference.SubContribParticipation', 'email') def setEmail( self, newMail ): tmp=newMail.strip() if tmp==self._email: return self._unindex() self._email=newMail.strip() self._index() self._notifyModification() def getEmail( self ): return self._email @Updates ('MaKaC.conference.SubContribParticipation', 'affiliation') def setAffiliation( self, newAffil ): self._affiliation = newAffil.strip() self._notifyModification() def getAffiliation( self ): return self._affiliation @Updates ('MaKaC.conference.SubContribParticipation', 'address') def setAddress( self, newAddr ): self._address = newAddr.strip() self._notifyModification() def getAddress( self ): return self._address @Updates ('MaKaC.conference.SubContribParticipation', 'phone') def setPhone( self, newPhone ): self._phone = newPhone.strip() self._notifyModification() def getPhone( self ): return self._phone @Updates ('MaKaC.conference.SubContribParticipation', 'title') def setTitle( self, newTitle ): self._title = newTitle.strip() self._notifyModification() def getTitle( self ): return self._title def setFax( self, newFax ): self._fax = newFax.strip() self._notifyModification() def getFax( self ): try: if self._fax: pass except AttributeError: self._fax="" return self._fax def getFullName( self ): res = self.getFamilyName().upper() if self.getFirstName() != "": if res.strip() != "": res = "%s, %s"%( res, self.getFirstName() ) else: res = self.getFirstName() if self.getTitle() != "": res = "%s %s"%( self.getTitle(), res ) return res def getAbrName(self): res = self.getFamilyName() if self.getFirstName() != "": if res != "": res = "%s, "%res res = "%s%s."%(res, self.getFirstName()[0].upper()) return res class SubContribution(Persistent, Fossilizable, CommonObjectBase): """ """ fossilizes(ISubContributionFossil, ISubContributionWithSpeakersFossil) def __init__( self, **subContData ): self.parent = None self.id = "" self.title = "" self.description = "" self.__schEntry = None self.duration = timedelta( minutes=15 ) self.speakers = [] self.speakerText = "" self.materials = {} self.__materialGenerator = Counter() # Provides material unique # identifiers whithin the current self.poster = None # contribution self.paper = None self.slides = None self.video = None self.poster = None self.minutes = None self._authorGen = Counter() self._keywords = "" def isFullyPublic( self ): if hasattr(self, "_fullyPublic"): return self._fullyPublic else: self.setFullyPublic() return self._fullyPublic def setFullyPublic( self ): for res in self.getAllMaterialList(): if not res.isFullyPublic(): self._fullyPublic = False self._p_changed = 1 return self._fullyPublic = True self._p_changed = 1 def updateFullyPublic( self ): self.setFullyPublic() self.getOwner().updateFullyPublic() def getKeywords(self): try: return self._keywords except: self._keywords = "" return "" def setKeywords(self, keywords): self._keywords = keywords def getLogInfo(self): data = {} data["subject"] = self.getTitle() data["id"] = self.id data["title"] = self.title data["parent title"] = self.getParent().getTitle() data["description"] = self.description data["duration"] = "%s"%self.duration data["minutes"] = self.minutes for sp in self.speakers : data["speaker %s"%sp.getId()] = sp.getFullName() return data def clone(self, deltaTime, parent, options): sCont = SubContribution() sCont.setParent(parent) sCont.setTitle(self.getTitle()) sCont.setDescription(self.getDescription()) sCont.setKeywords(self.getKeywords()) dur = self.getDuration() hours = dur.seconds / 3600 minutes = (dur.seconds % 3600) / 60 sCont.setDuration(hours, minutes) sCont.setReportNumberHolder(self.getReportNumberHolder().clone(self)) # There is no _order attribute in this class if options.get("authors", False) : for s in self.getSpeakerList() : sCont.newSpeaker(s.clone()) sCont.setSpeakerText(self.getSpeakerText()) if options.get("materials", False) : for m in self.getMaterialList() : sCont.addMaterial(m.clone(sCont)) if self.getPaper() is not None: sCont.setPaper(self.getPaper().clone(sCont)) if self.getSlides() is not None: sCont.setSlides(self.getSlides().clone(sCont)) if self.getVideo() is not None: sCont.setVideo(self.getVideo().clone(sCont)) if self.getPoster() is not None: sCont.setPoster(self.getPoster().clone(sCont)) if self.getMinutes() is not None: sCont.setMinutes(self.getMinutes().clone(sCont)) sCont.notifyModification() return sCont def notifyModification( self ): parent = self.getParent() if parent: parent.notifyModification() self.notifyOAIModification() self._p_changed = 1 def notifyOAIModification(self, date=None): #, force=False): return self.getParent().notifyOAIModification() def getOAIModificationDate( self ): parent = self.getParent() if parent: return parent.getOAIModificationDate() return nowutc() def getCategoriesPath(self): return self.getConference().getCategoriesPath() def getLocator( self ): """Gives back a globaly unique identification encapsulated in a Locator object for the contribution instance """ lconf = self.getOwner().getLocator() lconf["subContId"] = self.getId() return lconf def setId( self, newId ): self.id = newId def getId( self ): return self.id def getUniqueId( self ): """returns (string) the unique identifier of the item""" """used mainly in the web session access key table""" return "%ssc%s" % (self.getParent().getUniqueId(),self.id) def setTitle( self, newTitle ): self.title = newTitle.strip() self.notifyModification() def getTitle( self ): if self.title.strip() == "": return "(no title)" return self.title def setDescription( self, newDesc ): self.description = newDesc.strip() self.notifyModification() def getDescription( self ): return self.description def setParent(self,parent): self.parent = parent if self.parent == None: return def getParent( self ): return self.parent def setOwner(self, owner): self.setParent(owner) def getOwner( self ): return self.getParent() def getConference( self ): return self.parent.getConference() def getSession( self ): return self.parent.getSession() def getContribution(self): return self.parent def getDuration( self ): return self.duration def setDuration( self, hours, minutes=0, dur=0 ): if dur!=0: self.duration=dur else: hours = int( hours ) minutes = int( minutes ) self.duration = timedelta(hours=hours,minutes=minutes ) self.notifyModification() def getLocation( self ): return self.getOwner().getLocation() def getRoom( self ): return self.getOwner().getRoom() def getSpeakerById( self, id ): """ """ for spk in self.speakers: if spk.getId() == id: return spk return None def newSpeaker( self, spk ): """ """ self.speakers.append( spk ) try: if self._authorGen: pass except AttributeError: self._authorGen=Counter() newId = spk.getId() if newId == "": newId = str( self._authorGen.newCount() ) spk.includeInSubContrib(self, newId) if self.getConference() is not None: self.getConference().indexSpeaker(spk) self.notifyModification() def removeSpeaker( self, spk ): """ """ if spk not in self.speakers: return self.speakers.remove( spk ) if self.getConference() is not None: self.getConference().unindexSpeaker(spk) spk.delete() self.notifyModification() def recoverSpeaker(self, spk): self.newSpeaker(spk) spk.recover() def isSpeaker( self, spk): """ """ return spk in self._speakers def getSpeakerList ( self ): """ """ return self.speakers def getSpeakerText( self ): #to be removed try: if self.speakerText: pass except AttributeError, e: self.speakerText = "" return self.speakerText def setSpeakerText( self, newText ): self.speakerText = newText.strip() def appendSpeakerText( self, newText ): self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) ) # """ # There is no _order attribute in this class - # the methods below are either obsolate or the feature has not been implemented # """ # def setOrder( self, order ): # self._order = order # self.notifyModification() # # def getOrder(self): # return self._order def canIPAccess( self, ip ): #try: # return self._v_canipaccess[ip] #except AttributeError: # self._v_canipaccess = {} #except KeyError: # pass #if self.getOwner() != None: # self._v_canipaccess[ip] = self.getOwner().canIPAccess(ip) # return self._v_canipaccess[ip] #self._v_canipaccess[ip] = True #return self._v_canipaccess[ip] return self.getOwner().canIPAccess(ip) def isProtected( self ): return self.hasProtectedOwner() def getAccessProtectionLevel( self ): return self.getOwner().getAccessProtectionLevel() def hasAnyProtection( self ): """Tells whether a subContribution has any kind of protection over it: access or domain protection. """ return self.getOwner().hasAnyProtection() def hasProtectedOwner( self ): if self.getOwner() != None: return self.getOwner().isProtected() return False def getAccessKey( self ): return self.getOwner().getAccessKey() def getModifKey( self ): return self.getConference().getModifKey() def canView( self, aw ): """tells whether the specified user has access to the current object or any of its sub-objects """ if self.canAccess( aw ): return True return False def isAllowedToAccess( self, user ): return self.parent.isAllowedToAccess( user ) def canAccess( self, aw ): return self.getOwner().canAccess(aw) def canModify( self, aw ): return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw ) def canUserModify( self, av ): """Tells whether a user is allowed to modify the current contribution: only if the user is granted to modify the contribution or the user can modify any of its upper objects (i.e. conference or session). """ return self.getParent().canUserModify( av ) def canUserSubmit( self, av ): return self.getOwner().canUserSubmit( av ) def getAllowedToAccessList( self ): """Currently the SubContribution class has no access list. But instead of returning the owner Contribution's access list, I am returning an empty list. Methods such as getRecursiveAllowedToAccess() will call the owner Contribution anyway. """ return [] def addMaterial( self, newMat ): newMat.setId( str(self.__materialGenerator.newCount()) ) newMat.setOwner( self ) self.materials[ newMat.getId() ] = newMat self.notifyModification() def removeMaterial( self, mat): if mat.getId() in self.materials.keys(): self.materials[mat.getId()].setOwner(None) del self.materials[ mat.getId() ] mat.delete() self.notifyModification() elif mat.getId().lower() == 'paper': self.removePaper() self.notifyModification() elif mat.getId().lower() == 'slides': self.removeSlides() self.notifyModification() elif mat.getId().lower() == 'minutes': self.removeMinutes() self.notifyModification() elif mat.getId().lower() == 'video': self.removeVideo() self.notifyModification() elif mat.getId().lower() == 'poster': self.removePoster() self.notifyModification() def recoverMaterial(self, recMat): # Id must already be set in recMat. recMat.setOwner( self ) self.materials[ recMat.getId() ] = recMat recMat.recover() self.notifyModification() def getMaterialRegistry(self): """ Return the correct material registry for this type """ from MaKaC.webinterface.materialFactories import SubContributionMFRegistry return SubContributionMFRegistry def getMaterialById( self, matId ): if matId.lower() == 'paper': return self.getPaper() elif matId.lower() == 'slides': return self.getSlides() elif matId.lower() == 'video': return self.getVideo() elif matId.lower() == 'poster': return self.getPoster() elif matId.lower() == 'minutes': return self.getMinutes() elif self.materials.has_key(matId): return self.materials[ matId ] return None def getMaterialList( self ): return self.materials.values() def getAllMaterialList( self ): l = self.getMaterialList() if self.getPaper(): l.append( self.getPaper() ) if self.getSlides(): l.append( self.getSlides() ) if self.getVideo(): l.append( self.getVideo() ) if self.getMinutes(): l.append( self.getMinutes() ) if self.getPoster(): l.append( self.getPoster() ) l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle())) return l def setPaper( self, newPaper ): if self.getPaper() != None: raise MaKaCError( _("The paper for this subcontribution has already been set"), _("Contribution")) self.paper=newPaper self.paper.setOwner( self ) self.notifyModification() def removePaper( self ): if self.getPaper() is None: return self.paper.delete() self.paper.setOwner(None) self.paper = None self.notifyModification() def recoverPaper(self, p): self.setPaper(p) p.recover() def getPaper( self ): return self.paper def setSlides( self, newSlides ): if self.getSlides() != None: raise MaKaCError( _("The slides for this subcontribution have already been set"), _("Contribution")) self.slides=newSlides self.slides.setOwner( self ) self.notifyModification() def removeSlides( self ): if self.getSlides() is None: return self.slides.delete() self.slides.setOwner( None ) self.slides = None self.notifyModification() def recoverSlides(self, s): self.setSlides(s) s.recover() def getSlides( self ): return self.slides def setVideo( self, newVideo ): if self.getVideo() != None: raise MaKaCError( _("the video for this subcontribution has already been set")) self.video=newVideo self.video.setOwner( self ) self.notifyModification() def removeVideo( self ): if self.getVideo() is None: return self.video.delete() self.video.setOwner(None) self.video = None self.notifyModification() def recoverVideo(self, v): self.setVideo(v) v.recover() def getVideo( self ): try: if self.video: pass except AttributeError: self.video = None return self.video def setPoster( self, newPoster ): if self.getPoster() != None: raise MaKaCError( _("the poster for this subcontribution has already been set")) self.poster=newPoster self.poster.setOwner( self ) self.notifyModification() def removePoster( self ): if self.getPoster() is None: return self.poster.delete() self.poster.setOwner(None) self.poster = None self.notifyModification() def recoverPoster(self, p): self.setPoster(p) p.recover() def getPoster( self ): try: if self.poster: pass except AttributeError: self.poster = None return self.poster def setMinutes( self, newMinutes ): if self.getMinutes() != None: raise MaKaCError( _("the Minutes for this subcontribution has already been set")) self.minutes=newMinutes self.minutes.setOwner( self ) self.notifyModification() def createMinutes( self ): if self.getMinutes() != None: raise MaKaCError( _("The minutes for this subcontribution have already been created"), _("Sub Contribution")) self.minutes = Minutes() self.minutes.setOwner( self ) self.notifyModification() return self.minutes def removeMinutes( self ): if self.getMinutes() is None: return self.minutes.delete() self.minutes.setOwner( None ) self.minutes = None self.notifyModification() def recoverMinutes(self, min): self.removeMinutes() # To ensure that the current minutes are put in # the trash can. self.minutes = min self.minutes.setOwner( self ) min.recover() self.notifyModification() return self.minutes def getMinutes( self ): #To be removed try: if self.minutes: pass except AttributeError, e: self.minutes = None return self.minutes def getMasterSchedule( self ): return self.getOwner().getSchedule() def resetAccessCache(self, UP=True, DOWN=True): if UP: self.getOwner().resetAccessCache(True, False) if DOWN: for mat in self.getMaterialList(): mat.resetAccessCache(False, True) def resetModifyCache(self, UP=True, DOWN=True): if UP and DOWN: self.resetAccessCache(UP, DOWN) if UP: self.getOwner().resetModifyCache(True, False) if DOWN: for mat in self.getMaterialList(): mat.resetModifyCache(False, True) def unindex( self ): indexes.IndexesHolder().getById("OAIContributionModificationDate").unindexContribution(self) indexes.IndexesHolder().getById("OAIPrivateContributionModificationDate").unindexContribution(self) def delete(self): self.unindex() #index a DeletedObject to keep track of the sub-contribution after the deletion DeletedObjectHolder().add(DeletedObject(self)) while len(self.getSpeakerList()) > 0: self.removeSpeaker(self.getSpeakerList()[0]) for mat in self.getMaterialList(): self.removeMaterial(mat) self.removePaper() self.removeSlides() self.removeVideo() self.removePoster() self.removeMinutes() TrashCanManager().add(self) self.unindex() def recover(self): TrashCanManager().remove(self) def getReportNumberHolder(self): try: if self._reportNumberHolder: pass except AttributeError, e: self._reportNumberHolder=ReportNumberHolder(self) return self._reportNumberHolder def setReportNumberHolder(self, rnh): self._reportNumberHolder=rnh class Material(Persistent, Fossilizable, CommonObjectBase): """This class represents a set of electronic documents (resources) which can be attached to a conference, a session or a contribution. A material can be of several types (achieved by specialising this class) and is like a container of files which have some relation among them. It contains the minimal set of attributes to store basic meta data and provides useful operations to access and manage it. Attributes: owner -- (Conference, Session or Contribution) Object to which the material is attached to id -- (string) Material unique identifier. Normally used to uniquely identify a material within a conference, session or contribution title -- (string) Material denomination description -- (string) Longer text describing in more detail material intentions type -- (string) String identifying the material classification resources -- (PMapping) Collection of resouces grouped within the material. Dictionary of references to Resource objects indexed by their unique relative id. """ fossilizes(IMaterialMinimalFossil, IMaterialFossil) def __init__( self, materialData=None ): self.id = "not assigned" self.__resources = {} self.__resourcesIdGen = Counter() self.title = "" self.description = "" self.type = "" self.owner = None self.__ac = AccessController() self._mainResource = None def isFullyPublic( self ): if hasattr(self, "_fullyPublic"): return self._fullyPublic else: self.setFullyPublic() return self._fullyPublic def setFullyPublic( self ): if self.isProtected(): self._fullyPublic = False self._p_changed = 1 return for res in self.getResourceList(): if res.isProtected(): self._fullyPublic = False self._p_changed = 1 return self._fullyPublic = True self._p_changed = 1 def updateFullyPublic( self ): self.setFullyPublic() self.getOwner().updateFullyPublic() def setValues( self, params ): """Sets all the values of the current material object from a diccionary containing the following key-value pairs: title-(str) description-(str) Please, note that this method sets ALL values which means that if the given dictionary doesn't contain any of the keys the value will set to a default value. """ self.setTitle( params.get( "title", _("NO TITLE ASSIGNED") ) ) self.setDescription( params.get( "description", "" ) ) self.notifyModification() def clone ( self, owner): mat = type(self)() mat.setTitle(self.getTitle()) mat.setDescription(self.getDescription()) mat.notifyModification() mat.setId(self.getId()) mat.setOwner(owner) mat.setType(self.getType()) mat.setProtection(self.isItselfProtected()) mat.setAccessKey(self.getAccessKey()) lrep = self._getRepository() flist = lrep.getFiles() rlist = self.getResourceList() for r in rlist : if isinstance(r,Link): newlink = Link() newlink.setOwner(mat) newlink.setName(r.getName()) newlink.setDescription(r.getDescription()) newlink.setURL(r.getURL()) mat.addResource(newlink) elif isinstance(r,LocalFile): newfile = LocalFile() newfile.setOwner(mat) newfile.setName(r.getName()) newfile.setDescription(r.getDescription()) newfile.setFilePath(r.getFilePath()) newfile.setFileName(r.getFileName()) mat.addResource(newfile) else : raise Exception( _("Unexpected object type in Resource List : ")+str(type(r))) mat.setMainResource(self.getMainResource()) return mat def notifyModification( self ): parent = self.getOwner() if parent: parent.notifyModification() self._p_changed = 1 def getLocator( self ): if self.owner == None: return Locator() lconf = self.owner.getLocator() lconf["materialId"] = self.getId() return lconf def setId( self, newId ): self.id = str(newId).strip() @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'],'id') def getId( self ): return self.id def getUniqueId( self ): """returns (string) the unique identifier of the item""" """used mainly in the web session access key table""" return "%sm%s" % (self.getOwner().getUniqueId(),self.id) def setOwner( self, newOwner ): self.owner = newOwner def getOwner( self ): return self.owner def getCategory( self ): if isinstance(self.getOwner(), Category): return self.getOwner() return None def getConference( self ): if type(self.getOwner()) is Conference: return self.getOwner() if type(self.getOwner()) is Category: return None return self.getOwner().getConference() def getSession( self ): if self.getContribution(): return self.getContribution().getSession() if isinstance(self.getOwner(), Session): return self.getOwner() if isinstance(self.getOwner(), SubContribution): return self.getOwner().getSession() return None def getContribution( self ): if self.getSubContribution(): return self.getSubContribution().getContribution() if isinstance(self.getOwner(), Contribution): return self.getOwner() return None def getSubContribution( self ): if isinstance(self.getOwner(), SubContribution): return self.getOwner() return None @Updates (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'],'title') def setTitle( self, newTitle ): self.title = newTitle.strip() self.notifyModification() @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'],'title') def getTitle( self ): return self.title @Updates (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'description') def setDescription( self, newDescription ): self.description = newDescription.strip() self.notifyModification() @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'description') def getDescription( self ): return self.description def setType( self, newType ): self.type = newType.strip() self.notifyModification() @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'type') def getType( self ): return self.type @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster'], 'subjectToReviewing') def isSubjectToReviewing(self): """ Returns if a material is subject to reviewing. This only has sense if the material belongs to a contribuion. Otherwise, the returned value is None. If the material belongs to a contribution, the strings 'Yes' or 'No' are returned. """ if isinstance(self.owner, Contribution): reviewableMaterials = self.owner.getConference().getConfReview().getReviewableMaterials() if self.title in reviewableMaterials: return 'Yes' else: return 'No' else: return None @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster'], 'reviewingState') def getReviewingState(self): """ Returns the reviewing state of a material. The state is represented by an integer: 0 : there's no reviewing state because the material does not belong to a contribution, or the conference has not reviewing module enabled, or the module is enabled but the mode is "no reviewing" 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference 2 : the material is subject to reviewing, but has not been submitted yet by the author 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected """ if isinstance(self.owner, Contribution): conference = self.owner.getConference() if not conference.hasEnabledSection('paperReviewing') or conference.getConfReview().getChoice() == 0: #conference has no reviewing process return 0 else: #conference has reviewing reviewableMaterials = conference.getConfReview().getReviewableMaterials() if self.title in reviewableMaterials: #material is reviewable lastReview = self.owner.getReviewManager().getLastReview() if lastReview.isAuthorSubmitted(): #author has submitted refereeJudgement = lastReview.getRefereeJudgement() if refereeJudgement.isSubmitted(): #referee has submitted judgement if refereeJudgement.getJudgement() == "Accept": return 4 elif refereeJudgement.getJudgement() == "Reject": return 5 else: #we should never arrive here because referee judgements that are 'To be corrected' #or a custom state should imply a new review being created, so the state is back to 2 raise MaKaCError("RefereeJudgement should be 'Accept' or 'Reject' in this method") else: #referee has not submitted judgement return 3 else: #author has not submitted return 2 else: #material is not reviewable return 1 else: #material does not belong to a contribution return 0 def _getRepository( self ): dbRoot = DBMgr.getInstance().getDBConnection().root() try: fr = dbRoot["local_repositories"]["main"] except KeyError, e: fr = fileRepository.MaterialLocalRepository() dbRoot["local_repositories"] = OOBTree() dbRoot["local_repositories"]["main"] = fr return fr def hasFile( self, name ): for f in self.getResourceList(): if f.getName() == name: return True return False def addResource( self, newRes, forcedFileId = None ): newRes.setOwner( self ) newRes.setId( str( self.__resourcesIdGen.newCount() ) ) newRes.archive( self._getRepository(), forcedFileId = forcedFileId ) self.__resources[newRes.getId()] = newRes self.notifyModification() Logger.get('storage').debug("Finished storing resource %s for material %s" % (newRes.getId(), self.getLocator())) @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'],'resources', isPicklableObject = True) def getResourceList( self ): list = self.__resources.values() list.sort(utils.sortFilesByName) return list def getNbResources(self ): return len(self.__resources) def getResourceById( self, id ): return self.__resources[id] def removeResource( self, res ): if res.getId() in self.__resources.keys(): del self.__resources[ res.getId() ] res.delete() self.notifyModification() if self.getMainResource() is not None and \ self._mainResource.getId() == res.getId(): self._mainResource = None def recoverResource(self, recRes): recRes.setOwner(self) self.__resources[recRes.getId()] = recRes recRes.recover() self.notifyModification() def getMainResource(self): try: if self._mainResource: pass except AttributeError: self._mainResource = None return self._mainResource def setMainResource(self, mr): self._mainResource = mr def delete( self ): for res in self.getResourceList(): self.removeResource( res ) TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def canIPAccess( self, ip ): try: return self._v_canipaccess[ip] except AttributeError: self._v_canipaccess = {} except KeyError: pass if not self.__ac.canIPAccess( ip ): self._v_canipaccess[ip] = False return False if self.getOwner() != None: self._v_canipaccess[ip] = self.getOwner().canIPAccess(ip) return self._v_canipaccess[ip] self._v_canipaccess[ip] = True return self._v_canipaccess[ip] def isProtected( self ): # tells if a material is protected or not return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0 @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'protection') def getAccessProtectionLevel( self ): return self.__ac.getAccessProtectionLevel() def isItselfProtected( self ): return self.__ac.isItselfProtected() @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'protectedOwner') def hasProtectedOwner( self ): if self.getOwner() != None: return self.getOwner().isProtected() return False @Updates (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'protection', lambda(x): int(x)) def setProtection( self, private ): self.__ac.setProtection( private ) self.updateFullyPublic() self._p_changed = 1 @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'hidden') def isHidden( self ): return self.__ac.isHidden() @Updates (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'hidden') def setHidden( self, hidden ): self.__ac.setHidden( hidden ) self._p_changed = 1 @Updates (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'accessKey') def setAccessKey( self, pwd="" ): self.__ac.setAccessKey(pwd) self._p_changed = 1 self.resetAccessCache() @Retrieves (['MaKaC.conference.Material', 'MaKaC.conference.Minutes', 'MaKaC.conference.Paper', 'MaKaC.conference.Slides', 'MaKaC.conference.Video', 'MaKaC.conference.Poster', 'MaKaC.conference.Reviewing'], 'accessKey') def getAccessKey( self ): return self.__ac.getAccessKey() def grantAccess( self, prin ): self.__ac.grantAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "access") self._p_changed = 1 self.resetAccessCache() def revokeAccess( self, prin ): self.__ac.revokeAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "access") self._p_changed = 1 self.resetAccessCache() def canView( self, aw ): """tells whether the specified user has access to the current object or any of its sub-objects """ if self.isHidden() and not self.canAccess( aw ): return False else: return True def isAllowedToAccess( self, user ): try: return self._v_isallowedtoaccess[user] except AttributeError: self._v_isallowedtoaccess = {} except KeyError: pass self._v_isallowedtoaccess[user] = (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or self.__ac.canUserAccess( user ) or self.canUserModify(user) return self._v_isallowedtoaccess[user] def canAccess( self, aw ): try: return self._v_canaccess[aw] except AttributeError: self._v_canaccess = {} except KeyError: pass # Allow harvesters (Invenio, offline cache) to access # protected pages if self.__ac.isHarvesterIP(aw.getIP()): self._v_canaccess[aw] = True return True ##################################################### canUserAccess = self.isAllowedToAccess( aw.getUser() ) canIPAccess = self.canIPAccess( aw.getIP() ) if not self.isProtected(): self._v_canaccess[aw] = canUserAccess or canIPAccess else: canKeyAccess = self.canKeyAccess(aw) self._v_canaccess[aw] = canUserAccess or canKeyAccess return self._v_canaccess[aw] def resetAccessCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canaccess"): del self._v_canaccess if hasattr(self,"_v_isallowedtoaccess"): del self._v_isallowedtoaccess if hasattr(self,"_v_cankeyaccess"): del self._v_cankeyaccess if hasattr(self,"_v_canipaccess"): del self._v_canipaccess if UP: self.getOwner().resetAccessCache(True, False) if DOWN: for res in self.getResourceList(): res.resetAccessCache(False, True) def resetModifyCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canmodify"): del self._v_canmodify if hasattr(self,"_v_canusermodify"): del self._v_canusermodify if hasattr(self,"_v_cankeymodify"): del self._v_cankeymodify if UP and DOWN: self.resetAccessCache(UP, DOWN) if UP: self.getOwner().resetModifyCache(True, False) if DOWN: for res in self.getResourceList(): res.resetModifyCache(False, True) def canKeyAccess( self, aw ): sess = aw.getSession() if not sess: return False keys = sess.getVar("accessKeys") if keys != None: key = keys.get(self.getUniqueId(),"") if self.getAccessKey() != "": return self.__ac.canKeyAccess(key) elif self.getConference() != None: return self.getConference().canKeyAccess(aw, key) return False def grantModification( self, prin ): self.__ac.grantModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "manager") self._p_changed = 1 self.resetModifyCache() def revokeModification( self, prin ): self.__ac.revokeModification( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "manager") self._p_changed = 1 self.resetModifyCache() def canModify( self, aw ): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw )) return self._v_canmodify[aw] def canUserModify( self, user ): """Tells whether a user is allowed to modify the current contribution: only if the user is granted to modify the contribution or the user can modify any of its upper objects (i.e. conference or session). """ try: return self._v_canusermodify[user] except AttributeError: self._v_canusermodify = {} except KeyError: pass self._v_canusermodify[user] = self.getOwner().canUserModify( user ) return self._v_canusermodify[user] def getModifKey( self ): return self.getConference().getModifKey() def getManagerList( self ): return self.__ac.getModifierList() def getAllowedToAccessList( self ): return self.__ac.getAccessList() def requireDomain( self, dom ): self.__ac.requireDomain( dom ) self._p_changed = 1 self.resetAccessCache() def freeDomain( self, dom ): self.__ac.freeDomain( dom ) self._p_changed = 1 self.resetAccessCache() def getDomainList( self ): return self.__ac.getRequiredDomainList() def getAccessController(self): return self.__ac class Reviewing(Material): def __init__( self, materialData = None ): Material.__init__( self, materialData ) self.id = "reviewing" def setId( self, newId ): return class Paper(Material): def __init__( self, materialData = None ): Material.__init__( self, materialData ) self.id = "paper" def setId( self, newId ): return class Slides(Material): def __init__( self, materialData = None ): Material.__init__( self, materialData ) self.id = "slides" def setId( self, newId ): return class Video(Material): def __init__( self, materialData = None ): Material.__init__( self, materialData ) self.id = "video" def setId( self, newId ): return class Poster(Material): def __init__( self, materialData = None ): Material.__init__( self, materialData ) self.id = "poster" def setId( self, newId ): return class Minutes(Material): def __init__( self, materialData = None ): Material.__init__( self, materialData ) self.id = "minutes" self.title = "Minutes" self.file = None def clone ( self, owner): mat = Minutes() mat.setTitle(self.getTitle()) mat.setDescription(self.getDescription()) mat.notifyModification() mat.setId(self.getId()) mat.setOwner(owner) mat.setType(self.getType()) mat.setProtection(self.isItselfProtected()) mat.setAccessKey(self.getAccessKey()) lrep = self._getRepository() flist = lrep.getFiles() rlist = self.getResourceList() for r in rlist : if r.getId()=="minutes": mat.setText(self.getText()) elif isinstance(r,Link): newlink = Link() newlink.setOwner(mat) newlink.setName(r.getName()) newlink.setDescription(r.getDescription()) newlink.setURL(r.getURL()) mat.addResource(newlink) elif isinstance(r,LocalFile): newfile = LocalFile() newfile.setOwner(mat) newfile.setName(r.getName()) newfile.setDescription(r.getDescription()) newfile.setFilePath(r.getFilePath()) newfile.setFileName(r.getFileName()) mat.addResource(newfile) else : raise Exception( _("Unexpected object type in Resource List : ")+str(type(r))) mat.setMainResource(self.getMainResource()) return mat def setId( self, newId ): return def setTitle( self, newTitle ): self.title = newTitle.strip() self.notifyModification() def _setFile( self, forcedFileId = None ): #XXX: unsafe; it must be changed by mkstemp when migrating to python 2.3 tmpFileName = tempfile.mktemp() fh = open(tmpFileName, "w") fh.write(" ") fh.close() self.file = LocalFile() self.file.setId("minutes") self.file.setName("minutes") self.file.setFilePath(tmpFileName) self.file.setFileName("minutes.txt") self.file.setOwner(self) self.file.archive(self._getRepository(), forcedFileId = forcedFileId) def setText( self, text, forcedFileId = None ): if self.file: self.file.delete() self._setFile(forcedFileId = forcedFileId) self.file.replaceContent( text ) self.getOwner().notifyModification() def getText( self ): if not self.file: return "" return self.file.readBin() def getResourceList( self ): res = Material.getResourceList( self ) if self.file: res.insert(0, self.file) return res def getResourceById( self, id ): if id.strip() == "minutes": return self.file return Material.getResourceById( self, id ) def removeResource(self, res): Material.removeResource(self, res) if self.file is not None and res.getId().strip() == "minutes": self.file = None res.delete() self.notifyModification() def recoverResource(self, recRes): if recRes.getId() == "minutes": recRes.setOwner(self) self.file = recRes recRes.recover() self.notifyModification() else: Material.recoverResource(self, recRes) class Resource(Persistent, Fossilizable, CommonObjectBase): """This is the base class for representing individual resources which can be included in material containers for lately being attached to conference objects (i.e. conferences, sessions or contributions). This class provides basic data and operations to handle this resources. Resources can be of serveral types (files, links, ...) which means different specialisations of this class. Attributes: id -- (string) Allows to assign the resource a unique identifier. It is normally used to uniquely identify the resource among other resources included in a certain material. name -- (string) Short description about the purpose or the contents of the resource. description - (string) detailed and varied information about the resource. __owner - (Material) reference to the material object in which the current resource is included. """ fossilizes(IResourceMinimalFossil, IResourceFossil) def __init__( self, resData = None ): self.id = "not assigned" self.name = "" self.description = "" self._owner = None self.__ac = AccessController() def clone( self, conf ): res = Resource() res.setName(self.getName()) res.setDescription(self.getDescription()) res.setOwner(conf) res.notifyModification() res.setId(self.getId()) res.setProtection(self.isItselfProtected()) #res.__ac = self.getAccessController() return res def notifyModification( self ): parent = self.getOwner() if parent: parent.notifyModification() self._p_changed = 1 def getLocator( self ): if self._owner == None: return Locator() lconf = self._owner.getLocator() lconf["resId"] = self.getId() return lconf def setId( self, newId ): self.id = newId.strip() def getId( self ): return self.id def getUniqueId( self ): """returns (string) the unique identifier of the item used mainly in the web session access key table for resources, it is the same as the father material since only the material can be protected with an access key""" return self.getOwner().getUniqueId() def setOwner( self, newOwner ): self._owner = newOwner def getOwner( self ): return self._owner def getCategory( self ): #raise "%s:%s:%s"%(self.getOwner(), Material, isinstance(self.getOwner, Material)) if isinstance(self.getOwner(), Category): return self.getOwner() if isinstance(self.getOwner(), Material): return self.getOwner().getCategory() return None def getConference( self ): # this check owes itself to the fact that some # protection checking functions call getConference() # directly on resources, without caring whether they # are owned by Conferences or Categories if isinstance(self._owner, Category): return None else: return self._owner.getConference() def getSession( self ): return self._owner.getSession() def getContribution( self ): return self._owner.getContribution() def getSubContribution( self ): return self._owner.getSubContribution() @Updates (['MaKaC.conference.Link', 'MaKaC.conference.LocalFile'], 'name') def setName( self, newName ): self.name = newName.strip() self.notifyModification() def getName( self ): return self.name @Updates (['MaKaC.conference.Link', 'MaKaC.conference.LocalFile'], 'description') def setDescription( self, newDesc ): self.description = newDesc.strip() self.notifyModification() def getDescription( self ): return self.description def archive( self, repository = None, forcedFileId = None ): """performs necessary operations to ensure the archiving of the resource. By default is doing nothing as the persistence of the system already ensures the archiving of the basic resource data""" return def delete( self ): if self._owner != None: self._owner.removeResource( self ) self._owner = None TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def canIPAccess( self, ip ): try: self._v_canipaccess[ip] except AttributeError: self._v_canipaccess = {} except KeyError: pass if not self.__ac.canIPAccess( ip ): self._v_canipaccess[ip] = False return self._v_canipaccess[ip] if self.getOwner() != None: self._v_canipaccess[ip] = self.getOwner().canIPAccess(ip) return self._v_canipaccess[ip] self._v_canipaccess[ip] = True return self._v_canipaccess[ip] def isProtected( self ): # tells if a resource is protected or not return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0 def getAccessProtectionLevel( self ): return self.__ac.getAccessProtectionLevel() def isItselfProtected( self ): return self.__ac.isItselfProtected() def hasProtectedOwner( self ): if self.getOwner() != None: return self.getOwner().isProtected() return False @Updates (['MaKaC.conference.Link', 'MaKaC.conference.LocalFile'],'protection', lambda(x): int(x)) def setProtection( self, private ): self.__ac.setProtection( private ) self.getOwner().updateFullyPublic() def grantAccess( self, prin ): self.__ac.grantAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.linkTo(self, "access") self.resetAccessCache() def revokeAccess( self, prin ): self.__ac.revokeAccess( prin ) if isinstance(prin, MaKaC.user.Avatar): prin.unlinkTo(self, "access") self.resetAccessCache() def canView( self, aw ): """tells whether the specified user has access to the current object or any of its sub-objects """ return self.canAccess( aw ) def isAllowedToAccess( self, user ): try: return self._v_isallowedtoaccess[user] except AttributeError: self._v_isallowedtoaccess = {} except KeyError: pass self._v_isallowedtoaccess[user] = self.__ac.canUserAccess( user ) or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) return self._v_isallowedtoaccess[user] def canAccess( self, aw ): try: return self._v_canaccess[aw] except AttributeError: self._v_canaccess = {} except KeyError: pass # Allow harvesters (Invenio, offline cache) to access # protected pages if self.__ac.isHarvesterIP(aw.getIP()): self._v_canaccess[aw] = True return True ##################################################### if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ): self._v_canaccess[aw] = False return False if not self.isProtected(): self._v_canaccess[aw] = True return True flag = self.isAllowedToAccess( aw.getUser() ) self._v_canaccess[aw] = flag or self.canKeyAccess(aw) or self.getOwner().canKeyAccess(aw) or \ (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == "") or \ (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == self.getConference().getAccessKey()) return self._v_canaccess[aw] def resetAccessCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canaccess"): del self._v_canaccess if hasattr(self,"_v_isallowedtoaccess"): del self._v_isallowedtoaccess if hasattr(self,"_v_canipaccess"): del self._v_canipaccess if UP: self.getOwner().resetAccessCache(True, False) def resetModifyCache(self, UP=True, DOWN=True): if hasattr(self,"_v_canmodify"): del self._v_canmodify if hasattr(self,"_v_canusermodify"): del self._v_canusermodify if UP and DOWN: self.resetAccessCache(UP, DOWN) if UP: self.getOwner().resetModifyCache(True, False) def grantModification( self, prin ): self.__ac.grantModification( prin ) self.resetModifyCache() def revokeModification( self, prin ): self.__ac.revokeModification( prin ) self.resetModifyCache() def canModify( self, aw ): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw )) return self._v_canmodify[aw] def canUserModify( self, user ): """Tells whether a user is allowed to modify the current contribution: only if the user is granted to modify the contribution or the user can modify any of its upper objects (i.e. conference or session). """ try: return self._v_canusermodify[user] except AttributeError: self._v_canusermodify = {} except KeyError: pass self._v_canusermodify[user] = self.getOwner().canUserModify( user ) return self._v_canusermodify[user] def getModifKey( self ): return self.getConference().getModifKey() def getManagerList( self ): return self.__ac.getModifierList() def getAllowedToAccessList( self ): return self.__ac.getAccessList() def getURL( self ): return "" def requireDomain( self, dom ): self.__ac.requireDomain( dom ) self.resetAccessCache() def freeDomain( self, dom ): self.__ac.freeDomain( dom ) self.resetAccessCache() def getDomainList( self ): return self.__ac.getRequiredDomainList() def getAccessController(self): return self.__ac def getAccessKey(self): if self.getOwner() is not None: return self.getOwner().getAccessKey() return "" def canKeyAccess( self, aw ): sess = aw.getSession() if not sess: return False accessKey = self.getAccessKey() keys = sess.getVar("accessKeys") if keys != None: if keys.has_key(self.getUniqueId()): if (accessKey != "" and keys[self.getUniqueId()] == accessKey) or (accessKey == "" and self.getConference().getAccessKey() != "" and keys[self.getUniqueId()] == self.getConference().getAccessKey()): return True return False def getReviewingState(self): """ Returns the reviewing state of a resource, which is the reviewing state of the material to which it belongs. The state is represented by an integer: 0 : there's no reviewing state because the resource doesn't belong to a material, the material does not belong to a contribution, or the conference does not have reviewing. 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference 2 : the material is subject to reviewing, but has not been submitted yet by the author 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected """ if isinstance(self.getOwner(), Material): return self.getOwner().getReviewingState() else: #ressource does not belong to a material return 0 class Link(Resource): """Specialises Resource class in order to represent web links. Objects of this class will contain necessary information to include in a conference object links to internet resources through a URL. Params: url -- (string) Contains the URL to the internet target resource. """ fossilizes(ILinkMinimalFossil, ILinkFossil) def __init__( self, resData = None ): Resource.__init__( self, resData ) self.url = "" @Updates ('MaKaC.conference.Link', 'url') def setURL( self, newURL ): self.url = newURL.strip() self.notifyModification() def getURL( self ): return self.url class LocalFile(Resource): """Specialises Resource class in order to represent files which can be stored in the system. The user can choose to use the system as an archive of electronic files so he may want to attach a file which is in his computer to a conference so it remains there and must be kept in the system. This object contains the file basic metadata and provides the necessary operations to ensure the corresponding file is archived (it uses one of the file repositories of the system to do so) and keeps the reference for being able to access it afterwards. Params: fileName -- (string) Name of the file. Normally the original name of the user submitted file is kept. filePath -- (string) If it is set, it contains a local path to the file submitted by the user and uploaded in the system. This attribute is only temporary used so it keeps a pointer to a temporary uploaded file. __repository -- (FileRep) Once a file is archived, it is kept in a FileRepository for long term. This attribute contains a pointer to the file repository where the file is kept. __archivedId -- (string) It contains a unique identifier for the file inside the repository where it is archived. """ fossilizes(ILocalFileMinimalFossil, ILocalFileFossil, ILocalFileExtendedFossil) def __init__( self, resData = None ): Resource.__init__( self, resData ) self.fileName= "" self.fileType = "" self.filePath = "" self.__repository = None self.__archivedId = "" def setFileName( self, newFileName, checkArchive=True ): """While the file is not archived sets the file name of the current object to the one specified (if a full path is specified the base name is extracted) replacing on it blanks by underscores. """ if checkArchive and self.isArchived(): raise MaKaCError( _("The file name of an archived file cannot be changed"), _("File Archiving")) #Using os.path.basename is not enough as it only extract filenames # correclty depending on the server platform. So we need to convert # to the server platform and apply the basename extraction. As I # couldn't find a python function for this this is done manually # although it can contain errors #On windows basename function seems to work properly with unix file # paths if newFileName.count("/"): #unix filepath newFileName = newFileName.split("/")[-1] else: #windows file path: there "/" is not allowed on windows paths newFileName = newFileName.split("\\")[-1] self.fileName = newFileName.strip().replace(" ", "_") def getFileName( self ): return self.fileName def getFileType( self ): fileExtension = os.path.splitext( self.getFileName() )[1] if fileExtension != "": fileExtension = fileExtension[1:] cfg = Config.getInstance() if cfg.getFileType( fileExtension ) != "": return cfg.getFileType( fileExtension ) else: return fileExtension def setFilePath( self, filePath ): if self.isArchived(): raise MaKaCError( _("The path of an archived file cannot be changed"), _("File Archiving")) if not os.access( filePath.strip(), os.F_OK ): raise Exception( _("File does not exist : %s")%filePath.strip()) self.filePath = filePath.strip() def getCreationDate( self): return self.__repository.getCreationDate(self.__archivedId) def getFilePath( self ): if not self.isArchived(): return self.filePath return self.__repository.getFilePath(self.__archivedId) def getSize( self ): if not self.isArchived(): return int(os.stat(self.getFilePath())[stat.ST_SIZE]) return self.__repository.getFileSize( self.__archivedId ) def setArchivedId( self, rep, id ): self.__repository = rep self.__archivedId = id def getRepositoryId( self ): return self.__archivedId def setRepositoryId(self, id): self.__archivedId = id def isArchived( self ): return self.__repository != None and self.__archivedId != "" def readBin( self ): if not self.isArchived(): raise MaKaCError( _("File not available until it has been archived") , _("File Archiving")) return self.__repository.readFile( self.__archivedId ) def replaceContent( self, newContent ): if not self.isArchived(): raise MaKaCError( _("File not available until it has been archived") , _("File Archiving")) self.__repository.replaceContent( self.__archivedId, newContent ) def archive( self, repository=None, forcedFileId = None ): if self.isArchived(): raise Exception( _("File is already archived")) if not repository: raise Exception( _("Destination repository not set")) if self.filePath == "": return _("Nothing to archive") repository.storeFile( self, forcedFileId = forcedFileId) self.filePath = "" self.notifyModification() def unArchive(self): # Not used. self.__repository = None self.__archivedId = "" def recover(self): if not self.isArchived(): raise Exception( _("File is not archived, so it cannot be recovered.")) if not self.__repository: raise Exception( _("Destination repository not set.")) self.__repository.recoverFile(self) Resource.recover(self) self.notifyModification() def delete( self ): if not self.isArchived(): os.remove( self.getFilePath() ) try: self.__repository.retireFile( self ) except AttributeError, e: pass Resource.delete( self ) def getRepository(self): return self.__repository #getURL is removed at the moment from the LocalFile and the file access # is completely delegated to the web interface; the web interface will # have to access the files locally (using the getFilePath) or the readBin # function. #However, for the future it could be required to have several file # repositories so the file access will have to be reviewed. #def getURL( self ): # #XXX: Very bad!! We should find a better solution # c = Config.getInstance() # return c.getArchivedFileURL( self ) class TCIndex( Persistent ): """Index for conference track coordinators. This class allows to index conference track coordinators so the owner can answer optimally to the query if a user is coordinating any conference track. It is implemented by simply using a BTree where the Avatar id is used as key (because it is unique and non variable) and a list of coordinated tracks is kept as keys. It is the responsability of the index owner (conference) to keep it up-to-date i.e. notify track coordinator additions and removals. """ def __init__( self ): self._idx = OOBTree() def getTracks( self, av ): """Gives a list with the tracks a user is coordinating. """ if av == None: return [] return self._idx.get( av.getId(), [] ) def indexCoordinator( self, av, track ): """Registers in the index a coordinator of a track. """ if av == None or track == None: return if not self._idx.has_key( av.getId() ): l = [] self._idx[ av.getId() ] = l else: l = self._idx[ av.getId() ] if track not in l: l.append( track ) self.notifyModification() def unindexCoordinator( self, av, track ): if av == None or track == None: return l = self._idx.get( av.getId(), [] ) if track in l: l.remove( track ) self.notifyModification() def notifyModification(self): self._idx._p_changed = 1 self._p_changed = 1 class Track(Persistent): def __init__( self ): self.conference = None self.id = "not assigned" self.title = "" self.description = "" self.subTracks = {} self.__SubTrackGenerator = Counter() self._abstracts = OOBTree() self._coordinators = [] self._contributions = OOBTree() self._code="" def clone(self, conference): tr = Track() tr.setConference(conference) tr.setTitle(self.getTitle()) tr.setCode(self.getCode()) tr.setDescription(self.getDescription()) for co in self.getCoordinatorList() : tr.addCoordinator(co) for subtr in self.getSubTrackList() : tr.addSubTrack(subtr.clone()) return tr def delete( self ): """Deletes a track from the system. All the associated abstracts will also be notified so the track is no longer associated to them. """ #XXX: Should we allow to delete a track when there are some abstracts # or contributions submitted for it?!?!?!?! # we must notify each abstract in the track about the deletion of the # track while len(self._abstracts)>0: k = self._abstracts.keys()[0] abstract = self._abstracts[k] del self._abstracts[k] abstract.removeTrack( self ) # we must notify each contribution in the track about the deletion of the # track while len(self._contributions)>0: k = self._contributions.keys()[0] contrib = self._contributions[k] del self._contributions[k] contrib.removeTrack( self ) # we must delete and unindex all the possible track coordinators while len(self._coordinators)>0: self.removeCoordinator(self._coordinators[0]) # we must notify the conference about the track deletion if self.conference: conf = self.conference self.conference = None conf.removeTrack( self ) TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def canModify( self, aw ): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.conference.canModify( aw ) return self._v_canmodify[aw] def canUserModify( self, av ): try: return self._v_canusermodify[av] except AttributeError: self._v_canusermodify = {} except KeyError: pass self._v_canusermodify[av] = self.conference.canUserModify( av ) return self._v_canusermodify[av] def canView( self, aw ): return self.conference.canView( aw ) def notifyModification( self ): parent = self.getConference() if parent: parent.notifyModification() self._p_changed = 1 def getLocator( self ): """Gives back a globaly unique identification encapsulated in a Locator object for the track instance """ if self.conference == None: return Locator() lconf = self.conference.getLocator() lconf["trackId"] = self.getId() return lconf def setConference(self, conference): self.conference = conference def getConference( self ): return self.conference def getOwner( self ): return self.getConference() def setId( self, newId ): self.id = str(newId) def getId( self ): return self.id def setTitle( self, newTitle ): self.title = newTitle self.notifyModification() def getTitle( self ): return self.title def setDescription(self, newDescription ): self.description = newDescription self.notifyModification() def getDescription(self): return self.description def getCode(self): try: if self._code: pass except AttributeError: self._code=self.id return self._code def setCode(self,newCode): self._code=str(newCode).strip() def __generateNewSubTrackId( self ): return str(self.__SubTrackGenerator.newCount()) def addSubTrack( self, newSubTrack ): """Registers the contribution passed as parameter within the session assigning it a unique id. """ if newSubTrack in self.subTracks.values(): return subTrackId = newSubTrack.getId() if subTrackId == "not assigned": subTrackId = self.__generateNewSubTrackId() self.subTracks[subTrackId] = newSubTrack newSubTrack.setTrack( self ) newSubTrack.setId( subTrackId ) self.notifyModification() def removeSubTrack( self, subTrack ): """Removes the indicated contribution from the session """ if subTrack in self.subTracks.values(): del self.subTracks[ subTrack.getId() ] subTrack.setTrack( None ) subTrack.delete() self.notifyModification() def recoverSubTrack(self, subTrack): self.addSubTrack(subTrack) subTrack.recover() def newSubTrack( self ): st = SubTrack() self.addSubTrack( st ) return st def getSubTrackById( self, id ): if self.subTracks.has_key( id ): return self.subTracks[ id ] return None def getSubTrackList( self ): return self.subTracks.values() def getAbstractList( self ): """ """ try: if self._abstracts: pass except AttributeError: self._abstracts = OOBTree() return self._abstracts.values() def getAbstractById( self, id ): try: if self._abstracts: pass except AttributeError: self._abstracts = OOBTree() return self._abstracts[ str(id).strip() ] def hasAbstract( self, abstract ): """ """ try: if self._abstracts: pass except AttributeError: self._abstracts = OOBTree() return self._abstracts.has_key( abstract.getId() ) def addAbstract( self, abstract ): """Adds an abstract to the track abstract list. Notice that this method doesn't notify the abstract about the track addition. """ if not self.hasAbstract( abstract ): self._abstracts[ abstract.getId() ] = abstract #abstract.addTrack( self ) def removeAbstract( self, abstract ): """Removes an abstract from the track abstract list. Notice that this method doesn't notify the abstract about the track removal. """ if self.hasAbstract( abstract ): del self._abstracts[ abstract.getId() ] #abstract.removeTrack( self ) def addCoordinator( self, av ): """Grants coordination privileges to user. Arguments: av -- (MaKaC.user.Avatar) the user to which coordination privileges must be granted. """ try: if self._coordinators: pass except AttributeError, e: self._coordinators = [] self.notifyModification() if not (av in self._coordinators): self._coordinators.append( av ) self.getConference().addTrackCoordinator( self, av ) av.linkTo(self, "coordinator") self.notifyModification() def removeCoordinator( self, av ): """Revokes coordination privileges to user. Arguments: av -- (MaKaC.user.Avatar) user for which coordination privileges must be revoked """ try: if self._coordinators: pass except AttributeError, e: self._coordinators = [] self.notifyModification() if av in self._coordinators: self._coordinators.remove( av ) self.getConference().removeTrackCoordinator( self, av ) av.linkTo(self, "coordinator") self.notifyModification() def isCoordinator( self, av ): """Tells whether the specified user is a coordinator of the track. Arguments: av -- (MaKaC.user.Avatar) user to be checke Return value: (boolean) """ try: if self._coordinators: pass except AttributeError, e: self._coordinators = [] return av in self._coordinators def getCoordinatorList( self ): """Return all users which have privileges to coordinate the track. Return value: (list) """ try: if self._coordinators: pass except AttributeError, e: self._coordinators = [] return self._coordinators def canCoordinate( self, aw ): """Tells if a user has coordination privileges. Only track coordinators have coordination privileges over a track. Params: aw -- (MaKaC.accessControl.AccessWrapper) User access information for which the coordination privileges must be checked. Return value: (boolean) """ return self.isCoordinator( aw.getUser() ) or self.canModify( aw ) def addContribution( self, newContrib ): """ """ try: if self._contributions: pass except AttributeError: self._contributions = OOBTree() if self._contributions.has_key( newContrib.getId() ): return self._contributions[ newContrib.getId() ] = newContrib newContrib.setTrack( self ) def getModifKey( self ): return self.getConference().getModifKey() def removeContribution( self, contrib ): """ """ try: if self._contributions: pass except AttributeError: self._contributions = OOBTree() if not self._contributions.has_key( contrib.getId() ): return del self._contributions[ contrib.getId() ] contrib.setTrack( None ) def hasContribution( self, contrib ): try: if self._contributions: pass except AttributeError: self._contributions = OOBTree() return self._contributions.has_key( contrib.getId() ) def getContributionList(self): try: if self._contributions: pass except AttributeError: self._contributions = OOBTree() return self._contributions.values() def canUserCoordinate( self, av ): return self.isCoordinator( av ) or self.canUserModify( av ) def getModifKey( self ): return self.getConference().getModifKey() class SubTrack(Persistent): def __init__( self ): self.track = None self.id = "not assigned" self.title = "" self.description = "" def clone(self): sub = SubTrack() sub.setDescription(self.getDescription()) sub.setTitle(self.getTitle()) return sub def delete(self): TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def canModify( self, aw ): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self.track.canModify( aw ) return self._v_canmodify[aw] def canView( self, aw ): return self.track.canView( aw ) def notifyModification( self ): parent = self.getTrack() if parent: parent.notifyModification() self._p_changed = 1 def getLocator( self ): """Gives back a globaly unique identification encapsulated in a Locator object for the session instance """ if self.track == None: return Locator() lconf = self.track.getLocator() lconf["subTrackId"] = self.getId() return lconf def setTrack(self, track): self.track = track if track == None: return def getTrack( self ): return self.track def getOwner( self ): return self.getTrack() def setId( self, newId ): self.id = str(newId) def getId( self ): return self.id def setTitle( self, newTitle ): self.title = newTitle self.notifyModification() def getTitle( self ): return self.title def setDescription(self, newDescription ): self.description = newDescription self.notifyModification() def getDescription(self): return self.description class ContributionType(Persistent): def __init__(self, name, description, conference): self._id = "" self._name = name self._description = description self._conference = conference def getId(self): return self._id def setId(self, id): self._id = id def getName(self): return self._name def setName(self, name): self._name = name def getDescription(self): return self._description def setDescription(self, desc): self._description = desc def getConference(self): return self._conference def setConference(self, conf): self._conference = conf def getLocator( self ): if self._conference == None: return Locator() lconf = self._conference.getLocator() lconf["contribTypeId"] = self.getId() return lconf def canModify(self, aw): try: return self._v_canmodify[aw] except AttributeError: self._v_canmodify = {} except KeyError: pass self._v_canmodify[aw] = self._conference.canModify(aw) return self._v_canmodify[aw] def delete(self): self.setConference(None) TrashCanManager().add(self) def recover(self): TrashCanManager().remove(self) def clone(self, conference ): type = ContributionType(self.getName(), self.getDescription(),conference) return type class BOAConfig(Persistent): """Contains the configuration of the Book of Abstracts of a conference """ def __init__(self,conf): self._conf=conf self._text="" def getText(self): return self._text def setText(self,newText): self._text=newText.strip() class DeletedObjectHolder(ObjectHolder): idxName = "DeletedObject" counterName = "DELETEDOBJECT" def __init__(self): ObjectHolder.__init__(self) self.archivedConferenceObjs = [] self.archivedContribObjs = [] def initIndexes(self): indexes.IndexesHolder().getIndex("OAIDeletedConferenceModificationDate").initIndex() indexes.IndexesHolder().getIndex("OAIDeletedConferenceCategory").initIndex() indexes.IndexesHolder().getIndex("OAIDeletedContributionModificationDate").initIndex() indexes.IndexesHolder().getIndex("OAIDeletedContributionCategory").initIndex() indexes.IndexesHolder().getIndex("OAIDeletedPrivateConferenceModificationDate").initIndex() indexes.IndexesHolder().getIndex("OAIDeletedPrivateConferenceCategory").initIndex() indexes.IndexesHolder().getIndex("OAIDeletedPrivateContributionModificationDate").initIndex() indexes.IndexesHolder().getIndex("OAIDeletedPrivateContributionCategory").initIndex() def add( self, newItem ): ObjectHolder.add( self, newItem ) if newItem.wasArchived: if newItem._objClass == Conference: self.archivedConferenceObjs.append(newItem) else: self.archivedContribObjs.append(newItem) @classmethod def index(cls, newItem): if newItem._objClass == Conference: cls.getConferenceDateIndex(private=newItem.protected).indexConference(newItem) cls.getConferenceCategoryIndex(private=newItem.protected).indexConference(newItem) elif newItem._objClass == Contribution or newItem._objClass == SubContribution or newItem._objClass == AcceptedContribution: cls.getContributionDateIndex(private=newItem.protected).indexContribution(newItem) cls.getContributionCategoryIndex(private=newItem.protected).indexContribution(newItem) else: raise Exception("Unknown type for indexing: %s" % newItem._objClass) def get_earliest_datestamp(self): date = [] idxConf = DeletedObjectHolder.getConferenceDateIndex(private=True) d = idxConf.getLowerIndex() if d: date.append(d) idxCont = DeletedObjectHolder.getContributionDateIndex(private=True) d = idxCont.getLowerIndex() if d: date.append(d) idxConf = DeletedObjectHolder.getConferenceDateIndex(private=False) d = idxConf.getLowerIndex() if d: date.append(d) idxCont = DeletedObjectHolder.getContributionDateIndex(private=False) d = idxCont.getLowerIndex() if d: date.append(d) if not date: return None return min(date) def getAll(self): l = [] l.extend(self.archivedConferenceObjs) l.extend(self.archivedContribObjs) return l @classmethod def getConferenceDateIndex(cls, private=False): idxHolder = indexes.IndexesHolder() if private: return idxHolder.getIndex("OAIDeletedPrivateConferenceModificationDate") else: return idxHolder.getIndex("OAIDeletedConferenceModificationDate") @classmethod def getContributionDateIndex(cls, private=False): idxHolder = indexes.IndexesHolder() if private: return idxHolder.getIndex("OAIDeletedPrivateContributionModificationDate") else: return idxHolder.getIndex("OAIDeletedContributionModificationDate") @classmethod def getConferenceCategoryIndex(cls, private=False): idxHolder = indexes.IndexesHolder() if private: return idxHolder.getIndex("OAIDeletedPrivateConferenceCategory") else: return idxHolder.getIndex("OAIDeletedConferenceCategory") @classmethod def getContributionCategoryIndex(cls, private=False): idxHolder = indexes.IndexesHolder() if private: return idxHolder.getIndex("OAIDeletedPrivateContributionCategory") else: return idxHolder.getIndex("OAIDeletedContributionCategory") def getObjs(self, from_date=None, until_date=None, catId=None, type=[], private=False): confs = [] conts = [] if "conf" in type: idxConf = DeletedObjectHolder.getConferenceDateIndex(private=private) confs.extend(idxConf.getConferences(from_date, until_date)) if "cont" in type: idxCont = DeletedObjectHolder.getContributionDateIndex(private=private) conts.extend(idxCont.getContributions(from_date, until_date)) if catId: if "conf" in type: if confs: toRemove = [] for conf in confs: if not conf.wasInCategory(catId): toRemove.append(conf) for conf in toRemove: confs.remove(conf) else: confIdxCat = DeletedObjectHolder.getConferenceCategoryIndex(private=private) confs = confIdxCat.getConferences(catId) if "cont" in type: if conts: toRemove = [] for cont in conts: if not cont.wasInCategory(catId): toRemove.append(cont) for cont in toRemove: conts.remove(cont) else: contIdxCat = DeletedObjectHolder.getContributionCategoryIndex(private=private) conts = contIdxCat.getContributions(catId) res = [] res.extend(confs) res.extend(conts) return res def getObjsIds(self, from_date=None, until_date=None, catId=None, type=[], private=False): objs = self.getObjs(from_date, until_date, catId, type, private) ids = [] for obj in objs: ids.append(getHierarchicalId(obj)) return ids class DeletedObject(Persistent): #Object created after a deletion of a conference, contribution or subcontribution to keep track def __init__(self, obj): self._OAImodificationDS = nowutc() self._objClass = obj.__class__ self.categPath = obj.getConference().getOwnerList()[0].getCategoryPath() self.protected = obj.hasAnyProtection() self.confId = obj.getConference().getId() self.contribId = None self.subContribId = None if self._objClass == Contribution or self._objClass == AcceptedContribution: self.contribId = obj.getId() elif self._objClass == SubContribution: self.contribId = obj.getContribution().getId() self.subContribId = obj.getId() DeletedObjectHolder.index(self) def hasAnyProtection(self): return self.protected def getId(self): if self.subContribId: return "%s:%s:%s"%(self.confId, self.contribId, self.subContribId) elif self.contribId: return "%s:%s"%(self.confId, self.contribId) else: return self.confId def getOAIModificationDate(self): return self._OAImodificationDS def wasInCategory(self, categId): if categId in self.categPath: return True return False def getCategoryPath(self): return self.categPath getCategoriesPath = getCategoryPath def wasArchived(self): return self.archived