[FIX] getFullNameNoTitle method fix
[cds-indico.git] / indico / MaKaC / conference.py
blob79c97fa7fdee2dfd1b8eccbb738b293443aa4ace
1 # -*- coding: utf-8 -*-
2 ##
3 ##
4 ## This file is part of CDS Indico.
5 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
6 ##
7 ## CDS Indico is free software; you can redistribute it and/or
8 ## modify it under the terms of the GNU General Public License as
9 ## published by the FreeSoftware Foundation; either version 2 of the
10 ## License, or (at your option) any later version.
12 ## CDS Indico is distributed in the hope that it will be useful, but
13 ## WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ## General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21 # fossil classes
22 from MaKaC.plugins import PluginsHolder, Observable
23 from MaKaC.common.utils import formatDateTime
24 from MaKaC.fossils.subcontribution import ISubContribParticipationFossil,\
25 ISubContributionFossil, ISubContributionWithSpeakersFossil
26 from MaKaC.fossils.contribution import IContributionParticipationFossil,\
27 IContributionFossil, IContributionWithSpeakersFossil, IContributionParticipationMinimalFossil, \
28 IContributionWithSubContribsFossil,\
29 IContributionParticipationTTDisplayFossil, \
30 IContributionParticipationTTMgmtFossil
31 from MaKaC.fossils.conference import IConferenceMinimalFossil, \
32 IConferenceEventInfoFossil, IConferenceFossil,\
33 ISessionFossil, ISessionSlotFossil, IMaterialMinimalFossil,\
34 IMaterialFossil, IConferenceParticipationFossil,\
35 IResourceMinimalFossil, ILinkMinimalFossil, ILocalFileMinimalFossil,\
36 IResourceFossil, ILinkFossil, ILocalFileFossil,\
37 ILocalFileExtendedFossil, IConferenceParticipationMinimalFossil,\
38 ICategoryFossil, ILocalFileAbstractMaterialFossil
39 from MaKaC.common.fossilize import fossilizes, Fossilizable
40 from MaKaC.common.url import ShortURLMapper
41 from MaKaC.contributionReviewing import Review
42 from indico.util.i18n import L_
45 import re, os
46 import tempfile
47 import copy
48 import stat
49 from datetime import datetime, timedelta, time
51 from MaKaC.contributionReviewing import ReviewManager
52 from MaKaC.paperReviewing import ConferencePaperReview as ConferencePaperReview
53 from MaKaC.abstractReviewing import ConferenceAbstractReview as ConferenceAbstractReview
55 from pytz import timezone
56 from pytz import all_timezones
58 from persistent import Persistent
59 from BTrees.OOBTree import OOBTree, OOTreeSet, OOSet
60 from BTrees.OIBTree import OIBTree,OISet,union
61 import MaKaC
62 import MaKaC.common.indexes as indexes
63 from MaKaC.common.timezoneUtils import nowutc, maxDatetime
64 import MaKaC.fileRepository as fileRepository
65 from MaKaC.schedule import ConferenceSchedule, SessionSchedule,SlotSchedule,\
66 PosterSlotSchedule, SlotSchTypeFactory, ContribSchEntry, \
67 LinkedTimeSchEntry, BreakTimeSchEntry
68 import MaKaC.review as review
69 from MaKaC.common import Config, DBMgr, utils
70 from MaKaC.common.Counter import Counter
71 from MaKaC.common.ObjectHolders import ObjectHolder
72 from MaKaC.common.Locators import Locator
73 from MaKaC.accessControl import AccessController, AdminList
74 from MaKaC.errors import MaKaCError, TimingError, ParentTimingError, EntryTimingError, NoReportError
75 from MaKaC import registration,epayment
76 from MaKaC.evaluation import Evaluation
77 from MaKaC.trashCan import TrashCanManager
78 from MaKaC.user import AvatarHolder
79 from MaKaC.common import pendingQueues
80 from MaKaC.common.info import HelperMaKaCInfo
81 from MaKaC.participant import Participation
82 from MaKaC.common.log import LogHandler
83 import MaKaC.task as task
84 import MaKaC.common.info as info
85 from MaKaC.badge import BadgeTemplateManager
86 from MaKaC.poster import PosterTemplateManager
87 from MaKaC.common.cache import CategoryCache, EventCache
88 from MaKaC.common import mail
89 from MaKaC.common.utils import getHierarchicalId
90 from MaKaC.i18n import _
91 from MaKaC.common.PickleJar import Updates
92 from MaKaC.common.PickleJar import if_else
94 from MaKaC.webinterface import urlHandlers
96 from MaKaC.common.logger import Logger
97 from MaKaC.common.contextManager import ContextManager
98 import zope.interface
100 from indico.modules.scheduler import Client, tasks
101 from indico.util.date_time import utc_timestamp
102 from indico.core.index import IIndexableByStartDateTime, IUniqueIdProvider, Catalog
105 class CoreObject(Persistent):
107 CoreObjects are Persistent objects that are employed by Indico's core
110 zope.interface.implements(IUniqueIdProvider,
111 IIndexableByStartDateTime)
113 def setModificationDate(self, date = None):
115 Method called to notify the current object has been modified.
117 if not date:
118 date = nowutc()
119 self._modificationDS = date
121 def __conform__(self, proto):
123 if proto == IIndexableByStartDateTime:
124 return utc_timestamp(self.getStartDate())
125 else:
126 return None
129 class Locatable:
131 Inherited by objects that imply a physical location:
132 * Conferences
133 * Sessions
134 * SessionSlots
135 * Contributions
136 * SubContributions
139 def getLocationParent(self):
141 Returns the object the location info should be inherited from
142 (Overridden)
144 raise Exception("Unimplemented method")
146 def getLocation(self):
147 if self.getOwnLocation():
148 return self.getOwnLocation()
149 return self.getInheritedLocation()
151 def getOwnLocation(self):
152 if len(self.places) > 0:
153 return self.places[0]
154 return None
156 def getInheritedLocation(self):
157 return self.getLocationParent().getLocation()
159 def getOwnRoom(self):
160 if len(self.rooms) > 0:
161 return self.rooms[0]
162 return None
164 def getRoom(self):
165 if self.getOwnRoom():
166 return self.getOwnRoom()
167 return self.getInheritedRoom()
169 def getInheritedRoom(self):
170 return self.getLocationParent().getRoom()
172 def setLocation(self, newLocation):
173 oldLocation = self.getOwnLocation()
174 if newLocation == None:
175 if len(self.places) > 0:
176 del self.places[0]
177 elif len(self.places) > 0:
178 self.places[0] = newLocation
179 else:
180 self.places.append( newLocation )
181 self.notifyModification()
183 def setRoom(self, newRoom):
184 oldRoom = self.getOwnRoom()
185 if newRoom == None:
186 if len(self.rooms) > 0:
187 del self.rooms[0]
188 elif len(self.rooms) > 0:
189 self.rooms[0] = newRoom
190 else:
191 self.rooms.append( newRoom )
192 self.notifyModification()
195 class CommonObjectBase(CoreObject, Observable, Fossilizable):
197 This class is for holding commonly used methods that are used by several classes.
198 It is inherited by the following classes:
199 * Category
200 * Conference
201 * Session
202 * Contribution
203 * SubContribution
204 * Material
205 * Resource
208 def getRecursiveManagerList(self):
209 av_set = set()
211 # Get the AccessProtectionLevel for this
212 apl = self.getAccessProtectionLevel()
214 if apl == -1:
215 pass
216 elif apl == 1:
217 for av in self.getManagerList():
218 av_set.add(av)
219 for av in self.getOwner().getRecursiveManagerList():
220 av_set.add(av)
221 else:
222 for av in self.getManagerList():
223 av_set.add(av)
225 if self.getOwner():
226 for av in self.getOwner().getRecursiveManagerList():
227 av_set.add(av)
229 return list(av_set)
231 def getRecursiveAllowedToAccessList(self, onlyManagers=False):
232 """Returns a set of Avatar resp. CERNGroup objects for those people resp.
233 e-groups allowed to access this object as well as all parent objects.
236 # Initialize set of avatars/groups: this will hold those
237 # people/groups explicitly
238 # allowed to access this object
239 av_set = set()
241 # Get the AccessProtectionLevel for this
242 apl = self.getAccessProtectionLevel()
244 # If this object is "absolutely public", then return an empty set
245 if apl == -1:
246 pass
248 # If this object is protected "all by itself", then get the list of
249 # people/groups allowed to access it, plus managers of owner(s)
250 elif apl == 1:
251 al = self.getAllowedToAccessList() + self.getManagerList() + \
252 self.getOwner().getRecursiveManagerList()
253 if al is not None:
254 for av in al:
255 av_set.add(av)
257 # If access settings are inherited (and PRIVATE) from its owners, look at those.
258 elif apl == 0 and self.isProtected():
259 # If event is protected, then get list of people/groups allowed
260 # to access, and add that to the set of avatars.
261 al = self.getAllowedToAccessList() + self.getManagerList()
262 if al is not None:
263 for av in al:
264 av_set.add(av)
266 # Add list of avatars/groups allowed to access parents objects.
267 owner = self.getOwner()
268 if owner is not None:
269 owner_al = owner.getRecursiveAllowedToAccessList(onlyManagers=True)
270 if owner_al is not None:
271 for av in owner_al:
272 av_set.add(av)
274 # return set containing whatever avatars/groups we may have collected
275 return av_set
278 class CategoryManager( ObjectHolder ):
279 idxName = "categories"
280 counterName = "CATEGORY"
282 def add(self, category):
283 ObjectHolder.add(self, category)
284 # Add category to the name index
285 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
286 nameIdx.index(category.getId(), category.getTitle().decode('utf-8'))
288 def remove(self, category):
289 ObjectHolder.remove(self, category)
290 # remove category from the name index
291 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
292 nameIdx.unindex(category.getId())
293 Catalog.getIdx('categ_conf_sd').remove_category(category.getId())
295 def _newId( self ):
297 returns a new id for the category
298 the id must not already exist in the collection
300 id = ObjectHolder._newId( self )
301 while self.hasKey(id):
302 id = ObjectHolder._newId( self )
303 return id
305 def getRoot( self ):
306 root = DBMgr.getInstance().getDBConnection().root()
307 if not root.has_key("rootCategory"):
308 r = Category()
309 r.setName( _("Home"))
310 self.add( r )
311 root["rootCategory"] = r
312 return root["rootCategory"]
314 def getDefaultConference( self ):
315 dconf = HelperMaKaCInfo.getMaKaCInfoInstance().getDefaultConference()
316 if dconf == None:
317 return HelperMaKaCInfo.getMaKaCInfoInstance().setDefaultConference(DefaultConference())
318 else:
319 return dconf
323 class Category(CommonObjectBase):
325 fossilizes(ICategoryFossil)
327 def __init__( self ):
329 self.id = ""
330 self.name = ""
331 self.description = ""
332 self.subcategories = {}
333 self.materials = {}
334 self.conferences = OOTreeSet()
335 self._numConferences = 0
336 self.owner = None
337 self._defaultStyle = { "simple_event":"","meeting":"" }
338 self._order = 0
339 self.__ac = AccessController(self)
340 self.__confCreationRestricted = 1
341 self.__confCreators = []
342 self._visibility = 999
343 self._statistics = {"events":None,"contributions":None,"resources":None,\
344 "updated":None}
345 self._icon=None
346 self.materials = {}
347 #self._materials = {}
348 #self.material ={}
349 self._tasksAllowed = False
350 self._tasks = {}
351 self._taskIdGenerator = 0
352 self._tasksPublic = True
353 self._tasksCommentPublic = True
354 self._tasksManagers = []
355 self._tasksCommentators = []
356 self._taskAccessList = []
357 self._timezone = ""
358 self.__materialGenerator = Counter()
359 self._notifyCreationList = ""
361 def __str__(self):
362 return "<Category %s@%s>" % (self.getId(), hex(id(self)))
364 def getAccessController(self):
365 return self.__ac
367 def updateFullyPublic( self ):
368 pass
370 def getNotifyCreationList( self ):
371 """ self._notifyCreationList is a string containing the list of
372 email addresses to send an email to when a new event is created"""
373 try:
374 return self._notifyCreationList
375 except:
376 self._notifyCreationList = ""
377 return self._notifyCreationList
379 def setNotifyCreationList( self, value ):
380 self._notifyCreationList = value
382 def getUniqueId( self ):
383 return "cat%s" % self.getId()
385 def setPaper( self, newPaper ):
386 if self.getPaper() != None:
387 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
388 self.paper=newPaper
389 self.paper.setOwner( self )
390 self.notifyModification()
392 def cleanCache( self ):
393 """ delete cache files of this category and its fathers
394 usually used when an object in the category has changed """
395 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
396 if minfo.isCacheActive():
397 for id in self.getCategoryPath():
398 cache = CategoryCache({"categId":id})
399 cache.cleanCache()
401 def clearCache( self ):
402 """ delete cache file of this category. usually used for
403 admin purposes """
404 cache = CategoryCache({"categId":self.getId()})
405 cache.cleanCache()
407 def clearConferenceCaches( self ):
408 """ delete cache files of all conferences in the category
409 usually used for admin purposes """
410 for conf in self.getConferenceList():
411 conf.cleanCache()
413 def removePaper( self ):
414 if self.paper is None:
415 return
416 self.paper.delete()
417 self.paper.setOwner(None)
418 self.paper = None
419 self.notifyModification()
421 def recoverPaper(self, p):
422 self.setPaper(p)
423 p.recover()
425 def getPaper( self ):
426 try:
427 if self.paper:
428 pass
429 except AttributeError:
430 self.paper = None
431 return self.paper
433 def setSlides( self, newSlides ):
434 if self.getSlides() != None:
435 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
436 self.slides=newSlides
437 self.slides.setOwner( self )
438 self.notifyModification()
440 def removeSlides( self ):
441 if self.slides is None:
442 return
443 self.slides.delete()
444 self.slides.setOwner( None )
445 self.slides= None
446 self.notifyModification()
448 def recoverSlides(self, s):
449 self.setSlides(s)
450 s.recover()
452 def getSlides( self ):
453 try:
454 if self.slides:
455 pass
456 except AttributeError:
457 self.slides = None
458 return self.slides
460 def setVideo( self, newVideo ):
461 if self.getVideo() != None:
462 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
463 self.video=newVideo
464 self.video.setOwner( self )
465 self.notifyModification()
467 def removeVideo( self ):
468 if self.getVideo() is None:
469 return
470 self.video.delete()
471 self.video.setOwner(None)
472 self.video = None
473 self.notifyModification()
475 def recoverVideo(self, v):
476 self.setVideo(v)
477 v.recover()
479 def getVideo( self ):
480 try:
481 if self.video:
482 pass
483 except AttributeError:
484 self.video = None
485 return self.video
487 def setPoster( self, newPoster ):
488 if self.getPoster() != None:
489 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
490 self.poster=newPoster
491 self.poster.setOwner( self )
492 self.notifyModification()
494 def removePoster( self ):
495 if self.getPoster() is None:
496 return
497 self.poster.delete()
498 self.poster.setOwner(None)
499 self.poster = None
500 self.notifyModification()
502 def recoverPoster(self, p):
503 self.setPoster(p)
504 p.recover()
506 def getPoster( self ):
507 try:
508 if self.poster:
509 pass
510 except AttributeError:
511 self.poster = None
512 return self.poster
514 def setMinutes( self, newMinutes ):
515 if self.getMinutes() != None:
516 raise MaKaCError( _("The Minutes for this conference has already been set"))
517 self.minutes=newMinutes
518 self.minutes.setOwner( self )
519 self.notifyModification()
521 def createMinutes( self ):
522 if self.getMinutes() != None:
523 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
524 self.minutes = Minutes()
525 self.minutes.setOwner( self )
526 self.notifyModification()
527 return self.minutes
529 def removeMinutes( self ):
530 if self.getMinutes() is None:
531 return
532 self.minutes.delete()
533 self.minutes.setOwner( None )
534 self.minutes = None
535 self.notifyModification()
537 def recoverMinutes(self, min):
538 self.removeMinutes() # To ensure that the current minutes are put in
539 # the trash can.
540 self.minutes = min
541 self.minutes.setOwner( self )
542 min.recover()
543 self.notifyModification()
544 return self.minutes
546 def getMinutes( self ):
547 #To be removed
548 try:
549 if self.minutes:
550 pass
551 except AttributeError, e:
552 self.minutes = None
553 return self.minutes
555 def addMaterial( self, newMat ):
556 try:
557 newMat.setId( str(self.__materialGenerator.newCount()) )
558 except:
559 self.__materialGenerator = Counter()
560 newMat.setId(self.__materialGenerator.newCount() )
561 newMat.setOwner( self )
562 self.materials[ newMat.getId() ] = newMat
563 self.notifyModification()
565 def removeMaterial( self, mat ):
566 if mat.getId() in self.materials.keys():
567 self.materials[mat.getId()].setOwner(None)
568 del self.materials[ mat.getId() ]
569 mat.delete()
570 self.notifyModification()
571 return "done: %s"%mat.getId()
572 elif mat.getId().lower() == 'minutes':
573 self.removeMinutes()
574 return "done: %s"%mat.getId()
575 elif mat.getId().lower() == 'paper':
576 self.removePaper()
577 return "done: %s"%mat.getId()
578 elif mat.getId().lower() == 'slides':
579 self.removeSlides()
580 return "done: %s"%mat.getId()
581 elif mat.getId().lower() == 'video':
582 self.removeVideo()
583 return "done: %s"%mat.getId()
584 elif mat.getId().lower() == 'poster':
585 self.removePoster()
586 return "done: %s"%mat.getId()
587 return "not done: %s"%mat.getId()
589 def recoverMaterial(self, recMat):
590 # Id must already be set in recMat.
591 recMat.setOwner( self )
592 self.materials[ recMat.getId() ] = recMat
593 recMat.recover()
594 self.notifyModification()
596 def getMaterialRegistry(self):
598 Return the correct material registry for this type
600 from MaKaC.webinterface.materialFactories import CategoryMFRegistry
601 return CategoryMFRegistry
603 def getMaterialById( self, matId ):
604 if matId.lower() == 'paper':
605 return self.getPaper()
606 elif matId.lower() == 'slides':
607 return self.getSlides()
608 elif matId.lower() == 'video':
609 return self.getVideo()
610 elif matId.lower() == 'poster':
611 return self.getPoster()
612 elif matId.lower() == 'minutes':
613 return self.getMinutes()
614 elif self.materials.has_key(matId):
615 return self.materials[ matId ]
616 return None
618 def getMaterialList( self ):
619 try:
620 return self.materials.values()
621 except:
622 self.materials={}
623 return self.materials.values()
625 def getAllMaterialList( self ):
626 l = self.getMaterialList()
627 if self.getPaper():
628 l.append( self.getPaper() )
629 if self.getSlides():
630 l.append( self.getSlides() )
631 if self.getVideo():
632 l.append( self.getVideo() )
633 if self.getPoster():
634 l.append( self.getPoster() )
635 if self.getMinutes():
636 l.append( self.getMinutes() )
637 return l
639 def getTaskList(self):
640 try :
641 return self._tasks.values()
642 except :
643 self._tasks = {}
644 return self._tasks.values()
646 def getTitle(self):
647 return self.name
649 def getTasks(self):
650 try :
651 return self._tasks
652 except :
653 self._tasks = {}
654 return self._tasks
656 def getTask(self, taskId):
657 return self.getTasks().get(taskId,None)
659 def _getTasksAllowed(self):
660 try :
661 return self._tasksAllowed
662 except :
663 self._tasksAllowed = False
664 return self._tasksAllowed
666 def tasksAllowed(self):
667 if self.hasSubcategories():
668 return False
669 return self._getTasksAllowed()
671 def setTasksAllowed(self):
672 if self.hasSubcategories() :
673 return False
674 self._getTasksAllowed()
675 self._tasksAllowed = True
676 self.notifyModification()
677 return True
679 def setTasksForbidden(self):
680 if len(self.getTaskList()) > 0 :
681 return False
682 self._getTasksAllowed()
683 self._tasksAllowed = False
684 self.notifyModification()
685 return False
687 def _getNewTaskId(self):
688 try :
689 if self._taskIdGenerator :
690 pass
691 except :
692 self._taskIdGenerator = 0
693 self._taskIdGenerator = self._taskIdGenerator + 1
694 return self._taskIdGenerator
696 def newTask(self, user):
697 if user is None :
698 return None
699 newTask = task.Task(self, self._getNewTaskId(), user)
700 self.getTasks()["%s"%newTask.getId()] = newTask
701 self.notifyModification()
702 return newTask
704 def tasksPublic(self):
705 try :
706 return self._tasksPublic
707 except :
708 self._tasksPublic = True
709 return self._tasksPublic
711 def setTasksPublic(self):
712 self.tasksPublic()
713 self._tasksPublic = True
715 def setTasksPrivate(self):
716 self.tasksPublic()
717 self._tasksPublic = False
719 def tasksCommentPublic(self):
720 try :
721 return self._tasksCommentPublic
722 except :
723 self._tasksCommentPublic = True
724 return self._tasksCommentPublic
726 def setTasksCommentPublic(self):
727 self.tasksCommentPublic()
728 self._tasksCommentPublic = True
730 def setTasksCommentPrivate(self):
731 self.tasksCommentPublic()
732 self._tasksCommentPublic = False
734 def getTasksManagerList(self):
735 try :
736 return self._tasksManagers
737 except :
738 self._tasksManagers = []
739 self._p_changed = 1
740 return self._tasksManagers
742 def getTasksManager(self, index):
743 length = len(self.getTasksManagerList())
744 if index < 0 or index >= length :
745 return None
746 return self._tasksManagers[index]
748 def addTasksManager(self,user):
749 if user is None :
750 return False
751 self.getTasksManagerList().append(user)
752 self._p_changed = 1
753 return True
755 def removeTasksManager(self, index):
756 length = len(self.getTasksManagerList())
757 if index < 0 or index >= length :
758 return False
759 del self.getTasksManagerList()[index]
760 self._p_changed = 1
761 return True
763 def getTasksCommentatorList(self):
764 try :
765 return self._tasksCommentators
766 except :
767 self._tasksCommentators = []
768 self._p_changed = 1
769 return self._tasksCommentators
771 def getTasksCommentator(self, index):
772 length = len(self.getTasksCommentatorList())
773 if index < 0 or index >= length :
774 return None
775 return self._tasksCommentators[index]
777 def addTasksCommentator(self,user):
778 if user is None :
779 return False
780 self.getTasksCommentatorList().append(user)
781 self._p_changed = 1
782 return True
784 def removeTasksCommentator(self, index):
785 length = len(self.getTasksCommentatorList())
786 if index < 0 or index >= length :
787 return False
788 del self._tasksCommentators[index]
789 self._p_changed = 1
790 return True
793 def getTasksAccessList(self):
794 try :
795 return self._tasksAccessList
796 except :
797 self._tasksAccessList = []
798 self._p_changed = 1
799 return self._tasksAccessList
801 def getTasksAccessPerson(self, index):
802 length = len(self.getTasksAccessList())
803 if index < 0 or index >= length :
804 return None
805 return self._tasksAccessList[index]
807 def addTasksAccessPerson(self,user):
808 if user is None :
809 return False
810 self.getTasksAccessList().append(user)
811 self._p_changed = 1
812 return True
814 def removeTasksAccessPerson(self, index):
815 length = len(self.getTasksAccessList())
816 if index < 0 or index >= length :
817 return False
818 del self.getTasksAccessList()[index]
819 self._p_changed = 1
820 return True
822 def hasSubcategories(self):
823 return len(self.subcategories.values()) > 0
825 def getVisibility ( self ):
826 # TODO: Check if this actually works
827 # since getOwner() can be None (root categ)
828 try:
829 return max(0,min(int(self._visibility), self.getOwner().getVisibility()+1))
830 except:
831 self._visibility = 999
832 return 999
834 def setVisibility( self, visibility=999 ):
835 self._visibility = int(visibility)
836 self._reindex()
838 def _reindex( self ):
839 catIdx = indexes.IndexesHolder().getIndex('category')
840 catIdx.reindexCateg(self)
841 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
842 catDateIdx.reindexCateg(self)
844 def isRoot( self ):
845 #to be improved
846 return self.owner == None
848 def getDefaultStyle( self, type ):
849 try:
850 return self._defaultStyle[type]
851 except:
852 return ""
854 def setDefaultStyle( self, type, style, subcatsStyle=False ):
855 try:
856 self._defaultStyle[type] = style
857 except:
858 self._defaultStyle = { "simple_event":"","meeting":"" }
859 self._defaultStyle[type] = style
860 self.notifyModification()
861 #raise str(subcatsStyle)
862 if subcatsStyle:
864 categ=self.getSubCategoryList()
866 for cat in categ:
867 cat.setDefaultStyle(type, style, subcatsStyle )
869 ##################################
870 # Fermi timezone awareness #
871 ##################################
872 def getTimezone(self):
873 try:
874 if self._timezone not in all_timezones:
875 self.setTimezone('UTC')
876 return self._timezone
877 except:
878 self.setTimezone('UTC')
879 return 'UTC'
881 def setTimezone(self,tz):
882 self._timezone = tz
885 def changeConfTimezones(self, tz):
886 for conference in self.getConferenceList():
887 conference.moveToTimezone(tz)
889 ##################################
890 # Fermi timezone awareness(end) #
891 ##################################
893 def getOrder( self ):
894 try:
895 return self._order
896 except:
897 self._order = 0
898 return 0
900 def setOrder( self, order ):
901 self._order = order
903 def getId( self ):
904 return self.id
906 def setId( self, newId ):
907 self.id = str( newId.strip() )
909 def getLocator( self ):
910 """Gives back (Locator) a globaly unique identification encapsulated
911 in a Locator object for the category instance """
912 d = Locator()
913 d["categId"] = self.getId()
914 return d
916 def getCategory(self):
917 return self
919 def getOwner( self ):
920 return self.owner
922 def setOwner( self, newOwner ):
923 if self.getOwner() != None and newOwner != None and self.getOwner() != newOwner:
924 self.move( newOwner )
925 else:
926 self.owner = newOwner
928 def getCategoryPath(self):
929 if self.isRoot():
930 return [self.getId()]
931 else:
932 l = self.getOwner().getCategoryPath()
933 l.append(self.getId())
934 return l
936 def getCategoryPathTitles(self):
937 # Breadcrumbs
938 breadcrumbs = []
939 cat = self
940 while cat:
941 breadcrumbs.insert(0, cat.getTitle())
942 cat = cat.getOwner()
943 return breadcrumbs
945 def delete( self, deleteConferences=0 ):
946 """removes completely a category (and all its sub-items) from the
947 system"""
949 oldOwner = self.getOwner()
951 if self.isRoot():
952 raise MaKaCError( _("Root category cannot be deleted"), _("Category"))
953 if not deleteConferences:
954 if self.getNumConferences()>0:
955 raise MaKaCError( _("This category still contains some conferences, please remove them first"), _("Category"))
956 self.cleanCache()
957 for subcateg in self.getSubCategoryList():
958 subcateg.delete( deleteConferences )
959 for conference in self.getConferenceList():
960 self.removeConference( conference, delete = True )
961 self.getOwner()._removeSubCategory( self )
962 CategoryManager().remove( self )
963 TrashCanManager().add(self)
965 self._notify('deleted', oldOwner)
967 return
969 def move( self, newOwner ):
970 oldOwner = self.getOwner()
971 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
973 catDateIdx.unindexCateg(self)
975 self.getOwner()._removeSubCategory( self )
976 newOwner._addSubCategory( self )
977 self._reindex()
978 catDateIdx.indexCateg(self)
980 self._notify('moved', oldOwner, newOwner)
982 def getName( self ):
983 return self.name
985 def setName( self, newName ):
986 oldName = self.name
987 self.name = newName.strip()
989 # Reindex when name changes
990 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
991 nameIdx.unindex(self.getId())
992 nameIdx.index(self.getId(), self.getTitle().decode('utf-8'))
994 self._notify('categoryTitleChanged', oldName, newName)
996 self.cleanCache()
998 def getDescription( self ):
999 return self.description
1001 def setDescription( self, newDesc ):
1002 self.description = newDesc.strip()
1003 self.cleanCache()
1005 def moveConference(self, conf, toCateg):
1007 Moves a conference from this category to another one
1009 self.removeConference( conf )
1010 toCateg._addConference( conf )
1011 conf._notify('moved', self, toCateg)
1013 def _addSubCategory( self, newSc ):
1014 #categories can only contain either conferences either other categories
1015 # but can never contain both. For the moment an exception is raised
1016 # but this could be replaced by the following policy: if a
1017 # sub-category is to be added to a category already containing
1018 # conferences then the conferes are moved into the new sub-category
1019 # and it is added to target category.
1020 #first, check that the category is registered if not raise an exception
1021 if len(self.conferences)>0:
1022 for conf in self.getConferenceList():
1023 self.moveConference(conf, newSc)
1025 if len(self.conferences)>0:
1026 raise MaKaCError( _("Cannot add subcategory: the current category already contains events"), _("Category"))
1027 newSc.setOwner( self )
1028 self.subcategories[ newSc.getId() ] = newSc
1029 self._incNumConfs(newSc.getNumConferences())
1030 self.cleanCache()
1032 def _removeSubCategory( self, sc ):
1033 """if the given subcategory belongs to the current category it removes
1034 it from the subcategories list (don't use this method, use delete
1035 instead)
1037 if sc in self.getSubCategoryList():
1038 self._decNumConfs(sc.getNumConferences())
1039 del self.subcategories[ sc.getId() ]
1040 sc.setOwner( None )
1041 self.cleanCache()
1043 def newSubCategory(self, protection):
1044 cm = CategoryManager()
1045 sc = Category()
1046 cm.add( sc )
1048 # set the protection
1049 sc.setProtection(protection)
1051 Catalog.getIdx('categ_conf_sd').add_category(sc.getId())
1052 sc._notify('created', self)
1054 self._addSubCategory( sc )
1055 self.cleanCache()
1057 return sc
1059 def _incNumConfs(self, num=1):
1060 """Increases the number of conferences for the current category in a given number.
1061 WARNING: Only Categories must use this method!!!"""
1062 self._numConferences = self.getNumConferences()
1063 self._numConferences+=num
1064 if self.getOwner() is not None:
1065 self.getOwner()._incNumConfs(num)
1067 def _decNumConfs(self, num=1):
1068 """Decreases the number of conferences for the current category in a given number.
1069 WARNING: Only Categories must use this method!!!"""
1070 self._numConferences = self.getNumConferences()
1071 self._numConferences-=num
1072 if self.getOwner() is not None:
1073 self.getOwner()._decNumConfs(num)
1075 def _addConference( self, newConf ):
1076 if len(self.subcategories)>0:
1077 raise MaKaCError( _("Cannot add event: the current category already contains some sub-categories"), _("Category"))
1078 if newConf.getId() == "":
1079 raise MaKaCError( _("Cannot add to a category an event which is not registered"), _("Category"))
1080 self.conferences.insert(newConf)
1081 newConf.addOwner(self)
1082 self._incNumConfs(1)
1083 self.indexConf(newConf)
1084 self.cleanCache()
1086 def getAccessKey(self):
1087 return ""
1089 def getModifKey(self):
1090 return ""
1092 def indexConf( self, conf ):
1093 # Specific for category changes, calls Conference.indexConf()
1094 # (date-related indexes)
1095 catIdx = indexes.IndexesHolder().getIndex('category')
1096 catIdx.indexConf(conf)
1097 conf.indexConf()
1099 def unindexConf( self, conf ):
1100 catIdx = indexes.IndexesHolder().getIndex('category')
1101 catIdx.unindexConf(conf)
1102 conf.unindexConf()
1104 def newConference( self, creator, id="", creationDate=None, modificationDate=None ):
1105 conf = Conference( creator, id, creationDate, modificationDate )
1106 ConferenceHolder().add( conf )
1107 self._addConference( conf )
1109 conf._notify('created', self)
1111 return conf
1113 def removeConference( self, conf, notify=True, delete = False ):
1114 if not (conf in self.conferences):
1115 return
1117 self.unindexConf( conf )
1119 self.conferences.remove(conf)
1120 if delete:
1121 conf.delete()
1122 conf.removeOwner( self, notify )
1123 self._decNumConfs(1)
1124 self.cleanCache()
1126 def getSubCategoryList( self ):
1127 subcategs = self.subcategories.values()
1128 cl = []
1129 for categ in subcategs:
1130 cl.append("%04s%s-%s" % (categ.getOrder(),categ.getName().replace("-",""),categ.getId()))
1131 cl.sort()
1132 res = []
1133 for c in cl:
1134 id = c.split("-")[1]
1135 res.append(self.subcategories[id])
1136 return res
1138 def iteritems(self, *args):
1139 return self.conferences.iteritems(*args)
1141 def itervalues(self, *args):
1142 return self.conferences.itervalues(*args)
1144 def getConferenceList( self, sortType=1 ):
1145 """returns the list of conferences included in the current category.
1146 Thanks to the used structure the list is sorted by date.
1147 We can choose other sorting types:
1149 sortType=1--> By date
1150 sortType=2--> Alphabetically
1151 sortType=3--> Alphabetically - Reversed
1154 res = sorted(self.conferences, cmp=Conference._cmpByDate)
1156 if sortType==2:
1157 res.sort(Conference._cmpTitle)
1158 elif sortType==3:
1159 res.sort(Conference._cmpTitle)
1160 res = reversed(res)
1161 return res
1163 def iterConferences( self):
1164 """returns the iterator for conferences.
1166 return self.conferences
1168 def iterAllConferences( self):
1169 """returns the iterator for conferences in all subcategories.
1171 for conf in self.conferences:
1172 yield conf
1174 for subcateg in self.subcategories.itervalues():
1175 for conf in subcateg.iterAllConferences():
1176 yield conf
1178 def getAllConferenceList( self ):
1179 """returns the list of all conferences included in the current category
1180 and in all its subcategories"""
1181 res = self.getConferenceList()
1182 subcategs = self.getSubCategoryList()
1183 if subcategs != []:
1184 for subcateg in subcategs:
1185 res.extend(subcateg.getAllConferenceList())
1186 return res
1188 def getNeighborEvents(self, conf):
1190 index = Catalog.getIdx('categ_conf_sd').getCategory(conf.getOwner().getId())
1191 first, last = list(index[index.minKey()])[0], list(index[index.maxKey()])[-1]
1193 categIter = index.itervalues()
1195 prev = None
1196 for c in categIter:
1197 if c == conf:
1198 break
1199 prev = c
1201 nextEvt = next(categIter, None)
1203 # if the event is already the first or the last, don't confuse
1204 # users by showing the respective arrow
1205 if first == conf:
1206 first = None
1207 if last == conf:
1208 last = None
1210 return prev, nextEvt, first, last
1212 def _setNumConferences(self):
1213 self._numConferences = 0
1214 if self.conferences:
1215 self._incNumConfs(len(self.conferences))
1216 else:
1217 for sc in self.getSubCategoryList():
1218 self._incNumConfs(sc.getNumConferences())
1221 def getNumConferences( self ):
1222 """returns the total number of conferences contained in the current
1223 category and all its sub-categories (if any)"""
1224 #this new approach will speed up considerably the counting of category
1225 # conferences. However, it will give non accurate results for
1226 # conferences within many categories (a conference will be counted
1227 # twice in parent categories).
1228 # Besides this approach will generate much more conflict errors. This
1229 # can be reduced by simply isolating the counter in a separate object.
1230 try:
1231 if self._numConferences:
1232 pass
1233 except AttributeError:
1234 self._setNumConferences()
1235 return self._numConferences
1237 def _getRepository( self ):
1238 dbRoot = DBMgr.getInstance().getDBConnection().root()
1239 try:
1240 fr = dbRoot["local_repositories"]["main"]
1241 except KeyError, e:
1242 fr = fileRepository.MaterialLocalRepository()
1243 dbRoot["local_repositories"] = OOBTree()
1244 dbRoot["local_repositories"]["main"] = fr
1245 return fr
1247 def removeResource( self, res ):
1248 pass
1250 def setIcon( self, iconFile ):
1251 iconFile.setOwner( self )
1252 iconFile.setId( "icon" )
1253 iconFile.archive( self._getRepository() )
1254 iconFile.setProtection( -1 )
1255 if self.getIcon() != None:
1256 self._icon.delete()
1257 self._icon = iconFile
1258 self.notifyModification()
1260 def getIcon( self ):
1261 try:
1262 if self._icon:
1263 pass
1264 except AttributeError, e:
1265 self._icon=None
1266 return self._icon
1268 def getIconURL( self ):
1269 if self.getIcon() is None:
1270 return ""
1271 return self._icon.getURL()
1273 def removeIcon(self):
1274 if self.getIcon() is None:
1275 return
1276 self._icon.delete()
1277 self._icon = None
1278 self.notifyModification()
1280 def recoverIcon(self, icon):
1281 icon.setOwner(self)
1282 if self.getIcon() != None:
1283 self._icon.delete()
1284 self._icon = icon
1285 icon.recover()
1286 self.notifyModification()
1288 def getManagerList( self ):
1289 return self.__ac.getModifierList()
1291 def grantModification( self, prin ):
1292 self.__ac.grantModification( prin )
1293 if isinstance(prin, MaKaC.user.Avatar):
1294 prin.linkTo(self, "manager")
1295 self.cleanCache()
1297 def revokeModification( self, prin ):
1298 self.__ac.revokeModification( prin )
1299 if isinstance(prin, MaKaC.user.Avatar):
1300 prin.unlinkTo(self, "manager")
1301 self.cleanCache()
1303 def canModify( self, aw ):
1304 return self.canUserModify( aw.getUser() )
1306 def canUserModify( self, av ):
1307 inherited = 0
1308 if self.getOwner() != None:
1309 inherited = self.getOwner().canUserModify( av )
1310 return inherited or self.__ac.canModify( av )
1313 def getAllowedToAccessList( self ):
1314 return self.__ac.getAccessList()
1316 def canKeyAccess( self, aw ):
1317 # Categories don't allow access keys
1318 return False
1320 def canIPAccess( self, ip ):
1321 if not self.__ac.canIPAccess( ip ):
1322 return False
1323 if self.getOwner():
1324 return self.getOwner().canIPAccess(ip)
1325 return True
1327 def isProtected( self ):
1328 return self.__ac.isProtected()
1330 def getAccessProtectionLevel( self ):
1331 return self.__ac.getAccessProtectionLevel()
1333 def isItselfProtected( self ):
1334 return self.__ac.isItselfProtected()
1336 def hasAnyProtection( self ):
1337 if self.__ac.isProtected() or len(self.getDomainList())>0:
1338 return True
1339 if self.getAccessProtectionLevel() == -1: #PUBLIC
1340 return False
1341 if self.getOwner() is not None:
1342 return self.getOwner().hasAnyProtection()
1343 return False
1345 def setProtection( self, private ):
1347 Allows to change the category's access protection
1350 oldProtection = 1 if self.isProtected() else -1
1352 self.__ac.setProtection( private )
1353 self._notify('protectionChanged', oldProtection, private)
1354 self.cleanCache()
1356 def hasProtectedOwner( self ):
1357 return self.__ac._getFatherProtection()
1359 def isAllowedToAccess( self, av ):
1360 """Says whether an avatar can access a category independently of it is
1361 or not protected or domain filtered
1363 if self.__ac.canUserAccess( av ) or self.canUserModify( av ):
1364 return True
1365 if not self.isItselfProtected() and self.getOwner():
1366 return self.getOwner().isAllowedToAccess( av )
1368 def canView(self,aw):
1369 if self.canAccess( aw ):
1370 return True
1371 for conf in self.getConferenceList():
1372 if conf.canView( aw ):
1373 return True
1374 for subcateg in self.getSubCategoryList():
1375 if subcateg.canView( aw ):
1376 return True
1377 return False
1379 def canAccess( self, aw ):
1380 if not self.hasAnyProtection():
1381 return True
1382 if not self.isProtected():
1383 #domain checking only triggered if the category is PUBLIC
1384 return self.canIPAccess( aw.getIP() ) or \
1385 self.isAllowedToCreateConference(aw.getUser()) or \
1386 self.isAllowedToAccess(aw.getUser())
1387 return self.isAllowedToCreateConference(aw.getUser()) or \
1388 self.isAllowedToAccess(aw.getUser())
1390 def grantAccess( self, prin ):
1391 self.__ac.grantAccess( prin )
1392 if isinstance(prin, MaKaC.user.Avatar):
1393 prin.linkTo(self, "access")
1395 def revokeAccess( self, prin ):
1396 self.__ac.revokeAccess( prin )
1397 if isinstance(prin, MaKaC.user.Avatar):
1398 prin.unlinkTo(self, "access")
1400 def isConferenceCreationRestricted( self ):
1401 return self.__confCreationRestricted
1403 def restrictConferenceCreation( self ):
1404 self.__confCreationRestricted = 1
1406 def allowConferenceCreation( self ):
1407 self.__confCreationRestricted = 0
1409 def grantConferenceCreation( self, prin ):
1410 if prin not in self.__confCreators:
1411 self.__confCreators.append( prin )
1412 if isinstance(prin, MaKaC.user.Avatar):
1413 prin.linkTo(self, "creator")
1414 self._p_changed = 1
1416 def revokeConferenceCreation( self, prin ):
1417 if prin in self.__confCreators:
1418 self.__confCreators.remove( prin )
1419 if isinstance(prin, MaKaC.user.Avatar):
1420 prin.unlinkTo(self, "creator")
1421 self._p_changed = 1
1423 def getConferenceCreatorList( self ):
1424 return self.__confCreators
1426 def isAllowedToCreateConference( self, av ):
1428 if self.canUserModify( av ):
1429 return 1
1431 # Avatar is directly in the list
1432 if av in self.__confCreators:
1433 return 1
1435 # Otherwise, if it is a member of one of the groups in the list...
1436 for group in self.__confCreators:
1437 if isinstance(group, MaKaC.user.Group):
1438 if group.containsUser(av):
1439 return 1
1440 else:
1441 pass
1442 return 0
1444 def canCreateConference( self, av ):
1445 if not self.isConferenceCreationRestricted():
1446 return 1
1447 return self.isAllowedToCreateConference( av )
1449 def requireDomain( self, dom ):
1450 self.__ac.requireDomain( dom )
1451 self._notify('accessDomainAdded', dom)
1453 def freeDomain( self, dom ):
1454 self.__ac.freeDomain( dom )
1455 self._notify('accessDomainRemoved', dom)
1457 def getDomainList( self ):
1458 return self.__ac.getRequiredDomainList()
1460 def getStatistics( self ):
1461 try:
1462 if self._statistics:
1463 pass
1464 except AttributeError, e:
1465 self._statistics = {}
1466 return self._statistics
1468 def notifyModification( self ):
1469 """Method called to notify the current category has been modified.
1471 self._notify('infoChanged')
1472 self.cleanCache()
1473 self._p_changed=1
1476 class CustomLocation(Persistent):
1478 def __init__(self, **locationData):
1479 self.name = ""
1480 self.address = ""
1481 self.room = ""
1483 def setValues(self, data):
1484 self.setName(data.get("name",""))
1485 self.setAddress(data.get("address",""))
1486 self.setRoom(data.get("room",""))
1488 def getValues(self):
1489 d={}
1490 d["name"]=self.getName()
1491 d["address"]=self.getAddress()
1492 d["room"]=self.getRoom()
1493 return d
1495 def clone(self):
1496 newCL=CustomLocation()
1497 newCL.setValues(self.getValues())
1498 return newCL
1500 def setName(self, newName):
1501 self.name = newName
1503 def getName(self):
1504 return self.name
1506 def setAddress(self, newAddress):
1507 self.address = newAddress
1509 def getAddress(self):
1510 return self.address
1512 def setRoom(self, newRoom):
1513 self.room = newRoom
1515 def getRoom(self):
1516 return self.room
1519 class CustomRoom(Persistent):
1521 def __init__( self ):
1522 self.name = ""
1524 def setValues(self, data):
1525 self.setName(data.get("name",""))
1527 def getValues(self):
1528 d={}
1529 d["name"]=self.getName()
1530 return d
1532 def getId(self):
1533 return "Custom"
1535 def clone(self):
1536 newCR=CustomRoom()
1537 newCR.setValues(self.getValues())
1538 return newCR
1540 def setName( self, newName ):
1541 self.name = newName.strip()
1543 def getName( self ):
1544 return self.name
1547 class ConferenceParticipation(Persistent, Fossilizable, Observable):
1549 fossilizes(IConferenceParticipationFossil, IConferenceParticipationMinimalFossil)
1551 def __init__(self):
1552 self._firstName=""
1553 self._surName=""
1554 self._email=""
1555 self._affiliation=""
1556 self._address=""
1557 self._phone=""
1558 self._title=""
1559 self._fax=""
1561 def _notifyModification( self ):
1562 pass
1564 def setValues(self, data):
1565 self.setFirstName(data.get("firstName", ""))
1566 self.setFamilyName(data.get("familyName",""))
1567 self.setAffiliation(data.get("affilation",""))
1568 self.setAddress(data.get("address",""))
1569 self.setEmail(data.get("email",""))
1570 self.setFax(data.get("fax",""))
1571 self.setTitle(data.get("title",""))
1572 self.setPhone(data.get("phone",""))
1573 self._notifyModification()
1575 def getValues(self):
1576 data={}
1577 data["firstName"]=self.getFirstName()
1578 data["familyName"]=self.getFamilyName()
1579 data["affilation"]=self.getAffiliation()
1580 data["address"]=self.getAddress()
1581 data["email"]=self.getEmail()
1582 data["fax"]=self.getFax()
1583 data["title"]=self.getTitle()
1584 data["phone"]=self.getPhone()
1585 return data
1587 def setId(self, newId):
1588 self._id = newId
1590 def getId( self ):
1591 return self._id
1593 def setDataFromAvatar(self,av):
1594 # av is an Avatar object.
1595 if av is None:
1596 return
1597 self.setFirstName(av.getName())
1598 self.setFamilyName(av.getSurName())
1599 self.setEmail(av.getEmail())
1600 self.setAffiliation(av.getOrganisation())
1601 self.setAddress(av.getAddress())
1602 self.setPhone(av.getTelephone())
1603 self.setTitle(av.getTitle())
1604 self.setFax(av.getFax())
1605 self._notifyModification()
1607 def setDataFromOtherCP(self,cp):
1608 # cp is a ConferenceParticipation object.
1609 if cp is None:
1610 return
1611 self.setFirstName(cp.getFirstName())
1612 self.setFamilyName(cp.getFamilyName())
1613 self.setEmail(cp.getEmail())
1614 self.setAffiliation(cp.getAffiliation())
1615 self.setAddress(cp.getAddress())
1616 self.setPhone(cp.getPhone())
1617 self.setTitle(cp.getTitle())
1618 self.setFax(cp.getFax())
1619 self._notifyModification()
1621 def delete( self ):
1622 TrashCanManager().add(self)
1624 def recover(self):
1625 TrashCanManager().remove(self)
1627 @Updates (['MaKaC.conference.ConferenceParticipation',
1628 'MaKaC.conference.SessionChair',
1629 'MaKaC.conference.SlotChair'], 'firstName')
1630 def setFirstName(self,newName):
1631 tmp=newName.strip()
1632 if tmp==self._firstName:
1633 return
1634 self._firstName=tmp
1635 self._notifyModification()
1637 def getFirstName( self ):
1638 return self._firstName
1640 @Updates (['MaKaC.conference.ConferenceParticipation',
1641 'MaKaC.conference.SessionChair',
1642 'MaKaC.conference.SlotChair'], 'familyName')
1643 def setFamilyName(self,newName):
1644 tmp=newName.strip()
1645 if tmp==self._surName:
1646 return
1647 self._surName=tmp
1648 self._notifyModification()
1650 def getFamilyName( self ):
1651 return self._surName
1653 @Updates (['MaKaC.conference.ConferenceParticipation',
1654 'MaKaC.conference.SessionChair',
1655 'MaKaC.conference.SlotChair'], 'email')
1656 def setEmail(self,newMail):
1657 tmp=newMail.strip()
1658 if tmp==self._email:
1659 return
1660 self._email=newMail.strip()
1661 self._notifyModification()
1663 def getEmail( self ):
1664 return self._email
1666 @Updates (['MaKaC.conference.ConferenceParticipation',
1667 'MaKaC.conference.SessionChair',
1668 'MaKaC.conference.SlotChair'], 'affiliation')
1669 def setAffiliation(self,newAffil):
1670 self._affiliation=newAffil.strip()
1671 self._notifyModification()
1673 def getAffiliation(self):
1674 return self._affiliation
1676 @Updates (['MaKaC.conference.ConferenceParticipation',
1677 'MaKaC.conference.SessionChair',
1678 'MaKaC.conference.SlotChair'], 'address')
1679 def setAddress(self,newAddr):
1680 self._address=newAddr.strip()
1681 self._notifyModification()
1683 def getAddress(self):
1684 return self._address
1686 @Updates (['MaKaC.conference.ConferenceParticipation',
1687 'MaKaC.conference.SessionChair',
1688 'MaKaC.conference.SlotChair'], 'phone')
1689 def setPhone(self,newPhone):
1690 self._phone=newPhone.strip()
1691 self._notifyModification()
1693 def getPhone(self):
1694 return self._phone
1696 @Updates (['MaKaC.conference.ConferenceParticipation',
1697 'MaKaC.conference.SessionChair',
1698 'MaKaC.conference.SlotChair'], 'title')
1699 def setTitle(self,newTitle):
1700 self._title=newTitle.strip()
1701 self._notifyModification()
1703 def getTitle(self):
1704 return self._title
1706 @Updates (['MaKaC.conference.ConferenceParticipation',
1707 'MaKaC.conference.SessionChair',
1708 'MaKaC.conference.SlotChair'], 'fax')
1709 def setFax(self,newFax):
1710 self._fax=newFax.strip()
1711 self._notifyModification()
1713 def getFax(self):
1714 return self._fax
1716 def getFullName( self ):
1717 res = self.getFamilyName()
1718 if self.getFirstName() != "":
1719 if res.strip() != "":
1720 res = "%s, %s"%( res, self.getFirstName() )
1721 else:
1722 res = self.getFirstName()
1723 if self.getTitle() != "":
1724 res = "%s %s"%( self.getTitle(), res )
1725 return res
1727 def getFullNameNoTitle( self ):
1728 res = self.getFamilyName()
1729 if self.getFirstName() != "":
1730 if res.strip() != "":
1731 res = "%s, %s"%( res, self.getFirstName() )
1732 else:
1733 res = self.getFirstName()
1734 return res
1736 def getDirectFullName( self ):
1737 res = "%s %s"%( self.getFirstName(), self.getFamilyName() )
1738 res=res.strip()
1739 if self.getTitle() != "":
1740 res = "%s %s"%( self.getTitle(), res )
1741 return res
1743 def getAbrName(self):
1744 res = self.getFamilyName()
1745 if self.getFirstName() != "":
1746 if res != "":
1747 res = "%s, "%res
1748 res = "%s%s."%(res, self.getFirstName()[0].upper())
1749 return res
1751 def _cmpFamilyName( cp1, cp2 ):
1752 o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName())
1753 o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName())
1754 o1=o1.lower().strip()
1755 o2=o2.lower().strip()
1756 return cmp( o1, o2 )
1757 _cmpFamilyName=staticmethod(_cmpFamilyName)
1760 class ConferenceChair(ConferenceParticipation):
1762 def __init__(self):
1763 self._conf=None
1764 self._id=""
1765 ConferenceParticipation.__init__(self)
1767 def _notifyModification( self ):
1768 if self._conf != None:
1769 self._conf.notifyModification()
1771 def clone(self):
1772 newCC=ConferenceChair()
1773 newCC.setValues(self.getValues())
1774 return newCC
1776 def getConference(self):
1777 return self._conf
1779 def getId(self):
1780 return self._id
1782 def includeInConference(self,conf,id):
1783 if self.getConference()==conf and self.getId()==id.strip():
1784 return
1785 self._conf=conf
1786 self._id=id
1788 def delete( self ):
1789 self._conf=None
1790 ConferenceParticipation.delete(self)
1792 def getLocator(self):
1793 if self.getConference() is None:
1794 return None
1795 loc=self.getConference().getLocator()
1796 loc["chairId"]=self.getId()
1797 return loc
1799 class SubmitterIndex(Persistent):
1800 """Index for contribution submitters.
1802 This class allows to index users with submission privileges over the
1803 conference contributions so the owner can answer optimally to the query
1804 if a user has any submission privilege over any contribution
1805 of the conference.
1806 It is implemented by simply using a BTree where the Avatar id is used
1807 as key (because it is unique and non variable) and a list of
1808 contributions over which he has submission privileges is kept as values.
1809 It is the responsability of the index owner (conference contributions)
1810 to keep it up-to-date i.e. notify conference sumitters additions and
1811 removals.
1814 def __init__( self ):
1815 self._idx = OOBTree()
1816 self._idxEmail = OOBTree()
1818 def _getIdxEmail(self):
1819 try:
1820 return self._idxEmail
1821 except:
1822 self._idxEmail = OOBTree()
1823 return self._idxEmail
1825 def getContributions(self,av):
1826 """Gives a list with the contributions over which a user has
1827 coordination privileges
1829 if av == None:
1830 return []
1831 ret = self._idx.get(av.getId(),[])
1832 if not ret:
1833 self._moveEmailtoId(av)
1834 ret = self._idx.get(av.getId(),[])
1835 return ret
1837 def index(self,av,contrib):
1838 """Registers in the index a submitter of a contribution.
1840 if av==None or contrib==None:
1841 return
1842 if not self._idx.has_key(av.getId()):
1843 l=[]
1844 self._idx[av.getId()]=l
1845 else:
1846 l=self._idx[av.getId()]
1847 if contrib not in l:
1848 l.append(contrib)
1849 self._idx[av.getId()]=l
1851 def indexEmail(self, email, contrib):
1852 if not email or not contrib:
1853 return
1854 if not self._getIdxEmail().has_key(email):
1855 l = [contrib]
1856 self._getIdxEmail()[email] = l
1857 else:
1858 l = self._getIdxEmail()[email]
1859 if not contrib in l:
1860 l.append(contrib)
1861 self._getIdxEmail()[email] = l
1864 def unindex(self,av,contrib):
1865 if av==None or contrib==None:
1866 return
1867 l=self._idx.get(av.getId(),[])
1868 if contrib in l:
1869 l.remove(contrib)
1870 self._idx[av.getId()]=l
1872 def unindexEmail(self, email, contrib):
1873 if not email or not contrib:
1874 return
1875 if self._getIdxEmail().has_key(email):
1876 l = self._getIdxEmail()[email]
1877 if contrib in l:
1878 l.remove(contrib)
1879 if l == []:
1880 del self._getIdxEmail()[email]
1881 else:
1882 self._getIdxEmail()[email] = l
1884 def _moveEmailtoId(self, av):
1885 id = av.getId()
1886 email = av.getEmail()
1887 if not self._idx.has_key(id):
1888 if self._getIdxEmail().has_key(email):
1889 self._idx[id] = self._getIdxEmail()[email]
1890 del self._getIdxEmail()[email]
1893 class ReportNumberHolder(Persistent):
1895 def __init__(self, owner):
1896 self._owner=owner
1897 self._reports={}
1899 def getOwner(self):
1900 return self._owner
1902 def addReportNumber(self, system, number):
1903 if system in self.getReportNumberKeys() or system in Config.getInstance().getReportNumberSystems().keys():
1904 try:
1905 if not number in self._reports[system]:
1906 self._reports[system].append(number)
1907 except:
1908 self._reports[system]=[ number ]
1909 self.notifyModification()
1911 def removeReportNumber(self, system, number):
1912 if self.hasReportNumber(system):
1913 if number in self._reports[system]:
1914 self._reports[system].remove(number)
1915 self.notifyModification()
1917 def removeReportNumberById(self, id):
1918 try:
1919 rn = self.listReportNumbers()[int(id)]
1920 self.removeReportNumber(rn[0], rn[1])
1921 except:
1922 pass
1924 def hasReportNumber(self, system):
1925 return self._reports.has_key(system)
1927 def getReportNumber(self, system):
1928 if self.hasReportNumber(system):
1929 return self._reports[system]
1930 return None
1932 def getReportNumberKeys(self):
1933 return self._reports.keys()
1935 def listReportNumbersOnKey(self, key):
1936 reports=[]
1937 if key in self._reports.keys():
1938 # compatibility with previous versions
1939 if type(self._reports[key]) is str:
1940 self._reports[key] = [ self._reports[key] ]
1941 for number in self._reports[key]:
1942 reports.append([key, number])
1943 return reports
1945 def listReportNumbers(self):
1946 reports=[]
1947 keys = self._reports.keys()
1948 keys.sort()
1949 for key in keys:
1950 # compatibility with previous versions
1951 if type(self._reports[key]) is str:
1952 self._reports[key] = [ self._reports[key] ]
1953 for number in self._reports[key]:
1954 reports.append([key, number])
1955 return reports
1957 def clone(self, owner):
1958 newR=ReportNumberHolder(owner)
1959 for key in self._reports.keys():
1960 for number in self._reports[key]:
1961 newR.addReportNumber(key, number)
1962 return newR
1964 def notifyModification(self):
1965 self._p_changed=1
1966 if self.getOwner() != None:
1967 self.getOwner().notifyModification()
1969 class Conference(CommonObjectBase, Locatable):
1970 """This class represents the real world conferences themselves. Objects of
1971 this class will contain basic data about the confence and will provide
1972 access to other objects representing certain parts of the conferences
1973 (ex: contributions, sessions, ...).
1976 fossilizes(IConferenceFossil, IConferenceMinimalFossil, IConferenceEventInfoFossil)
1978 def __init__(self, creator, id="", creationDate = None, modificationDate = None):
1979 """Class constructor. Initialise the class attributes to the default
1980 values.
1981 Params:
1982 confData -- (Dict) Contains the data the conference object has to
1983 be initialised to.
1985 #IndexedObject.__init__(self)
1986 if creator == None:
1987 raise MaKaCError( _("A creator must be specified when creating a new Event"), _("Event"))
1988 self.__creator = creator
1989 self.__creator.linkTo(self, "creator")
1990 self.id = id
1991 self.title = ""
1992 self.description = ""
1993 self.places = []
1994 self.rooms = []
1995 ###################################
1996 # Fermi timezone awareness #
1997 ###################################
1998 self.startDate = nowutc()
1999 self.endDate = nowutc()
2000 self.timezone = ""
2001 ###################################
2002 # Fermi timezone awareness(end) #
2003 ###################################
2004 self._screenStartDate = None
2005 self._screenEndDate = None
2006 self.contactInfo =""
2007 self.chairmanText = ""
2008 self.chairmans = []
2009 self._chairGen=Counter()
2010 self._chairs=[]
2011 self.sessions = {}
2012 self.__sessionGenerator = Counter() # Provides session unique
2013 # identifiers for this conference
2014 self.contributions = {}
2015 self.__contribGenerator = Counter() # Provides contribution unique
2016 # identifiers for this conference
2017 self.programDescription = ""
2018 self.program = []
2019 self.__programGenerator = Counter() # Provides track unique
2020 # identifiers for this conference
2021 self.__ac = AccessController(self)
2022 self.materials = {}
2023 self.__materialGenerator = Counter() # Provides material unique
2024 # identifiers for this conference
2025 self.paper = None
2026 self.slides = None
2027 self.video = None
2028 self.poster = None
2029 self.minutes=None
2030 self.__schedule=None
2031 self.__owners = []
2032 if creationDate:
2033 self._creationDS = creationDate
2034 else:
2035 self._creationDS = nowutc() #creation timestamp
2036 if modificationDate:
2037 self._modificationDS = modificationDate
2038 else:
2039 self._modificationDS = nowutc() #modification timestamp
2041 self.alarmList = {}
2042 self.__alarmCounter = Counter()
2044 self.abstractMgr = review.AbstractMgr(self)
2045 self._logo = None
2046 self._trackCoordinators = TCIndex() #index for the track coordinators
2047 self._supportEmail = "" #Support email for the conference
2048 self._contribTypes = {}
2049 self.___contribTypeGenerator = Counter()
2050 self._authorIdx=AuthorIndex()
2051 self._speakerIdx=AuthorIndex()
2052 self._primAuthIdx=_PrimAuthIdx(self)
2053 self._sessionCoordinators=SCIndex()
2054 self._sessionCoordinatorRights = []
2055 self._submitterIdx=SubmitterIndex()
2056 self._boa=BOAConfig(self)
2057 self._registrationForm = registration.RegistrationForm(self)
2058 self._evaluationCounter = Counter()
2059 self._evaluations = [Evaluation(self)]
2060 self._registrants = {} #key=registrantId; value=Registrant
2061 self._bookings = {}
2062 self._registrantGenerator = Counter()
2063 self._accessKey=""
2064 self._modifKey=""
2065 self._closed = False
2066 self._visibility = 999
2067 self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self)
2068 self._sections = []
2069 self._participation = Participation(self)
2070 self._logHandler = LogHandler()
2071 self._reportNumberHolder=ReportNumberHolder(self)
2072 self._enableSessionSlots = False
2073 self._enableSessions = False
2074 self._autoSolveConflict = True
2075 self.__badgeTemplateManager = BadgeTemplateManager(self)
2076 self.__posterTemplateManager = PosterTemplateManager(self)
2077 self._keywords = ""
2078 self._confPaperReview = ConferencePaperReview(self)
2079 self._confAbstractReview = ConferenceAbstractReview(self)
2080 self._orgText = ""
2081 self._comments = ""
2082 self._sortUrlTag = ""
2084 self._observers = []
2086 if PluginsHolder().hasPluginType("Collaboration"):
2087 from MaKaC.plugins.Collaboration.base import CSBookingManager
2088 self._CSBookingManager = CSBookingManager(self)
2090 def __str__(self):
2091 return "<Conference %s@%s>" % (self.getId(), hex(id(self)))
2093 @staticmethod
2094 def _cmpByDate(self, toCmp):
2095 res = cmp(self.getStartDate(), toCmp.getStartDate())
2096 if res != 0:
2097 return res
2098 else:
2099 return cmp(self, toCmp)
2101 def __cmp__(self, toCmp):
2102 if isinstance(toCmp, Conference):
2103 return cmp(self.getId(), toCmp.getId())
2104 else:
2105 return cmp(hash(self), hash(toCmp))
2107 def __eq__(self, toCmp):
2108 return self is toCmp
2110 def __ne__(self, toCmp):
2111 return not(self is toCmp)
2113 def setUrlTag(self, tag):
2114 self._sortUrlTag = tag
2116 def getUrlTag(self):
2117 try:
2118 return self._sortUrlTag
2119 except:
2120 self._sortUrlTag = ""
2121 return self._sortUrlTag
2123 def setComments(self,comm=""):
2124 self._comments = comm.strip()
2126 def getComments(self):
2127 try:
2128 if self._comments:
2129 pass
2130 except AttributeError,e:
2131 self.setComments()
2132 return self._comments
2134 def getConfPaperReview(self):
2135 if not hasattr(self, "_confPaperReview"):
2136 self._confPaperReview = ConferencePaperReview(self)
2137 return self._confPaperReview
2139 def getConfAbstractReview(self):
2140 if not hasattr(self, "_confAbstractReview"):
2141 self._confAbstractReview = ConferenceAbstractReview(self)
2142 return self._confAbstractReview
2144 def getOrgText( self ):
2145 try:
2146 return self._orgText
2147 except:
2148 self.setOrgText()
2149 return ""
2151 def setOrgText( self, org="" ):
2152 self._orgText = org
2154 def cleanCache( self ):
2155 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
2156 if minfo.isCacheActive():
2157 cache = EventCache({"id":self.getId(), "type": "normal"})
2158 cache.cleanCache()
2159 cache = EventCache({"id":self.getId(), "type": "manager"})
2160 cache.cleanCache()
2161 cache = EventCache({"id":self.getId(), "type": "static"})
2162 cache.cleanCache()
2164 def cleanCategoryCache( self ):
2165 if len(self.getOwnerList()) > 0:
2166 self.getOwnerList()[0].cleanCache()
2168 def isFullyPublic( self ):
2169 """ determines whether an event (or any part of it) is private or not"""
2170 if hasattr(self, "_fullyPublic"):
2171 return self._fullyPublic
2172 else:
2173 self.setFullyPublic()
2174 return self._fullyPublic
2176 def setFullyPublic( self ):
2177 """ This function calculates the self._fullyPublic attribute"""
2178 if self.isProtected():
2179 self._fullyPublic = False
2180 self._p_changed=1
2181 return
2182 for mat in self.getAllMaterialList():
2183 if not mat.isFullyPublic():
2184 self._fullyPublic = False
2185 self._p_changed=1
2186 return
2187 for cont in self.getContributionList():
2188 if not cont.isFullyPublic():
2189 self._fullyPublic = False
2190 self._p_changed=1
2191 return
2192 for ses in self.getSessionList():
2193 if not ses.isFullyPublic():
2194 self._fullyPublic = False
2195 self._p_changed=1
2196 return
2197 self._fullyPublic = True
2198 self._p_changed = 1
2200 def updateFullyPublic( self ):
2201 self.setFullyPublic()
2203 # Room booking related
2204 #self.__roomBookingGuids = []
2207 def getKeywords(self):
2208 try:
2209 return self._keywords
2210 except:
2211 self._keywords = ""
2212 return ""
2214 def setKeywords(self, keywords):
2215 self._keywords = keywords
2217 def _setCreator(self, av):
2218 self.__creator = av
2220 # Room booking related ===================================================
2222 def getRoomBookingList( self ):
2224 Returns list of bookings for this conference.
2227 resvs = []
2228 for resvGuid in self.getRoomBookingGuids():
2229 r = resvGuid.getReservation()
2230 if r == None:
2231 self.removeRoomBookingGuid( resvGuid )
2232 elif r.isValid:
2233 resvs.append( r )
2234 return resvs
2236 def getBookedRooms( self ):
2238 Returns list of rooms booked for this conference.
2239 Returns [] if room booking module is off.
2241 rooms = []
2243 for r in self.getRoomBookingList():
2244 if not r.room in rooms:
2245 rooms.append( r.room )
2246 return rooms
2248 def getRoomBookingGuids( self ):
2249 try:
2250 self.__roomBookingGuids
2251 except AttributeError:
2252 self.__roomBookingGuids = []
2253 return self.__roomBookingGuids
2255 def setRoomBookingGuids( self, guids ):
2256 self.__roomBookingGuids = guids
2258 def addRoomBookingGuid( self, guid ):
2259 self.getRoomBookingGuids().append( guid )
2260 self._p_changed = True
2262 def removeRoomBookingGuid( self, guid ):
2263 self.getRoomBookingGuids().remove( guid )
2264 self._p_changed = True
2266 def __TMP_PopulateRoomBookings( self ):
2267 # TEMPORARY GENERATION OF RESERVATIONS FOR CONFERENCE
2268 from MaKaC.rb_reservation import ReservationBase
2269 from MaKaC.rb_location import ReservationGUID, Location
2270 resvs = []
2271 resvs.append( ReservationBase.getReservations( resvID = 395887 ) )
2272 resvs.append( ReservationBase.getReservations( resvID = 381406 ) )
2273 resvs.append( ReservationBase.getReservations( resvID = 387688 ) )
2274 resvs.append( ReservationBase.getReservations( resvID = 383459 ) )
2276 resvGuids = []
2277 for resv in resvs:
2278 resvGuids.append( ReservationGUID( Location.getDefaultLocation(), resv.id ) )
2280 self.__roomBookingGuids = resvGuids
2283 # ========================================================================
2285 def getParticipation(self):
2286 try :
2287 if self._participation :
2288 pass
2289 except AttributeError :
2290 self._participation = Participation(self)
2291 return self._participation
2293 def getType( self ):
2294 import MaKaC.webinterface.webFactoryRegistry as webFactoryRegistry
2295 wr = webFactoryRegistry.WebFactoryRegistry()
2296 wf = wr.getFactory(self)
2297 if wf != None:
2298 type = wf.getId()
2299 else:
2300 type = "conference"
2301 return type
2303 def getVerboseType( self ):
2304 # Like getType, but returns "Lecture" instead of "simple_type"
2305 type = self.getType()
2306 if type == "simple_event":
2307 type = "lecture"
2308 return type.capitalize()
2311 def getLogHandler(self):
2312 try :
2313 if self._logHandler:
2314 pass
2315 except AttributeError :
2316 self._logHandler = LogHandler()
2317 return self._logHandler
2320 def getEnableSessionSlots(self):
2321 #try :
2322 # if self._enableSessionSlots :
2323 # pass
2324 #except AttributeError :
2325 # self._enableSessionSlots = True
2326 #if self.getType() == "conference":
2327 # return True
2328 #return self._enableSessionSlots
2329 return True
2331 def getEnableSessions(self):
2332 try :
2333 if self._enableSessions :
2334 pass
2335 except AttributeError :
2336 self._enableSessions = True
2337 if self.getType() == "conference":
2338 return True
2339 return self._enableSessions
2341 def enableSessionSlots(self):
2342 self._enableSessionSlots = True
2344 def disableSessionSlots(self):
2345 self._enableSessionSlots = False
2347 def enableSessions(self):
2348 self._enableSessions = True
2350 def disableSessions(self):
2351 self._enableSessions = False
2353 def setValues(self, confData):
2355 Sets SOME values of the current conference object from a dictionary
2356 containing the following key-value pairs:
2357 visibility-(str)
2358 title-(str)
2359 description-(str)
2360 supportEmail-(str)
2361 contactInfo-(str)
2362 locationName-(str) => name of the location, if not specified
2363 it will be set to the conference location name.
2364 locationAddress-(str)
2365 roomName-(str) => name of the room, if not specified it will
2366 be set to the conference room name.
2367 Please, note that this method sets SOME values which means that if
2368 needed it can be completed to set more values. Also note that if
2369 the given dictionary doesn't contain all the values, the missing
2370 ones will be set to the default values.
2372 self.setVisibility(confData.get("visibility", "999"))
2373 self.setTitle(confData.get("title", _("NO TITLE ASSIGNED")))
2374 self.setDescription(confData.get("description", ""))
2375 self.setSupportEmail(confData.get("supportEmail", ""))
2376 self.setContactInfo(confData.get("contactInfo", ""))
2377 if confData.get("locationName", "").strip() == "":
2378 self.setLocation(None)
2379 else:
2380 #if the location name is defined we must set a new location (or
2381 # modify the existing one) for the conference
2382 loc = self.getLocation()
2383 if not loc:
2384 loc = CustomLocation()
2385 self.setLocation(loc)
2386 loc.setName(confData["locationName"])
2387 loc.setAddress(confData.get("locationAddress", ""))
2388 #same as for the location
2389 if confData.get("roomName", "").strip() == "":
2390 self.setRoom(None)
2391 else:
2392 room = self.getRoom()
2393 if not room:
2394 room = CustomRoom()
2395 self.setRoom(room)
2396 room.setName(confData["roomName"])
2397 self.notifyModification()
2399 def getVisibility ( self ):
2400 try:
2401 return int(self._visibility)
2402 except:
2403 self._visibility = 999
2404 return 999
2406 def getFullVisibility( self ):
2407 return max(0,min(self.getVisibility(), self.getOwnerList()[0].getVisibility()))
2409 def setVisibility( self, visibility=999 ):
2410 self._visibility = int(visibility)
2411 catIdx = indexes.IndexesHolder().getIndex('category')
2412 catIdx.reindexConf(self)
2413 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2414 catDateIdx.reindexConf(self)
2416 def isClosed( self ):
2417 try:
2418 return self._closed
2419 except:
2420 self._closed = False
2421 return False
2423 def setClosed( self, closed=True ):
2424 self._closed = closed
2426 def indexConf( self ):
2427 # called when event dates change
2428 # see also Category.indexConf()
2430 calIdx = indexes.IndexesHolder().getIndex('calendar')
2431 calIdx.indexConf(self)
2432 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2433 catDateIdx.indexConf(self)
2435 Catalog.getIdx('categ_conf_sd').index_obj(self)
2437 def unindexConf( self ):
2438 calIdx = indexes.IndexesHolder().getIndex('calendar')
2439 calIdx.unindexConf(self)
2440 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2441 catDateIdx.unindexConf(self)
2443 Catalog.getIdx('categ_conf_sd').unindex_obj(self)
2445 def __generateNewContribTypeId( self ):
2446 """Returns a new unique identifier for the current conference sessions
2448 try:
2449 return str(self.___contribTypeGenerator.newCount())
2450 except:
2451 self.___contribTypeGenerator = Counter()
2452 return str(self.___contribTypeGenerator.newCount())
2454 def addContribType(self, ct):
2455 try:
2456 if self._contribTypes:
2457 pass
2458 except:
2459 self._contribTypes = {}
2460 if ct in self._contribTypes.values():
2461 return
2462 id = ct.getId()
2463 if id == "":
2464 id = self.__generateNewContribTypeId()
2465 ct.setId(id)
2466 self._contribTypes[id] = ct
2467 self.notifyModification()
2469 def newContribType(self, name, description):
2470 ct = ContributionType(name, description, self)
2471 self.addContribType(ct)
2472 return ct
2474 def getContribTypeList(self):
2475 try:
2476 return self._contribTypes.values()
2477 except:
2478 self._contribTypes = {}
2479 self.notifyModification()
2480 return self._contribTypes.values()
2482 def getContribTypeById(self, id):
2483 try:
2484 if self._contribTypes:
2485 pass
2486 except:
2487 self._contribTypes = {}
2488 self.notifyModification()
2489 if id in self._contribTypes.keys():
2490 return self._contribTypes[id]
2491 return None
2493 def removeContribType(self, ct):
2494 try:
2495 if self._contribTypes:
2496 pass
2497 except:
2498 self._contribTypes = {}
2499 if not ct in self._contribTypes.values():
2500 return
2501 del self._contribTypes[ct.getId()]
2502 for cont in self.getContributionList():
2503 if cont.getType() == ct:
2504 cont.setType(None)
2505 ct.delete()
2506 self.notifyModification()
2508 def recoverContribType(self, ct):
2509 ct.setConference(self)
2510 self.addContribType(ct)
2511 ct.recover()
2513 def _getRepository( self ):
2514 dbRoot = DBMgr.getInstance().getDBConnection().root()
2515 try:
2516 fr = dbRoot["local_repositories"]["main"]
2517 except KeyError, e:
2518 fr = fileRepository.MaterialLocalRepository()
2519 dbRoot["local_repositories"] = OOBTree()
2520 dbRoot["local_repositories"]["main"] = fr
2521 return fr
2523 def removeResource( self, res ):
2524 pass
2526 def setLogo( self, logoFile ):
2527 logoFile.setOwner( self )
2528 logoFile.setId( "logo" )
2529 logoFile.archive( self._getRepository() )
2530 if self._logo != None:
2531 self._logo.delete()
2532 self._logo = logoFile
2533 self.notifyModification()
2535 def getLogo( self ):
2536 return self._logo
2538 def getLogoURL( self ):
2539 try:
2540 if self._logo == None:
2541 return ""
2542 return self._logo.getURL()
2543 except AttributeError:
2544 self._logo = None
2545 return ""
2547 def removeLogo(self):
2548 if self._logo is None:
2549 return
2550 self._logo.delete()
2551 self._logo = None
2552 self.notifyModification()
2554 def recoverLogo(self, logo):
2555 logo.setOwner(self)
2556 if self._logo != None:
2557 self._logo.delete()
2558 self._logo = logo
2559 logo.recover()
2560 self.notifyModification()
2562 def getSession(self):
2563 return None
2565 def getContribution(self):
2566 return None
2568 def getSubContribution(self):
2569 return None
2571 def getAbstractMgr(self):
2572 return self.abstractMgr
2574 def notifyModification( self, date = None, raiseEvent = True):
2575 """Method called to notify the current conference has been modified.
2577 self.setModificationDate()
2579 if raiseEvent:
2580 self._notify('infoChanged')
2582 self.cleanCache()
2583 self._p_changed=1
2585 def getModificationDate( self ):
2586 """Returns the date in which the conference was last modified"""
2587 return self._modificationDS
2589 def getAdjustedModificationDate( self, tz ):
2590 """Returns the date in which the conference was last modified"""
2591 return self._modificationDS.astimezone(timezone(tz))
2593 def getCreationDate( self ):
2594 """Returns the date in which the conference was created"""
2595 return self._creationDS
2597 def getAdjustedCreationDate( self, tz ):
2598 """Returns the date in which the conference was created"""
2599 return self._creationDS.astimezone(timezone(tz))
2601 def getCreator( self ):
2602 return self.__creator
2604 def setCreator( self, creator):
2605 if self.__creator:
2606 self.__creator.unlinkTo(self, "creator")
2607 creator.linkTo(self, "creator")
2608 self.__creator = creator
2610 def getId( self ):
2611 """returns (string) the unique identifier of the conference"""
2612 return self.id
2614 def getUniqueId( self ):
2615 """returns (string) the unique identiffier of the item"""
2616 """used mainly in the web session access key table"""
2617 return "a%s" % self.id
2619 def setId(self, newId):
2620 """changes the current unique identifier of the conference to the
2621 one which is specified"""
2622 self.id = str(newId)
2624 def getLocator( self ):
2625 """Gives back (Locator) a globaly unique identification encapsulated in
2626 a Locator object for the conference instance """
2627 d = Locator()
2628 d["confId"] = self.getId()
2629 return d
2631 def getOwner( self ):
2632 if self.getOwnerList() == []:
2633 return None
2634 return self.getOwnerList()[0]
2636 def getOwnerList( self ):
2637 return self.__owners
2639 def getOwnerPath( self ):
2640 l=[]
2641 owner = self.getOwnerList()[0]
2642 while owner != None and owner.getId() != "0":
2643 l.append(owner)
2644 owner = owner.getOwner()
2645 return l
2647 def getOwnerById( self, key ):
2648 """Returns one specific category which contains the conference.
2649 Params:
2650 - key: The "id" of the category.
2652 for owner in self.__owners:
2653 if key == owner.getId():
2654 return owner
2655 return None
2657 def addOwner( self, newOwner ):
2658 if newOwner == None:
2659 return
2660 self.__owners.append( newOwner )
2661 self.notifyModification()
2663 def removeOwner( self, owner, notify=True ):
2664 if not (owner in self.__owners):
2665 return
2666 self.__owners.remove( owner )
2667 owner.removeConference( self )
2668 if notify:
2669 self.notifyModification()
2671 def getCategoriesPath(self):
2672 return [self.getOwnerList()[0].getCategoryPath()]
2674 def notifyContributions(self):
2676 for c in self.getContributionList():
2677 # take care of subcontributions
2678 for sc in c.getSubContributionList():
2679 sc._notify('deleted', c)
2681 c._notify('deleted', self)
2683 def delete( self ):
2684 """deletes the conference from the system.
2686 #we notify the observers that the conference has been deleted
2687 try:
2688 self._notify('deleted', self.getOwner())
2689 except Exception, e:
2690 try:
2691 Logger.get('Conference').error("Exception while notifying the observer of a conference deletion for conference %s: %s" %
2692 (self.getId(), str(e)))
2693 except Exception, e2:
2694 Logger.get('Conference').error("Exception while notifying a conference deletion: %s (origin: %s)" % (str(e2), str(e)))
2696 self.notifyContributions()
2698 #will have to remove it from all the owners (categories) and the
2699 # conference registry
2700 ConferenceHolder().remove( self )
2701 for owner in self.__owners:
2702 owner.removeConference( self, notify=False )
2704 for alarm in self.getAlarmList():
2705 if not alarm.getEndedOn():
2706 self.removeAlarm(alarm)
2708 self.removeAllEvaluations()
2710 #For each conference we have a list of managers. If we delete the conference but we don't delete
2711 #the link in every manager to the conference then, when the manager goes to his "My profile" he
2712 #will see a link to a conference that doesn't exist. Therefore, we need to delete that link as well
2713 for manager in self.getManagerList():
2714 if isinstance(manager, MaKaC.user.Avatar):
2715 manager.unlinkTo(self, "manager")
2717 # Remote short URL mappings
2718 sum = ShortURLMapper()
2719 sum.remove(self)
2721 TrashCanManager().add(self)
2723 def getConference( self ):
2724 return self
2726 def getObservers(self):
2727 if not hasattr(self, "_observers"):
2728 self._observers = []
2729 return self._observers
2731 def setDates( self, sDate, eDate=None, check=1, moveEntries=0):
2733 Set the start/end date for a conference
2736 oldStartDate = self.getStartDate()
2737 oldEndDate = self.getEndDate()
2739 # do some checks first
2740 if sDate > eDate:
2741 # obvious case
2742 raise MaKaCError( _("Start date cannot be after the end date"), _("Event"))
2744 elif sDate == oldStartDate and eDate == oldEndDate:
2745 # if there's nothing to do (yet another obvious case)
2746 return
2748 # if we reached this point, it means either the start or
2749 # the end date (or both) changed
2750 # If only the end date was changed, moveEntries = 0
2751 if sDate == oldStartDate:
2752 moveEntries = 0
2754 # Pre-check for moveEntries
2755 if moveEntries == 1:
2756 # in case the entries are to be simply shifted
2757 # we should make sure the interval is big enough
2758 # just store the old values for later
2760 oldInterval = oldEndDate - oldStartDate
2761 newInterval = eDate - sDate
2763 if oldInterval > newInterval:
2764 raise TimingError(
2765 _("The start/end dates were not changed since the selected "
2766 "timespan is not large enough to accomodate the contained "
2767 "timetable entries and spacings."),
2768 explanation =
2769 _("You should try using a larger timespan."))
2771 # so, we really need to try changing something
2773 self.unindexConf()
2775 # set the dates
2776 self.setStartDate(sDate, check=0, moveEntries = moveEntries, index=False, notifyObservers = False)
2777 self.setEndDate(eDate, check=0, index=False, notifyObservers = False)
2779 # sanity check
2780 self._checkInnerSchedule()
2782 # reindex the conference
2783 self.indexConf()
2785 # clear the category cache
2786 self.cleanCategoryCache()
2788 # notify observers
2789 try:
2790 self._notify('dateChanged', {'oldStartDate': oldStartDate, 'newStartDate': self.getStartDate(), 'oldEndDate': oldEndDate, 'newEndDate': self.getEndDate()})
2791 except Exception, e:
2792 try:
2793 Logger.get('Conference').error("Exception while notifying the observer of a start and end date change from %s - %s to %s - %s for conference %s: %s" %
2794 (formatDateTime(oldStartDate), formatDateTime(oldEndDate),
2795 formatDateTime(self.getStartDate()), formatDateTime(self.getEndDate()), self.getId(), str(e)))
2796 except Exception, e2:
2797 Logger.get('Conference').error("Exception while notifying a start and end date change: %s (origin: %s)" % (str(e2), str(e)))
2800 def _checkInnerSchedule( self ):
2801 self.getSchedule().checkSanity()
2803 def setStartDate(self, sDate, check = 1, moveEntries = 0, index = True, notifyObservers = True):
2804 """ Changes the current conference starting date/time to the one specified by the parameters.
2806 if not sDate.tzname():
2807 raise MaKaCError("date should be timezone aware")
2808 if sDate == self.getStartDate():
2809 return
2810 ###################################
2811 # Fermi timezone awareness #
2812 ###################################
2813 if sDate.year < 1900:
2814 sDate = timezone('UTC').localize(1900,sDate.month, \
2815 sDate.day,sDate.hour,sDate.minute)
2816 ###################################
2817 # Fermi timezone awareness #
2818 ###################################
2819 if check != 0:
2820 self.verifyStartDate(sDate)
2821 oldSdate = self.getStartDate()
2822 diff = sDate - oldSdate
2824 if index:
2825 self.unindexConf()
2826 self.startDate = sDate
2827 if moveEntries and diff is not None:
2828 # If the start date changed, we move entries inside the timetable
2829 self.getSchedule()._startDate=None
2830 self.getSchedule()._endDate=None
2831 #if oldSdate.date() != sDate.date():
2832 # entries = self.getSchedule().getEntries()[:]
2833 #else:
2834 # entries = self.getSchedule().getEntriesOnDay(sDate.astimezone(timezone(self.getTimezone())))[:]
2835 entries = self.getSchedule().getEntries()[:]
2836 self.getSchedule().moveEntriesBelow(diff, entries)
2837 #datetime object is non-mutable so we must "force" the modification
2838 # otherwise ZODB won't be able to notice the change
2839 self.notifyModification()
2840 if index:
2841 self.indexConf()
2843 # update the time for the alarms to be sent
2844 self._updateAlarms()
2846 #if everything went well, we notify the observers that the start date has changed
2847 if notifyObservers:
2848 try:
2849 self._notify('startDateChanged', {'newDate': sDate, 'oldDate': oldSdate})
2850 except Exception, e:
2851 try:
2852 Logger.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s" %
2853 (formatDateTime(oldSdate), formatDateTime(sDate), self.getId(), str(e)))
2854 except Exception, e2:
2855 Logger.get('Conference').error("Exception while notifying a start date change: %s (origin: %s)" % (str(e2), str(e)))
2858 def _updateAlarms(self):
2859 c = Client()
2860 # are there any alarms? if so, update the relative ones
2861 for alarm in self.getAlarmList():
2862 tbef = alarm.getTimeBefore()
2863 if tbef:
2864 # only relative alarms
2865 c.moveTask(alarm, self.getStartDate() - tbef)
2867 def verifyStartDate(self, sdate, check=1):
2868 if sdate>self.getEndDate():
2869 raise MaKaCError( _("End date cannot be before the Start date"), _("Event"))
2871 def setStartTime(self, hours=0, minutes=0, notifyObservers = True):
2872 """ Changes the current conference starting time (not date) to the one specified by the parameters.
2875 sdate = self.getStartDate()
2876 self.startDate = datetime( sdate.year, sdate.month, sdate.day,
2877 int(hours), int(minutes) )
2878 self.verifyStartDate(self.startDate)
2879 self.notifyModification()
2881 #if everything went well, we notify the observers that the start date has changed
2882 if notifyObservers:
2883 try:
2884 self._notify('startTimeChanged', sdate)
2885 #for observer in self.getObservers():
2886 #observer.notifyEventDateChanges(sdate, self.startDate, None, None)
2887 except Exception, e:
2888 try:
2889 Logger.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s"%
2890 (formatDateTime(sdate), formatDateTime(self.startDate), self.getId(), str(e)))
2891 except Exception, e2:
2892 Logger.get('Conference').error("Exception while notifying a start time change: %s (origin: %s)"%(str(e2), str(e)))
2894 def getStartDate(self):
2895 """returns (datetime) the starting date of the conference"""
2896 return self.startDate
2898 ###################################
2899 # Fermi timezone awareness #
2900 ###################################
2902 def getAdjustedStartDate(self,tz=None):
2903 if not tz:
2904 tz = self.getTimezone()
2905 if tz not in all_timezones:
2906 tz = 'UTC'
2907 return self.getStartDate().astimezone(timezone(tz))
2909 ###################################
2910 # Fermi timezone awareness(end) #
2911 ###################################
2913 def setScreenStartDate(self, date):
2914 if date == self.getStartDate():
2915 date = None
2916 self._screenStartDate = date
2917 self.notifyModification()
2919 def getScreenStartDate(self):
2920 try:
2921 date = self._screenStartDate
2922 except:
2923 date = self._screenStartDate = None
2924 if date != None:
2925 return date
2926 else:
2927 return self.getStartDate()
2929 def getAdjustedScreenStartDate(self, tz=None):
2930 if not tz:
2931 tz = self.getTimezone()
2932 return self.getScreenStartDate().astimezone(timezone(tz))
2934 def calculateDayStartTime(self, day):
2935 """returns (date) the start date of the conference on a given day
2936 day is a tz aware datetime"""
2937 if self.getStartDate().astimezone(day.tzinfo).date() == day.date():
2938 return self.getStartDate().astimezone(day.tzinfo)
2939 return self.getSchedule().calculateDayStartDate(day)
2941 def verifyEndDate(self, edate):
2942 if edate<self.getStartDate():
2943 raise TimingError( _("End date cannot be before the start date"), _("Event"))
2944 if self.getSchedule().hasEntriesAfter(edate):
2945 raise TimingError(_("Cannot change end date to %s: some entries in the timetable would be outside this date (%s)") % (edate,self.getSchedule().getEntries()[-1].getStartDate()), _("Event"))
2947 def setEndDate(self, eDate, check = 1, index = True, notifyObservers = True):
2948 """ Changes the current conference end date/time to the one specified by the parameters.
2950 if not eDate.tzname():
2951 raise MaKaCError("date should be timezone aware")
2952 if eDate == self.getEndDate():
2953 return
2954 if eDate.year < 1900:
2955 eDate = datetime(1900,eDate.month,eDate.day,eDate.hour,eDate.minute)
2956 if check != 0:
2957 self.verifyEndDate(eDate)
2958 if index:
2959 self.unindexConf()
2961 oldEdate = self.endDate
2962 self.endDate = eDate
2963 #datetime object is non-mutable so we must "force" the modification
2964 # otherwise ZODB won't be able to notice the change
2965 self.notifyModification()
2966 if index:
2967 self.indexConf()
2969 #if everything went well, we notify the observers that the start date has changed
2970 if notifyObservers:
2971 try:
2972 self._notify('endDateChanged', {'newDate': eDate, 'oldDate': oldEdate})
2973 except Exception, e:
2974 try:
2975 Logger.get('Conference').error("Exception while notifying the observer of a end date change from %s to %s for conference %s: " %
2976 (formatDateTime(oldEdate), formatDateTime(eDate), self.getId(), str(e)))
2977 except Exception, e2:
2978 Logger.get('Conference').error("Exception while notifying a end date change: %s (origin: %s)" % (str(e2), str(e)))
2981 def setEndTime(self, hours = 0, minutes = 0, notifyObservers = True):
2982 """ Changes the current conference end time (not date) to the one specified by the parameters.
2984 edate = self.getEndDate()
2985 self.endDate = datetime( edate.year, edate.month, edate.day, int(hours), int(minutes) )
2986 self.verifyEndDate(self.endDate)
2987 self.notifyModification()
2989 #if everything went well, we notify the observers that the start date has changed
2990 if notifyObservers:
2991 try:
2992 self._notify('endTimeChanged', edate)
2993 #for observer in self.getObservers():
2994 except Exception, e:
2995 #observer.notifyEventDateChanges(None, None, edate, self.endDate)
2996 try:
2997 Logger.get('Conference').error("Exception while notifying the observer of a end timet change from %s to %s for conference %s: %s" %
2998 (formatDateTime(edate), formatDateTime(self.endDate), self.getId(), str(e)))
2999 except Exception, e2:
3000 Logger.get('Conference').error("Exception while notifying a end time change: %s (origin: %s)"%(str(e2), str(e)))
3002 def getEndDate(self):
3003 """returns (datetime) the ending date of the conference"""
3004 return self.endDate
3006 ##################################
3007 # Fermi timezone awareness #
3008 ##################################
3010 def getAdjustedEndDate(self,tz=None):
3011 if not tz:
3012 tz = self.getTimezone()
3013 if tz not in all_timezones:
3014 tz = 'UTC'
3015 return self.getEndDate().astimezone(timezone(tz))
3017 ##################################
3018 # Fermi timezone awareness(end) #
3019 ##################################
3021 def setScreenEndDate(self, date):
3022 if date == self.getEndDate():
3023 date = None
3024 self._screenEndDate = date
3025 self.notifyModification()
3027 def getScreenEndDate(self):
3028 try:
3029 date = self._screenEndDate
3030 except:
3031 date = self._screenEndDate = None
3032 if date != None:
3033 return date
3034 else:
3035 return self.getEndDate()
3037 def getAdjustedScreenEndDate(self, tz=None):
3038 if not tz:
3039 tz = self.getTimezone()
3040 return self.getScreenEndDate().astimezone(timezone(tz))
3042 def isEndDateAutoCal( self ):
3043 """Says whether the end date has been explicitely set for the session
3044 or it must be calculated automatically
3046 return self._endDateAutoCal
3048 ####################################
3049 # Fermi timezone awareness #
3050 ####################################
3051 def setTimezone(self, tz):
3052 try:
3053 oldTimezone = self.timezone
3054 except AttributeError:
3055 oldTimezone = tz
3056 self.timezone = tz
3057 #for observer in self.getObservers():
3058 try:
3059 #observer.notifyTimezoneChange(oldTimezone, tz)
3060 self._notify('timezoneChanged', oldTimezone)
3061 except Exception, e:
3062 try:
3063 Logger.get('Conference').error("Exception while notifying the observer of a timezone change from %s to %s for conference %s: %s" %
3064 (str(oldTimezone), str(tz), self.getId(), str(e)))
3065 except Exception, e2:
3066 Logger.get('Conference').error("Exception while notifying a timezone change: %s (origin: %s)"%(str(e2), str(e)))
3068 def getTimezone(self):
3069 try:
3070 return self.timezone
3071 except:
3072 return 'UTC'
3074 def moveToTimezone(self, tz):
3075 if self.getTimezone() == tz:
3076 return
3077 sd=self.getAdjustedStartDate()
3078 ed=self.getAdjustedEndDate()
3079 self.setTimezone(tz)
3080 try:
3081 sDate = timezone(tz).localize(datetime(sd.year, \
3082 sd.month, \
3083 sd.day, \
3084 sd.hour, \
3085 sd.minute))
3086 eDate = timezone(tz).localize(datetime(ed.year, \
3087 ed.month, \
3088 ed.day, \
3089 ed.hour, \
3090 ed.minute))
3091 except ValueError,e:
3092 raise MaKaCError("Error moving the timezone: %s"%e)
3093 self.setDates( sDate.astimezone(timezone('UTC')), \
3094 eDate.astimezone(timezone('UTC')),
3095 moveEntries=1)
3099 ####################################
3100 # Fermi timezone awareness(end) #
3101 ####################################
3103 def getTitle(self):
3104 """returns (String) the title of the conference"""
3105 return self.title
3107 def setTitle(self, title):
3108 """changes the current title of the conference to the one specified"""
3109 oldTitle = self.title
3111 self.title = title
3112 self.cleanCategoryCache()
3113 self.notifyModification()
3115 #we notify the observers that the conference's title has changed
3116 try:
3117 self._notify('eventTitleChanged', oldTitle, title)
3118 except Exception, e:
3119 Logger.get('Conference').exception("Exception while notifying the observer of a conference title change for conference %s: %s" %
3120 (self.getId(), str(e)))
3123 def getDescription(self):
3124 """returns (String) the description of the conference"""
3125 return self.description
3127 def setDescription(self, desc):
3128 """changes the current description of the conference"""
3129 self.description = desc
3130 self.notifyModification()
3132 def getSupportEmail( self, returnNoReply=False, caption=False ):
3134 Returns the support email address associated with the conference
3135 :param returnNoReply: Return no-reply address in case there's no support e-mail (default True)
3136 :type returnNoReply: bool
3139 try:
3140 if self._supportEmail:
3141 pass
3142 except AttributeError, e:
3143 self._supportEmail = ""
3144 if self._supportEmail.strip() == "" and returnNoReply:
3145 # In case there's no conference support e-mail, return the no-reply
3146 # address, and the 'global' support e-mail if there isn't one
3147 return HelperMaKaCInfo.getMaKaCInfoInstance().getNoReplyEmail(returnSupport=True)
3148 else:
3149 supportCaption = self.getDisplayMgr().getSupportEmailCaption()
3151 if caption and supportCaption:
3152 return '"%s" <%s>' % (supportCaption, self._supportEmail)
3153 else:
3154 return self._supportEmail
3156 def setSupportEmail( self, newSupportEmail ):
3157 self._supportEmail = newSupportEmail.strip()
3159 def hasSupportEmail( self ):
3160 try:
3161 if self._supportEmail:
3162 pass
3163 except AttributeError, e:
3164 self._supportEmail = ""
3165 return self._supportEmail != "" and self._supportEmail != None
3167 def getChairmanText( self ):
3168 try:
3169 if self.chairmanText:
3170 pass
3171 except AttributeError, e:
3172 self.chairmanText = ""
3173 return self.chairmanText
3175 def setChairmanText( self, newText ):
3176 self.chairmanText = newText.strip()
3178 def appendChairmanText( self, newText ):
3179 self.setChairmanText( "%s, %s"%(self.getChairmanText(), newText.strip()) )
3180 self._chairGen=Counter()
3181 self._chairs=[]
3183 def _resetChairs(self):
3184 try:
3185 if self._chairs:
3186 return
3187 except AttributeError:
3188 self._chairs=[]
3189 for oc in self.chairmans:
3190 newChair=ConferenceChair()
3191 newChair.setDataFromAvatar(oc)
3192 self._addChair(newChair)
3194 def getChairList(self):
3195 """Method returning a list of the conference chairmans (Avatars)
3197 self._resetChairs()
3198 return self._chairs
3200 def _addChair(self,newChair):
3201 if newChair in self._chairs:
3202 return
3203 try:
3204 if self._chairGen:
3205 pass
3206 except AttributeError:
3207 self._chairGen=Counter()
3208 id = newChair.getId()
3209 if id == "":
3210 id=int(self._chairGen.newCount())
3211 if isinstance(newChair,ConferenceChair):
3212 newChair.includeInConference(self,id)
3213 self._chairs.append(newChair)
3214 if isinstance(newChair, MaKaC.user.Avatar):
3215 newChair.linkTo(self, "chair")
3216 self.notifyModification()
3218 def addChair(self,newChair):
3219 """includes the specified user in the list of conference
3220 chairs"""
3221 self._resetChairs()
3222 self._addChair(newChair)
3224 def removeChair(self,chair):
3225 """removes the specified user from the list of conference
3226 chairs"""
3227 self._resetChairs()
3228 if chair not in self._chairs:
3229 return
3230 self._chairs.remove(chair)
3231 if isinstance(chair, MaKaC.user.Avatar):
3232 chair.unlinkTo(self, "chair")
3233 chair.delete()
3234 self.notifyModification()
3236 def recoverChair(self, ch):
3237 self.addChair(ch)
3238 ch.recover()
3240 def getChairById(self,id):
3241 id=int(id)
3242 for chair in self._chairs:
3243 if chair.getId()==id:
3244 return chair
3245 return None
3247 def getAllSessionsConvenerList(self) :
3248 dictionary = {}
3249 for session in self.getSessionList() :
3250 for convener in session.getConvenerList() :
3251 key = convener.getEmail()+" "+convener.getFirstName().lower()+" "+convener.getFamilyName().lower()
3252 dictionary.setdefault(key, set()).add(convener)
3253 for slot in session.getSlotList():
3254 for convener in slot.getConvenerList() :
3255 key = convener.getEmail()+" "+convener.getFirstName().lower()+" "+convener.getFamilyName().lower()
3256 dictionary.setdefault(key, set()).add(convener)
3258 return dictionary
3260 def getContactInfo(self):
3261 return self.contactInfo
3263 def setContactInfo(self, contactInfo):
3264 self.contactInfo = contactInfo
3265 self.notifyModification()
3267 def getLocationParent( self ):
3269 Returns the object from which the room/location
3270 information should be inherited.
3271 For Conferences, it's None, since they can't inherit
3272 from anywhere else.
3274 return None
3276 def getLocation( self ):
3277 return self.getOwnLocation()
3279 def getRoom( self ):
3280 return self.getOwnRoom()
3282 def getLocationList(self):
3283 """Method returning a list of "location" objects which contain the
3284 information about the different places the conference is gonna
3285 happen
3287 return self.places
3289 def getFavoriteRooms(self):
3290 roomList = []
3291 roomList.extend(self.getRoomList())
3292 #roomList.extend(map(lambda x: x._getName(), self.getBookedRooms()))
3294 return roomList
3296 def addLocation(self, newPlace):
3297 self.places.append( newPlace )
3298 self.notifyModification()
3300 def setAccessKey(self, accessKey=""):
3301 """sets the access key of the conference"""
3302 self._accessKey = accessKey
3303 self.notifyModification()
3305 def getAccessKey(self):
3306 try:
3307 return self._accessKey
3308 except AttributeError:
3309 self._accessKey = ""
3310 return self._accessKey
3312 def setModifKey(self, modifKey=""):
3313 """sets the modification key of the conference"""
3314 self._modifKey = modifKey
3315 self.notifyModification()
3317 def getModifKey(self):
3318 try:
3319 return self._modifKey
3320 except AttributeError:
3321 self._modifKey = ""
3322 return self._modifKey
3324 def __generateNewSessionId( self ):
3325 """Returns a new unique identifier for the current conference sessions
3327 return str(self.__sessionGenerator.newCount())
3329 def addSession(self,newSession, check = 2, id = None):
3330 """Adds a new session object to the conference taking care of assigning
3331 a new unique id to it
3333 """check parameter:
3334 0: no check at all
3335 1: check and raise error in case of problem
3336 2: check and adapt the owner dates"""
3338 if self.hasSession(newSession):
3339 return
3340 if self.getSchedule().isOutside(newSession):
3341 if check == 1:
3342 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")
3343 elif check == 2:
3344 if self.getSchedule().getStartDate() > newSession.getStartDate():
3345 self.setStartDate(newSession.getStartDate())
3346 if self.getSchedule().getEndDate() < newSession.getEndDate():
3347 self.setEndDate(newSession.getEndDate())
3348 if id!=None:
3349 sessionId = id
3350 else:
3351 sessionId=self.__generateNewSessionId()
3352 self.sessions[sessionId]=newSession
3353 newSession.includeInConference(self,sessionId)
3354 #keep the session coordinator index updated
3355 for sc in newSession.getCoordinatorList():
3356 self.addSessionCoordinator(newSession,sc)
3357 self.notifyModification()
3359 def hasSession(self,session):
3360 if session != None and session.getConference()==self and \
3361 self.sessions.has_key(session.getId()):
3362 return True
3363 return False
3365 def removeSession(self,session, deleteContributions=False):
3366 if self.hasSession(session):
3367 for sc in session.getCoordinatorList():
3368 self.removeSessionCoordinator(session,sc)
3370 if deleteContributions:
3371 for contrib in session.getContributionList():
3372 contrib.delete()
3374 del self.sessions[session.getId()]
3376 session.delete()
3377 self.notifyModification()
3379 def recoverSession(self, session, check, isCancelled):
3380 self.addSession(session, check, session.getId())
3381 session.recover(isCancelled)
3383 def getSessionById( self, sessionId ):
3384 """Returns the session from the conference list corresponding to the
3385 unique session id specified
3387 return self.sessions.get(sessionId,None)
3389 def getRoomList(self):
3390 roomList =[]
3391 for session in self.sessions.values():
3392 if session.getRoom()!=None:
3393 roomname = session.getRoom().getName()
3394 if roomname not in roomList:
3395 roomList.append(roomname)
3396 return roomList
3398 def getSessionList( self ):
3399 """Retruns a list of the conference session objects
3401 return self.sessions.values()
3403 def getSessionListSorted( self ):
3404 """Retruns a sorted list of the conference sessions
3406 res=[]
3407 for entry in self.getSchedule().getEntries():
3408 if isinstance(entry,LinkedTimeSchEntry) and \
3409 isinstance(entry.getOwner(),SessionSlot):
3410 session=entry.getOwner().getSession()
3411 if session not in res:
3412 res.append(session)
3413 return res
3415 def getNumberOfSessions( self ):
3416 return len(self.sessions)
3418 def _generateNewContributionId( self ):
3419 """Returns a new unique identifier for the current conference
3420 contributions
3422 return str(self.__contribGenerator.newCount())
3424 def genNewAbstractId(self):
3425 return str(self.__contribGenerator.newCount())
3427 def syncContribCounter(self):
3428 self.__contribGenerator.sync(self.getAbstractMgr()._getOldAbstractCounter())
3429 return self.__contribGenerator._getCount()
3431 def addContribution(self,newContrib,id=""):
3432 """Adds a new contribution object to the conference taking care of
3433 assigning a new unique id to it
3435 if self.hasContribution(newContrib):
3436 return
3437 if isinstance(newContrib.getCurrentStatus(),ContribStatusWithdrawn):
3438 raise MaKaCError( _("Cannot add a contribution which has been withdrawn"), _("Event"))
3439 if id is None or id=="":
3440 contribId=self._generateNewContributionId()
3441 while self.contributions.has_key(contribId):
3442 contribId=self._generateNewContributionId()
3443 else:
3444 contribId=str(id)
3445 if self.contributions.has_key(contribId):
3446 raise MaKaCError( _("Cannot add this contribution id:(%s) as it has already been used")%contribId, _("Event"))
3447 newContrib.includeInConference(self,contribId)
3448 self.contributions[contribId]=newContrib
3449 for auth in newContrib.getAuthorList():
3450 self.indexAuthor(auth)
3451 for spk in newContrib.getSpeakerList():
3452 self.indexSpeaker(spk)
3453 for sub in newContrib.getSubmitterList():
3454 self.addContribSubmitter(newContrib,sub)
3456 newContrib._notify('created', self)
3457 self.notifyModification()
3459 def hasContribution(self,contrib):
3460 return contrib.getConference()==self and \
3461 self.contributions.has_key(contrib.getId())
3463 def removeContribution( self, contrib, callDelete=True ):
3464 if not self.contributions.has_key( contrib.getId() ):
3465 return
3466 for sub in contrib.getSubmitterList():
3467 self.removeContribSubmitter(contrib,sub)
3468 for auth in contrib.getPrimaryAuthorList():
3469 contrib.removePrimaryAuthor(auth)
3470 for auth in contrib.getCoAuthorList():
3471 contrib.removeCoAuthor(auth)
3472 for spk in contrib.getSpeakerList():
3473 contrib.removeSpeaker(spk)
3474 del self.contributions[ contrib.getId() ]
3475 if callDelete:
3476 contrib.delete()
3477 #else:
3478 # contrib.unindex()
3479 self.notifyModification()
3481 def recoverContribution(self, contrib):
3482 self.addContribution(contrib, contrib.getId())
3483 contrib.recover()
3485 # Note: this kind of factories should never be used as they only allow to
3486 # create a single type of contributions
3487 def newContribution( self, id=None ):
3488 """Creates and returns a new contribution object already added to the
3489 conference list (all its data is set to the default)
3491 c = Contribution()
3492 self.addContribution( c, id )
3493 return c
3495 def getOwnContributionById( self, id ):
3496 """Returns the contribution from the conference list corresponding to
3497 the unique contribution id specified
3499 if self.contributions.has_key( id ):
3500 return self.contributions[ id ]
3501 return None
3503 def getContributionById( self, id ):
3504 """Returns the contribution corresponding to the id specified
3506 return self.contributions.get(str(id).strip(),None)
3508 def getContributionList(self):
3509 """Returns a list of the conference contribution objects
3511 return self.contributions.values()
3513 def iterContributions(self):
3514 return self.contributions.itervalues()
3516 def getContributionListWithoutSessions(self):
3517 """Returns a list of the conference contribution objects which do not have a session
3519 return [c for c in self.contributions.values() if not c.getSession()]
3521 def getContributionListSortedById(self):
3522 """Returns a list of the conference contribution objects, sorted by their id
3524 contributions = self.contributions.values()
3525 contributions.sort(key = lambda c: c.getId())
3526 return contributions
3528 def getNumberOfContributions(self):
3529 return len(self.contributions)
3531 def getProgramDescription(self):
3532 try:
3533 return self.programDescription
3534 except:
3535 self.programDescription = ""
3536 return self.programDescription
3538 def setProgramDescription(self, txt):
3539 self.programDescription = txt
3541 def _generateNewTrackId( self ):
3544 return str(self.__programGenerator.newCount())
3546 def addTrack( self, newTrack ):
3549 #XXX: The conference program shoul be isolated in a separated object
3550 if newTrack in self.program:
3551 return
3553 trackId = newTrack.getId()
3554 if trackId == "not assigned":
3555 trackId = self._generateNewTrackId()
3556 self.program.append( newTrack )
3557 newTrack.setConference( self )
3558 newTrack.setId( trackId )
3559 self.notifyModification()
3561 def removeTrack( self, track ):
3562 if track in self.program:
3563 track.delete()
3564 if track in self.program:
3565 self.program.remove( track )
3566 self.notifyModification()
3568 def recoverTrack(self, track):
3569 self.addTrack(track)
3570 track.recover()
3572 def newTrack( self ):
3575 t = Track()
3576 self.addTrack( t )
3577 return t
3579 def getTrackById( self, id ):
3582 for track in self.program:
3583 if track.getId() == id.strip():
3584 return track
3585 return None
3587 def getTrackList( self ):
3590 return self.program
3592 def isLastTrack(self,track):
3595 return self.getTrackPos(track)==(len(self.program)-1)
3597 def isFirstTrack(self,track):
3600 return self.getTrackPos(track)==0
3602 def getTrackPos(self,track):
3605 return self.program.index(track)
3607 def moveTrack(self,track,newPos):
3610 self.program.remove(track)
3611 self.program.insert(newPos,track)
3612 self.notifyModification()
3614 def moveUpTrack(self,track):
3617 if self.isFirstTrack(track):
3618 return
3619 newPos=self.getTrackPos(track)-1
3620 self.moveTrack(track,newPos)
3622 def moveDownTrack(self,track):
3625 if self.isLastTrack(track):
3626 return
3627 newPos=self.getTrackPos(track)+1
3628 self.moveTrack(track,newPos)
3630 def _cmpTracks( self, t1, t2 ):
3631 o1 = self.program.index(t1)
3632 o2 = self.program.index(t2)
3633 return cmp( o1, o2 )
3635 def sortTrackList( self, l ):
3636 """Sorts out a list of tracks according to the current programme order.
3638 if len(l) == 0:
3639 return []
3640 elif len(l) == 1:
3641 return [l[0]]
3642 else:
3643 res = []
3644 for i in l:
3645 res.append( i )
3646 res.sort( self._cmpTracks )
3647 return res
3649 def canIPAccess( self, ip ):
3650 if not self.__ac.canIPAccess( ip ):
3651 return False
3652 for owner in self.getOwnerList():
3653 if not owner.canIPAccess(ip):
3654 return False
3655 return True
3657 def requireDomain( self, dom ):
3658 self.__ac.requireDomain( dom )
3659 self._notify('accessDomainAdded', dom)
3661 def freeDomain( self, dom ):
3662 self.__ac.freeDomain( dom )
3663 self._notify('accessDomainRemoved', dom)
3665 def getDomainList( self ):
3666 return self.__ac.getRequiredDomainList()
3668 def isProtected( self ):
3669 """Tells whether a conference is protected for accessing or not
3671 return self.__ac.isProtected()
3673 def getAccessProtectionLevel( self ):
3674 return self.__ac.getAccessProtectionLevel()
3676 def isItselfProtected( self ):
3677 return self.__ac.isItselfProtected()
3679 def hasAnyProtection( self ):
3680 """Tells whether a conference has any kind of protection over it:
3681 access or domain protection.
3683 if self.isProtected():
3684 return True
3685 if self.getDomainList():
3686 return True
3688 if self.getAccessProtectionLevel() == -1:
3689 return False
3691 for owner in self.getOwnerList():
3692 if owner.hasAnyProtection():
3693 return True
3695 return False
3697 def hasProtectedOwner( self ):
3698 return self.__ac._getFatherProtection()
3700 def setProtection( self, private ):
3702 Allows to change the conference access protection
3705 oldValue = 1 if self.isProtected() else -1
3707 self.__ac.setProtection( private )
3708 self.updateFullyPublic()
3709 self.cleanCategoryCache()
3711 if oldValue != private:
3712 # notify listeners
3713 self._notify('protectionChanged', oldValue, private)
3715 def grantAccess( self, prin ):
3716 self.__ac.grantAccess( prin )
3717 if isinstance(prin, MaKaC.user.Avatar):
3718 prin.linkTo(self, "access")
3720 def revokeAccess( self, prin ):
3721 self.__ac.revokeAccess( prin )
3722 if isinstance(prin, MaKaC.user.Avatar):
3723 prin.unlinkTo(self, "access")
3725 def canView( self, aw ):
3726 """tells whether the specified access wrappers has access to the current
3727 object or any of its parts"""
3728 if self.canAccess( aw ):
3729 return True
3730 for session in self.getSessionList():
3731 if session.canView( aw ):
3732 return True
3733 for contrib in self.getContributionList():
3734 if contrib.canView( aw ):
3735 return True
3736 return False
3738 def isAllowedToAccess( self, av):
3739 """tells if a user has privileges to access the current conference
3740 (independently that it is protected or not)
3742 if not av:
3743 return False
3744 if (av in self.getChairList()) or (self.__ac.canUserAccess( av )) or (self.canUserModify( av )):
3745 return True
3747 # if the conference is not protected by itself
3748 if not self.isItselfProtected():
3749 # then inherit behavior from parent category
3750 for owner in self.getOwnerList():
3751 if owner.isAllowedToAccess( av ):
3752 return True
3754 # track coordinators are also allowed to access the conference
3755 for track in self.getTrackList():
3756 if track.isCoordinator( av ):
3757 return True
3759 # paper reviewing team should be also allowed to access
3760 if self.getConfPaperReview().isInReviewingTeam(av):
3761 return True
3763 # video services managers are also allowed to access the conference
3764 if PluginsHolder().hasPluginType("Collaboration"):
3765 if self.getCSBookingManager().isPluginManagerOfAnyPlugin(av):
3766 return True
3767 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
3768 if RCCollaborationAdmin.hasRights(user=av) or \
3769 RCCollaborationPluginAdmin.hasRights(user=av, plugins ='any'):
3770 return True
3772 return False
3774 def canAccess( self, aw ):
3775 """Tells whether an access wrapper is allowed to access the current
3776 conference: when the conference is protected, only if the user is a
3777 chair or is granted to access the conference, when the client ip is
3778 not restricted.
3780 # Allow harvesters (Invenio, offline cache) to access
3781 # protected pages
3782 if self.__ac.isHarvesterIP(aw.getIP()):
3783 return True
3785 if self.isProtected():
3786 if self.canUserModify(aw.getUser()) or self.isAllowedToAccess( aw.getUser() ):
3787 return True
3788 else:
3789 return self.canKeyAccess(aw)
3790 else:
3791 return self.canIPAccess(aw.getIP())
3793 def canKeyAccess( self, aw, key=None ):
3794 sess = aw.getSession()
3795 accessKey = self.getAccessKey()
3796 if accessKey != "" and sess:
3797 if key and key == accessKey:
3798 return True
3799 keys = sess.getVar("accessKeys")
3800 if keys != None:
3801 if keys.has_key(self.getUniqueId()):
3802 if keys[self.getUniqueId()] == accessKey:
3803 return True
3804 return False
3806 def canKeyModify( self, aw ):
3807 sess = aw.getSession()
3808 modifKey = self.getModifKey()
3809 if modifKey != "" and sess:
3810 keys = sess.getVar("modifKeys")
3811 if keys != None:
3812 if keys.has_key(self.id):
3813 if keys[self.id] == modifKey:
3814 return True
3815 return False
3817 def grantModification( self, prin, sendEmail=True ):
3818 email = None
3819 if isinstance(prin, ConferenceChair):
3820 email = prin.getEmail()
3821 elif isinstance(prin, str):
3822 email = prin
3823 if email != None:
3824 if email == "":
3825 return
3826 ah = AvatarHolder()
3827 results=ah.match({"email":email}, exact=1)
3828 #No registered user in Indico with that email
3829 if len(results) == 0:
3830 self.__ac.grantModificationEmail(email)
3831 if sendEmail and isinstance(prin, ConferenceChair):
3832 notif = pendingQueues._PendingConfManagerNotification( [prin] )
3833 mail.GenericMailer.sendAndLog( notif, self.getConference() )
3834 #The user is registered in Indico and is activated as well
3835 elif len(results) == 1 and results[0] is not None and results[0].isActivated():
3836 self.__ac.grantModification(results[0])
3837 results[0].linkTo(self, "manager")
3838 else:
3839 self.__ac.grantModification( prin )
3840 if isinstance(prin, MaKaC.user.Avatar):
3841 prin.linkTo(self, "manager")
3843 def revokeModification( self, prin ):
3844 self.__ac.revokeModification( prin )
3845 if isinstance(prin, MaKaC.user.Avatar):
3846 prin.unlinkTo(self, "manager")
3848 def canUserModify( self, av ):
3849 if av == None:
3850 return False
3851 if ( av == self.getCreator()) or self.getAccessController().canModify( av ):
3852 return True
3853 for owner in self.getOwnerList():
3854 if owner.canUserModify( av ):
3855 return True
3856 return False
3858 def canModify( self, aw ):
3859 """Tells whether an access wrapper is allowed to modify the current
3860 conference: only if the user is granted to modify the conference and
3861 he is accessing from an IP address which is not restricted.
3863 return self.canUserModify( aw.getUser() ) or self.canKeyModify( aw )
3865 def getManagerList( self ):
3866 return self.__ac.getModifierList()
3868 def addToRegistrars(self, av):
3869 self.getRegistrarList().append(av)
3870 self.notifyModification()
3871 if isinstance(av, MaKaC.user.Avatar):
3872 av.linkTo(self, "registrar")
3874 def removeFromRegistrars(self, av):
3875 self.getRegistrarList().remove(av)
3876 self.notifyModification()
3877 if isinstance(av, MaKaC.user.Avatar):
3878 av.unlinkTo(self, "registrar")
3880 def isRegistrar(self, av):
3881 if av == None:
3882 return False
3883 try:
3884 return av in self.getRegistrarList()
3885 except AttributeError:
3886 return False
3888 def getRegistrarList(self):
3889 try:
3890 return self.__registrars
3891 except AttributeError:
3892 self.__registrars = []
3893 return self.__registrars
3895 def canManageRegistration(self, av):
3896 return self.isRegistrar(av) or self.canUserModify(av)
3898 def getAllowedToAccessList( self ):
3899 return self.__ac.getAccessList()
3901 def addMaterial( self, newMat ):
3902 newMat.setId( str(self.__materialGenerator.newCount()) )
3903 newMat.setOwner( self )
3904 self.materials[ newMat.getId() ] = newMat
3905 self.notifyModification()
3907 def removeMaterial( self, mat ):
3908 if mat.getId() in self.materials.keys():
3909 mat.delete()
3910 self.materials[mat.getId()].setOwner(None)
3911 del self.materials[ mat.getId() ]
3912 self.notifyModification()
3913 elif mat.getId().lower() == 'paper':
3914 self.removePaper()
3915 self.notifyModification()
3916 elif mat.getId().lower() == 'slides':
3917 self.removeSlides()
3918 self.notifyModification()
3919 elif mat.getId().lower() == 'minutes':
3920 self.removeMinutes()
3921 self.notifyModification()
3922 elif mat.getId().lower() == 'video':
3923 self.removeVideo()
3924 self.notifyModification()
3925 elif mat.getId().lower() == 'poster':
3926 self.removePoster()
3927 self.notifyModification()
3929 def recoverMaterial(self, recMat):
3930 # Id must already be set in recMat.
3931 recMat.setOwner(self)
3932 self.materials[recMat.getId()] = recMat
3933 recMat.recover()
3934 self.notifyModification()
3936 def getMaterialRegistry(self):
3938 Return the correct material registry for this type
3940 from MaKaC.webinterface.materialFactories import ConfMFRegistry
3941 return ConfMFRegistry
3943 def getMaterialById( self, matId ):
3944 if matId.lower() == 'paper':
3945 return self.getPaper()
3946 elif matId.lower() == 'slides':
3947 return self.getSlides()
3948 elif matId.lower() == 'video':
3949 return self.getVideo()
3950 elif matId.lower() == 'poster':
3951 return self.getPoster()
3952 elif matId.lower() == 'minutes':
3953 return self.getMinutes()
3954 elif self.materials.has_key(matId):
3955 return self.materials[ matId ]
3956 return None
3958 def getMaterialList( self ):
3959 return self.materials.values()
3961 def getAllMaterialList( self ):
3962 l = self.getMaterialList()
3963 if self.getPaper():
3964 l.append( self.getPaper() )
3965 if self.getSlides():
3966 l.append( self.getSlides() )
3967 if self.getVideo():
3968 l.append( self.getVideo() )
3969 if self.getPoster():
3970 l.append( self.getPoster() )
3971 if self.getMinutes():
3972 l.append( self.getMinutes() )
3973 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
3974 return l
3976 def setPaper( self, newPaper ):
3977 if self.getPaper() != None:
3978 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
3979 self.paper=newPaper
3980 self.paper.setOwner( self )
3981 self.notifyModification()
3983 def removePaper( self ):
3984 if self.paper is None:
3985 return
3986 self.paper.delete()
3987 self.paper.setOwner(None)
3988 self.paper = None
3989 self.notifyModification()
3991 def recoverPaper(self, p):
3992 self.setPaper(p)
3993 p.recover()
3995 def getPaper( self ):
3996 try:
3997 if self.paper:
3998 pass
3999 except AttributeError:
4000 self.paper = None
4001 return self.paper
4003 def setSlides( self, newSlides ):
4004 if self.getSlides() != None:
4005 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
4006 self.slides=newSlides
4007 self.slides.setOwner( self )
4008 self.notifyModification()
4010 def removeSlides( self ):
4011 if self.slides is None:
4012 return
4013 self.slides.delete()
4014 self.slides.setOwner( None )
4015 self.slides= None
4016 self.notifyModification()
4018 def recoverSlides(self, s):
4019 self.setSlides(s)
4020 s.recover()
4022 def getSlides( self ):
4023 try:
4024 if self.slides:
4025 pass
4026 except AttributeError:
4027 self.slides = None
4028 return self.slides
4030 def setVideo( self, newVideo ):
4031 if self.getVideo() != None:
4032 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
4033 self.video=newVideo
4034 self.video.setOwner( self )
4035 self.notifyModification()
4037 def removeVideo( self ):
4038 if self.getVideo() is None:
4039 return
4040 self.video.delete()
4041 self.video.setOwner(None)
4042 self.video = None
4043 self.notifyModification()
4045 def recoverVideo(self, v):
4046 self.setVideo(v)
4047 v.recover()
4049 def getVideo( self ):
4050 try:
4051 if self.video:
4052 pass
4053 except AttributeError:
4054 self.video = None
4055 return self.video
4057 def setPoster( self, newPoster ):
4058 if self.getPoster() != None:
4059 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
4060 self.poster=newPoster
4061 self.poster.setOwner( self )
4062 self.notifyModification()
4064 def removePoster( self ):
4065 if self.getPoster() is None:
4066 return
4067 self.poster.delete()
4068 self.poster.setOwner(None)
4069 self.poster = None
4070 self.notifyModification()
4072 def recoverPoster(self, p):
4073 self.setPoster(p)
4074 p.recover()
4076 def getPoster( self ):
4077 try:
4078 if self.poster:
4079 pass
4080 except AttributeError:
4081 self.poster = None
4082 return self.poster
4084 def setMinutes( self, newMinutes ):
4085 if self.getMinutes() != None:
4086 raise MaKaCError( _("The Minutes for this conference has already been set"))
4087 self.minutes=newMinutes
4088 self.minutes.setOwner( self )
4089 self.notifyModification()
4091 def createMinutes( self ):
4092 if self.getMinutes() != None:
4093 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
4094 self.minutes = Minutes()
4095 self.minutes.setOwner( self )
4096 self.notifyModification()
4097 return self.minutes
4099 def removeMinutes( self ):
4100 if self.getMinutes() is None:
4101 return
4102 self.minutes.delete()
4103 self.minutes.setOwner( None )
4104 self.minutes = None
4105 self.notifyModification()
4107 def recoverMinutes(self, min):
4108 self.removeMinutes() # To ensure that the current minutes are put in
4109 # the trash can.
4110 self.minutes = min
4111 self.minutes.setOwner( self )
4112 min.recover()
4113 self.notifyModification()
4114 return self.minutes
4116 def getMinutes( self ):
4117 #To be removed
4118 try:
4119 if self.minutes:
4120 pass
4121 except AttributeError, e:
4122 self.minutes = None
4123 return self.minutes
4125 def _setSchedule( self, sch=None ):
4126 self.__schedule=ConferenceSchedule(self)
4127 for session in self.getSessionList():
4128 for slot in session.getSlotList():
4129 self.__schedule.addEntry(slot.getConfSchEntry())
4131 def getSchedule( self ):
4132 try:
4133 if not self.__schedule:
4134 self._setSchedule()
4135 except AttributeError, e:
4136 self._setSchedule()
4137 return self.__schedule
4139 def fit( self ):
4140 sch = self.getSchedule()
4142 sDate = sch.calculateStartDate()
4143 eDate = sch.calculateEndDate()
4144 self.setStartDate(sDate)
4145 self.setEndDate(eDate)
4147 def fitSlotsOnDay( self, day ):
4148 for entry in self.getSchedule().getEntriesOnDay(day) :
4149 if isinstance(entry.getOwner(), SessionSlot) :
4150 entry.getOwner().fit()
4152 def getDisplayMgr(self):
4154 Return the display manager for the conference
4156 from MaKaC.webinterface import displayMgr
4157 return displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self)
4159 def getDefaultStyle( self ):
4160 return self.getDisplayMgr(self).getDefaultStyle()
4162 def clone( self, startDate, options, eventManager=None, userPerformingClone = None ):
4163 # startDate must be in the timezone of the event (to avoid problems with daylight-saving times)
4164 cat = self.getOwnerList()[0]
4165 managing = options.get("managing",None)
4166 if managing is not None:
4167 creator = managing
4168 else:
4169 creator = self.getCreator()
4170 conf = cat.newConference(creator)
4171 if managing is not None :
4172 conf.grantModification(managing)
4173 conf.setTitle(self.getTitle())
4174 conf.setDescription(self.getDescription())
4175 conf.setTimezone(self.getTimezone())
4176 for loc in self.getLocationList():
4177 if loc is not None:
4178 conf.addLocation(loc.clone())
4179 if self.getRoom() is not None:
4180 conf.setRoom(self.getRoom().clone())
4181 startDate = timezone(self.getTimezone()).localize(startDate).astimezone(timezone('UTC'))
4182 timeDelta = startDate - self.getStartDate()
4183 endDate = self.getEndDate() + timeDelta
4184 conf.setDates( startDate, endDate, moveEntries=1 )
4185 conf.setContactInfo(self.getContactInfo())
4186 conf.setChairmanText(self.getChairmanText())
4187 conf.setVisibility(self.getVisibility())
4188 conf.setSupportEmail(self.getSupportEmail())
4189 conf.setReportNumberHolder(self.getReportNumberHolder().clone(self))
4190 for ch in self.getChairList():
4191 conf.addChair(ch.clone())
4192 # Display Manager
4193 from MaKaC.webinterface import displayMgr
4194 selfDispMgr=displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self)
4195 selfDispMgr.clone(conf)
4196 # Contribution Types' List (main detailes of the conference)
4197 for t in self.getContribTypeList() :
4198 conf.addContribType(t.clone(conf))
4199 for item in self.getSections() :
4200 conf._sections.append(item)
4201 if options.get("sessions", False):
4202 for entry in self.getSchedule().getEntries():
4203 if isinstance(entry,BreakTimeSchEntry):
4204 conf.getSchedule().addEntry(entry.clone(conf))
4205 db_root = DBMgr.getInstance().getDBConnection().root()
4206 if db_root.has_key( "webfactoryregistry" ):
4207 confRegistry = db_root["webfactoryregistry"]
4208 else:
4209 confRegistry = OOBTree.OOBTree()
4210 db_root["webfactoryregistry"] = confRegistry
4211 meeting=False
4212 # if the event is a meeting or a lecture
4213 if confRegistry.get(str(self.getId()), None) is not None :
4214 meeting=True
4215 confRegistry[str(conf.getId())] = confRegistry[str(self.getId())]
4216 # if it's a conference, no web factory is needed
4217 # Tracks in a conference
4218 if options.get("tracks",False) :
4219 for tr in self.getTrackList() :
4220 conf.addTrack(tr.clone(conf))
4221 # Meetings' and conferences' sessions cloning
4222 if options.get("sessions",False) :
4223 for s in self.getSessionList() :
4224 conf.addSession(s.clone(timeDelta, conf, options))
4225 # Materials' cloning
4226 if options.get("materials",False) :
4227 for m in self.getMaterialList() :
4228 conf.addMaterial(m.clone(conf))
4229 if self.getPaper() is not None:
4230 conf.setPaper(self.getPaper().clone(conf))
4231 if self.getSlides() is not None:
4232 conf.setSlides(self.getSlides().clone(conf))
4233 if self.getVideo() is not None:
4234 conf.setVideo(self.getVideo().clone(conf))
4235 if self.getPoster() is not None:
4236 conf.setPoster(self.getPoster().clone(conf))
4237 if self.getMinutes() is not None:
4238 conf.setMinutes(self.getMinutes().clone(conf))
4239 # access and modification keys
4240 if options.get("keys", False) :
4241 conf.setAccessKey(self.getAccessKey())
4242 conf.setModifKey(self.getModifKey())
4243 # Access Control cloning
4244 if options.get("access",False) :
4245 conf.setProtection(self.getAccessController()._getAccessProtection())
4246 for mgr in self.getManagerList() :
4247 conf.grantModification(mgr)
4248 for user in self.getAllowedToAccessList() :
4249 conf.grantAccess(user)
4250 for right in self.getSessionCoordinatorRights():
4251 conf.addSessionCoordinatorRight(right)
4252 for domain in self.getDomainList():
4253 conf.requireDomain(domain)
4254 # conference's registration form
4255 if options.get("registration",False) :
4256 conf.setRegistrationForm(self.getRegistrationForm().clone(conf))
4258 # conference's evaluation
4259 if options.get("evaluation",False) :
4260 #Modify this, if you have now many evaluations.
4261 #You will have to clone every evaluations of this conference.
4262 conf.setEvaluations([self.getEvaluation().clone(conf)])
4264 #conference's abstracts
4265 if options.get("abstracts",False) :
4266 conf.abstractMgr = self.abstractMgr.clone(conf)
4267 # conference's alerts
4268 if options.get("alerts",False) :
4269 for alarm in self.getAlarmList() :
4270 # .clone takes care of enqueuing it
4271 alarm.clone(conf)
4272 # Meetings' and conferences' contributions cloning
4273 if options.get("contributions",False) :
4274 sch = conf.getSchedule()
4275 for cont in self.getContributionList():
4276 if cont.getSession() is None :
4277 if not meeting:
4278 nc = cont.clone(conf, options, timeDelta)
4279 conf.addContribution(nc)
4280 if cont.isScheduled() :
4281 sch.addEntry(nc.getSchEntry())
4282 elif cont.isScheduled():
4283 # meetings...only scheduled
4284 nc = cont.clone(conf, options, timeDelta)
4285 conf.addContribution(nc)
4286 sch.addEntry(nc.getSchEntry())
4287 # Participants' module settings and list cloning
4288 if options.get("participants",False) :
4289 self.getParticipation().clone(conf, options, eventManager)
4290 conf.notifyModification()
4292 #we inform the plugins in case they want to add anything to the new conference
4293 self._notify('cloneEvent', {'conf': conf, 'user': userPerformingClone, 'options': options})
4294 return conf
4296 def newAlarm(self, when, enqueue=True):
4298 if type(when) == timedelta:
4299 relative = when
4300 dtStart = None
4301 else:
4302 relative = None
4303 dtStart = when
4305 confRelId = self._getNextAlarmId()
4306 al = tasks.AlarmTask(self, confRelId,
4307 startDateTime=dtStart,
4308 relative=relative)
4310 self.addAlarm(al, enqueue)
4311 return al
4313 def removeAlarm(self, alarm):
4314 confRelId = alarm.getConfRelativeId()
4316 if confRelId in self.alarmList:
4317 del self.alarmList[confRelId]
4318 self._p_changed = 1
4320 tl = Client()
4321 tl.dequeue(alarm)
4322 else:
4323 raise Exception("alarm not in list!")
4325 def _getNextAlarmId(self):
4326 return self.__alarmCounter.newCount()
4328 def addAlarm(self, alarm, enqueue = True):
4329 if enqueue:
4330 tl = Client()
4331 tl.enqueue(alarm)
4333 self.alarmList[alarm.getConfRelativeId()] = alarm
4334 self._p_changed = 1
4336 def recoverAlarm(self, alarm):
4337 self.addAlarm(alarm)
4338 alarm.conf = self
4339 alarm.recover()
4341 def getAlarmList(self):
4342 return self.alarmList.values()
4344 def getAlarmById(self, id):
4345 """For given id returns corresponding Alarm or None if not found."""
4346 return self.alarmList.get(id, None)
4348 def getCoordinatedTracks( self, av ):
4349 """Returns a list with the tracks for which a user is coordinator.
4351 try:
4352 if self._trackCoordinators:
4353 pass
4354 except AttributeError:
4355 self._trackCoordinators = TCIndex()
4356 self.notifyModification()
4357 return self._trackCoordinators.getTracks( av )
4359 def addTrackCoordinator( self, track, av ):
4360 """Makes a user become coordinator for a track.
4362 try:
4363 if self._trackCoordinators:
4364 pass
4365 except AttributeError:
4366 self._trackCoordinators = TCIndex()
4367 self.notifyModification()
4368 if track in self.program:
4369 track.addCoordinator( av )
4370 self._trackCoordinators.indexCoordinator( av, track )
4371 self.notifyModification()
4373 def removeTrackCoordinator( self, track, av ):
4374 """Removes a user as coordinator for a track.
4376 try:
4377 if self._trackCoordinators:
4378 pass
4379 except AttributeError:
4380 self._trackCoordinators = TCIndex()
4381 self.notifyModification()
4382 if track in self.program:
4383 track.removeCoordinator( av )
4384 self._trackCoordinators.unindexCoordinator( av, track )
4385 self.notifyModification()
4387 def _rebuildAuthorIndex(self):
4388 self._authorIdx=AuthorIndex()
4389 for contrib in self.getContributionList():
4390 if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn):
4391 for auth in contrib.getAuthorList():
4392 self._authorIdx.index(auth)
4394 def getAuthorIndex(self):
4395 try:
4396 if self._authorIdx:
4397 pass
4398 except AttributeError:
4399 self._rebuildAuthorIndex()
4400 return self._authorIdx
4402 def indexAuthor(self,auth):
4403 c=auth.getContribution()
4404 if c.isAuthor(auth):
4405 if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4406 self.getAuthorIndex().index(auth)
4407 if c.isPrimaryAuthor(auth):
4408 self._getPrimAuthIndex().index(auth)
4410 def unindexAuthor(self,auth):
4411 c=auth.getContribution()
4412 if c.isAuthor(auth):
4413 self.getAuthorIndex().unindex(auth)
4414 if c.isPrimaryAuthor(auth):
4415 self._getPrimAuthIndex().unindex(auth)
4417 def _rebuildSpeakerIndex(self):
4418 self._speakerIdx=AuthorIndex()
4419 for contrib in self.getContributionList():
4420 if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn):
4421 for auth in contrib.getSpeakerList():
4422 self._speakerIdx.index(auth)
4423 for subcontrib in contrib.getSubContributionList():
4424 for auth in subcontrib.getSpeakerList():
4425 self._speakerIdx.index(auth)
4427 def getSpeakerIndex(self):
4428 try:
4429 if self._speakerIdx:
4430 pass
4431 except AttributeError:
4432 self._rebuildSpeakerIndex()
4433 return self._speakerIdx
4435 def indexSpeaker(self,auth):
4436 c=auth.getContribution()
4437 if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4438 self.getSpeakerIndex().index(auth)
4440 def unindexSpeaker(self,auth):
4441 c=auth.getContribution()
4442 if c and not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4443 self.getSpeakerIndex().unindex(auth)
4445 def getRegistrationForm(self):
4446 try:
4447 if self._registrationForm is None:
4448 self._registrationForm = registration.RegistrationForm(self)
4449 except AttributeError,e:
4450 self._registrationForm = registration.RegistrationForm(self)
4451 return self._registrationForm
4453 def setRegistrationForm(self,rf):
4454 self._registrationForm = rf
4455 rf.setConference(self)
4457 def removeRegistrationForm(self):
4458 try:
4459 self._registrationForm.delete()
4460 self._registrationForm.setConference(None)
4461 self._registrationForm = None
4462 except AttributeError:
4463 self._registrationForm = None
4465 def recoverRegistrationForm(self, rf):
4466 self.setRegistrationForm(rf)
4467 rf.recover()
4469 def getEvaluation(self, id=0):
4470 ############################################################################
4471 #For the moment only one evaluation per conference is used. #
4472 #In the future if there are more than one evaluation, modify this function.#
4473 ############################################################################
4474 """ Return the evaluation given by its ID or None if nothing found.
4475 Params:
4476 id -- id of the wanted evaluation
4478 for evaluation in self.getEvaluations():
4479 if str(evaluation.getId()) == str(id) :
4480 return evaluation
4481 if HelperMaKaCInfo.getMaKaCInfoInstance().isDebugActive():
4482 raise Exception(_("Error with id: expected '%s', found '%s'.")%(id, self.getEvaluations()[0].getId()))
4483 else:
4484 return self.getEvaluations()[0]
4486 def getEvaluations(self):
4487 if not hasattr(self, "_evaluations"):
4488 self._evaluations = [Evaluation(self)]
4489 return self._evaluations
4491 def setEvaluations(self, evaluationsList):
4492 self._evaluations = evaluationsList
4493 for evaluation in self._evaluations:
4494 evaluation.setConference(self)
4496 def removeEvaluation(self, evaluation):
4497 """remove the given evaluation from its evaluations."""
4498 evaluations = self.getEvaluations()
4499 if evaluations.count(evaluation)>0:
4500 evaluations.remove(evaluation)
4501 evaluation.removeReferences()
4502 self.notifyModification()
4504 def removeAllEvaluations(self):
4505 for evaluation in self.getEvaluations():
4506 evaluation.removeReferences()
4507 self._evaluations = []
4508 self.notifyModification()
4510 def _getEvaluationCounter(self):
4511 if not hasattr(self, "_evaluationCounter"):
4512 self._evaluationCounter = Counter()
4513 return self._evaluationCounter
4515 ## Videoconference bookings related
4516 def getBookings(self):
4517 try:
4518 if self._bookings:
4519 pass
4520 except AttributeError, e:
4521 self._bookings = {}
4522 self.notifyModification()
4523 return self._bookings
4525 def getBookingsList(self, sort = False):
4526 bl = self.getBookings().values()
4527 if sort:
4528 bl.sort()
4529 return bl
4531 def _getBookingGenerator(self):
4532 try:
4533 return self._bookingGenerator
4534 except AttributeError, e:
4535 self._bookingGenerator = Counter()
4536 return self._bookingGenerator
4538 def getNewBookingId(self):
4539 return str(self._getBookingGenerator().newCount())
4541 def addBooking(self, bp):
4542 if (bp.getId() == ""):
4543 bp.setId(self.getNewBookingId())
4544 self.getBookings()[bp.getId()] = bp
4545 self.notifyModification()
4547 def hasBooking(self,booking):
4548 return booking.getConference()==self and \
4549 self.getBookings().has_key(booking.getId())
4551 def removeBooking(self, booking):
4552 if self.hasBooking(booking):
4553 deletion= booking.deleteBooking()
4554 if deletion[0] != 1:
4555 del self.getBookings()[booking.getId()]
4556 self.notifyModification()
4557 return deletion
4559 def getBookingByType(self, type):
4560 if self.getBookings().has_key(type):
4561 return self.getBookings()[type]
4562 return None
4564 def getBookingById(self, id):
4565 if self.getBookings().has_key(id):
4566 return self.getBookings()[id]
4567 return None
4569 ## End of Videoconference bookings related
4571 def getModPay(self):
4572 try:
4573 if self._modPay is None:
4574 self._modPay= epayment.EPayment(self)
4575 except AttributeError,e:
4576 self._modPay= epayment.EPayment(self)
4577 return self._modPay
4579 def getRegistrants(self):
4580 try:
4581 if self._registrants:
4582 pass
4583 except AttributeError, e:
4584 self._registrants = {}
4585 self.notifyModification()
4586 return self._registrants
4588 def getRegistrantsByEmail(self):
4589 try:
4590 if self._registrantsByEmail:
4591 pass
4592 except AttributeError, e:
4593 self._registrantsByEmail = self._createRegistrantsByEmail()
4594 self.notifyModification()
4595 return self._registrantsByEmail
4597 def _createRegistrantsByEmail(self):
4598 dicByEmail = {}
4599 for r in self.getRegistrantsList():
4600 dicByEmail[r.getEmail()] = r
4601 return dicByEmail
4603 def getRegistrantsList(self, sort = False):
4604 rl = self.getRegistrants().values()
4605 if sort:
4606 rl.sort(registration.Registrant._cmpFamilyName)
4607 return rl
4609 def _getRegistrantGenerator(self):
4610 try:
4611 return self._registrantGenerator
4612 except AttributeError, e:
4613 self._registrantGenerator = Counter()
4614 return self._registrantGenerator
4616 def addRegistrant(self, rp):
4617 rp.setId( str(self._getRegistrantGenerator().newCount()) )
4618 rp.setOwner( self )
4619 self.getRegistrants()[rp.getId()] = rp
4620 self.notifyModification()
4622 def updateRegistrantIndexByEmail(self, rp, newEmail):
4623 oldEmail = rp.getEmail()
4624 if oldEmail != newEmail:
4625 if self.getRegistrantsByEmail().has_key(oldEmail):
4626 del self.getRegistrantsByEmail()[oldEmail]
4627 self.getRegistrantsByEmail()[newEmail] = rp
4628 self.notifyModification()
4630 def hasRegistrant(self,rp):
4631 return rp.getConference()==self and \
4632 self.getRegistrants().has_key(rp.getId())
4634 def hasRegistrantByEmail(self, email):
4635 # Return true if there is someone with the email of the param "email"
4636 return self.getRegistrantsByEmail().has_key(email)
4638 def removeRegistrant(self, id):
4639 part = self.getRegistrants()[id]
4640 self._registrationForm.notifyRegistrantRemoval(self.getRegistrants()[id])
4641 del self.getRegistrantsByEmail()[self.getRegistrantById(id).getEmail()]
4642 del self.getRegistrants()[id]
4643 if part.getAvatar() is not None:
4644 part.getAvatar().removeRegistrant(part)
4645 TrashCanManager().add(part)
4646 self.notifyModification()
4648 def getRegistrantById(self, id):
4649 if self.getRegistrants().has_key(id):
4650 return self.getRegistrants()[id]
4651 return None
4653 def _getPrimAuthIndex(self):
4654 try:
4655 if self._primAuthIdx:
4656 pass
4657 except AttributeError:
4658 self._primAuthIdx=_PrimAuthIdx(self)
4659 return self._primAuthIdx
4661 def getContribsMatchingAuth(self,query,onlyPrimary=True):
4662 if str(query).strip()=="":
4663 return self.getContributionList()
4664 res=self._getPrimAuthIndex().match(query)
4665 return [self.getContributionById(id) for id in res]
4667 def getCoordinatedSessions( self, av ):
4668 """Returns a list with the sessions for which a user is coordinator.
4670 try:
4671 if self._sessionCoordinators:
4672 pass
4673 except AttributeError:
4674 self._sessionCoordinators = SCIndex()
4675 sessions = self._sessionCoordinators.getSessions( av )
4676 for session in self.getSessionList():
4677 if session not in sessions and av != None:
4678 for email in av.getEmails():
4679 if email in session.getCoordinatorEmailList():
4680 sessions.append(session)
4681 break
4682 return sessions
4684 def getManagedSession( self, av ):
4685 ls = []
4686 for session in self.getSessionList():
4687 pending = False
4688 if av != None:
4689 for email in av.getEmails():
4690 if email in session.getAccessController().getModificationEmail():
4691 pending = True
4692 break
4693 if av in session.getManagerList() or pending:
4694 ls.append(session)
4695 return ls
4697 def addSessionCoordinator(self,session,av):
4698 """Makes a user become coordinator for a session.
4700 try:
4701 if self._sessionCoordinators:
4702 pass
4703 except AttributeError:
4704 self._sessionCoordinators = SCIndex()
4705 if self.sessions.has_key(session.getId()):
4706 session.addCoordinator(av)
4707 self._sessionCoordinators.index(av,session)
4709 def removeSessionCoordinator( self, session, av ):
4710 """Removes a user as coordinator for a session.
4712 try:
4713 if self._sessionCoordinators:
4714 pass
4715 except AttributeError:
4716 self._sessionCoordinators = SCIndex()
4717 if self.sessions.has_key(session.getId()):
4718 session.removeCoordinator( av )
4719 self._sessionCoordinators.unindex(av,session)
4721 def _getSubmitterIdx(self):
4722 try:
4723 return self._submitterIdx
4724 except AttributeError:
4725 self._submitterIdx=SubmitterIndex()
4726 return self._submitterIdx
4728 def addContribSubmitter(self,contrib,av):
4729 self._getSubmitterIdx().index(av,contrib)
4731 def removeContribSubmitter(self,contrib,av):
4732 self._getSubmitterIdx().unindex(av,contrib)
4734 def getContribsForSubmitter(self,av):
4735 return self._getSubmitterIdx().getContributions(av)
4737 def getBOAConfig(self):
4738 try:
4739 if self._boa:
4740 pass
4741 except AttributeError:
4742 self._boa=BOAConfig(self)
4743 return self._boa
4745 def getSessionCoordinatorRights(self):
4746 try:
4747 if self._sessionCoordinatorRights:
4748 pass
4749 except AttributeError, e:
4750 self._sessionCoordinatorRights = []
4751 self.notifyModification()
4752 return self._sessionCoordinatorRights
4754 def hasSessionCoordinatorRight(self, right):
4755 return right in self.getSessionCoordinatorRights()
4757 def addSessionCoordinatorRight(self, right):
4758 if SessionCoordinatorRights().hasRight(right) and not self.hasSessionCoordinatorRight(right):
4759 self._sessionCoordinatorRights.append(right)
4760 self.notifyModification()
4762 def removeSessionCoordinatorRight(self, right):
4763 if SessionCoordinatorRights().hasRight(right) and self.hasSessionCoordinatorRight(right):
4764 self._sessionCoordinatorRights.remove(right)
4765 self.notifyModification()
4767 def getSections(self):
4768 try:
4769 if self._sections:
4770 pass
4771 except AttributeError, e:
4772 self._sections = ConfSectionsMgr().getSectionKeys()
4773 self.notifyModification()
4774 return self._sections
4776 def hasEnabledSection(self, section):
4777 # This hack is there since there is no more enable/disable boxes
4778 # in the conference managment area corresponding to those features.
4779 # Until the managment area is improved to get a more user-friendly
4780 # way of enabling/disabling those features, we always make them
4781 # available for the time being, but we keep the previous code for
4782 # further improvements
4783 return True
4785 def enableSection(self, section):
4786 if ConfSectionsMgr().hasSection(section) and not self.hasEnabledSection(section):
4787 self._sections.append(section)
4788 self.notifyModification()
4790 def disableSection(self, section):
4791 if ConfSectionsMgr().hasSection(section) and self.hasEnabledSection(section):
4792 self._sections.remove(section)
4793 self.notifyModification()
4795 def getPendingQueuesMgr(self):
4796 try:
4797 if self._pendingQueuesMgr:
4798 pass
4799 except AttributeError, e:
4800 self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self)
4801 return self._pendingQueuesMgr
4803 def getAccessController(self):
4804 return self.__ac
4806 def _cmpTitle( c1, c2 ):
4807 o1 = c1.getTitle().lower().strip()
4808 o2 = c2.getTitle().lower().strip()
4809 return cmp( o1, o2 )
4810 _cmpTitle=staticmethod(_cmpTitle)
4812 def getReportNumberHolder(self):
4813 try:
4814 if self._reportNumberHolder:
4815 pass
4816 except AttributeError, e:
4817 self._reportNumberHolder=ReportNumberHolder(self)
4818 return self._reportNumberHolder
4820 def setReportNumberHolder(self, rnh):
4821 self._reportNumberHolder=rnh
4823 def getBadgeTemplateManager(self):
4824 try:
4825 if self.__badgeTemplateManager:
4826 pass
4827 except AttributeError:
4828 self.__badgeTemplateManager = BadgeTemplateManager(self)
4829 return self.__badgeTemplateManager
4831 def setBadgeTemplateManager(self, badgeTemplateManager):
4832 self.__badgeTemplateManager = badgeTemplateManager
4834 def getPosterTemplateManager(self):
4835 try:
4836 if self.__posterTemplateManager:
4837 pass
4838 except AttributeError:
4839 self.__posterTemplateManager = PosterTemplateManager(self)
4841 return self.__posterTemplateManager
4843 def setPosterTemplateManager(self, posterTemplateManager):
4844 self.__posterTemplateManager = posterTemplateManager
4846 def getCSBookingManager(self):
4848 if PluginsHolder().hasPluginType("Collaboration"):
4849 if not hasattr(self, "_CSBookingManager"):
4850 from MaKaC.plugins.Collaboration.base import CSBookingManager
4851 self._CSBookingManager = CSBookingManager(self)
4852 return self._CSBookingManager
4853 else:
4854 return None
4857 class DefaultConference(Conference):
4858 """ 'default' conference, which stores the
4859 default templates for posters and badges
4862 def indexConf(self):
4863 pass
4865 def __init__(self):
4866 """ Default constructor
4868 try:
4869 Conference.__init__(self, AdminList.getInstance().getList()[0], "default")
4870 except IndexError:
4871 raise MaKaCError(_("""There are no admin users. The "default" conference that stores the template cannot be created.
4872 Please add at least 1 user to the admin list."""))
4875 class ConferenceHolder( ObjectHolder ):
4876 """Specialised ObjectHolder dealing with conference objects. It gives a
4877 common entry point and provides simple methods to access and
4878 maintain the collection of stored conferences (DB).
4880 idxName = "conferences"
4881 counterName = "CONFERENCE"
4883 def _newId( self ):
4884 id = ObjectHolder._newId( self )
4885 return "%s"%id
4887 def getByStartDate( self, sday, eday = None ):
4888 # XXX This function seems strange?
4889 res=[]
4890 sDayStart=datetime(sday.year,sday.month,sday.day,0,0)
4891 sDayEnd=datetime(sday.year,sday.month,sday.day,23,59)
4892 for conf in self.getList():
4893 if sday>=sDayStart and sdat<=sDayEnd:
4894 res.append(conf)
4895 return conf
4897 def getById( self, id, quiet=False ):
4898 """returns an object from the index which id corresponds to the one
4899 which is specified.
4902 if (id == "default"):
4903 return CategoryManager().getDefaultConference()
4905 if type(id) is int:
4906 id = str(id)
4907 if self._getIdx().has_key(str(id)):
4908 return self._getIdx()[str(id)]
4909 elif quiet:
4910 return None
4911 else:
4912 raise NoReportError( _("The specified event with id \"%s\" does not exist or has been deleted.") % str(id) )
4914 class ConfSectionsMgr:
4916 def __init__(self):
4917 self._sections = {
4918 "cfa": _("Call for abstracts"),
4919 #comment the following line to make the Paper Reviewing module not appear
4920 "paperReviewing" : _("Paper Reviewing"),
4921 "evaluation": _("Evaluation Form"),
4922 "videoconference": _("Videoconference"), # only for meetings
4923 "collaboration": _("Collaboration"), # only for meetings
4924 "regForm": _("Registration Form")
4927 def hasSection(self, s):
4928 # This hack is there since there is no more enable/disable boxes
4929 # in the conference managment area corresponding to those features.
4930 # Until the managment area is improved to get a more user-friendly
4931 # way of enabling/disabling those features, we always make them
4932 # available in the side menu for the time being, but we keep
4933 # the previous code for further improvements
4934 #return self._sections.has_key(s)
4935 return True
4937 def getSections(self):
4938 return self._sections
4940 def getSectionList(self, sort=False):
4941 l=self._sections.values()
4942 if sort:
4943 l.sort()
4944 return l
4946 def getSectionKeys(self, sort=False):
4947 l=self._sections.keys()
4948 if sort:
4949 l.sort()
4950 return l
4952 def getSection(self, id):
4953 if self._sections.has_key(id):
4954 return self._sections[id]
4955 return None
4958 class Observer(object):
4959 """ Base class for Observer objects.
4960 Inheriting classes should overload the following boolean class attributes:
4961 _shouldBeTitleNotified
4962 _shouldBeDateChangeNotified
4963 _shouldBeLocationChangeNotified
4964 _shouldBeDeletionNotified
4965 And set them to True if they want to be notified of the corresponding event.
4966 In that case, they also have to implement the corresponding methods:
4967 _notifyTitleChange (for title notification)
4968 _notifyEventDateChanges and _notifyTimezoneChange (for date / timezone notification)
4969 _shouldBeLocationChangeNotified (for location notification)
4970 _notifyDeletion (for deletion notification).
4971 The interface for those methods is also specified in this class. If the corresponding
4972 class attribute is set to False but the method is not implemented, an exception will be thrown.
4974 _shouldBeTitleNotified = False
4975 _shouldBeDateChangeNotified = False
4976 _shouldBeLocationChangeNotified = False
4977 _shouldBeDeletionNotified = False
4979 def getObserverName(self):
4980 name = "'Observer of class" + self.__class__.__name__
4981 try:
4982 conf = self.getOwner()
4983 name = name + " of event " + conf.getId() + "'"
4984 except AttributeError:
4985 pass
4986 return name
4988 def notifyTitleChange(self, oldTitle, newTitle):
4989 if self._shouldBeTitleNotified:
4990 self._notifyTitleChange(oldTitle, newTitle)
4992 def notifyEventDateChanges(self, oldStartDate = None, newStartDate = None, oldEndDate = None, newEndDate = None):
4993 if self._shouldBeDateChangeNotified:
4994 self._notifyEventDateChanges(oldStartDate, newStartDate, oldEndDate, newEndDate)
4996 def notifyTimezoneChange(self, oldTimezone, newTimezone):
4997 if self._shouldBeDateChangeNotified:
4998 self._notifyTimezoneChange(oldTimezone, newTimezone)
5000 def notifyLocationChange(self, newLocation):
5001 if self._shouldBeLocationChangeNotified:
5002 self._notifyLocationChange(newLocation)
5004 def notifyDeletion(self):
5005 if self._shouldBeDeletionNotified:
5006 self._notifyDeletion()
5008 def _notifyTitleChange(self, oldTitle, newTitle):
5009 """ To be implemented by inheriting classes
5010 Notifies the observer that the Conference object's title has changed
5012 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method _notifyTitleChange")
5014 def _notifyEventDateChanges(self, oldStartDate, newStartDate, oldEndDate, newEndDate):
5015 """ To be implemented by inheriting classes
5016 Notifies the observer that the start and / or end dates of the object it is attached to has changed.
5017 If the observer finds any problems during whatever he needs to do as a consequence of
5018 the event dates changing, he should write strings describing the problems
5019 in the 'dateChangeNotificationProblems' context variable (which is a list of strings).
5021 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyStartDateChange")
5023 def _notifyTimezoneChange(self, oldTimezone, newTimezone):
5024 """ To be implemented by inheriting classes.
5025 Notifies the observer that the end date of the object it is attached to has changed.
5026 This method has to return a list of strings describing problems encountered during
5027 whatever the DateChangeObserver object does as a consequence of the notification.
5028 If there are no problems, the DateChangeObserver should return an empty list.
5030 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTimezoneChange")
5032 def _notifyLocationChange(self):
5033 """ To be implemented by inheriting classes
5034 Notifies the observer that the location of the object it is attached to has changed.
5036 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyLocationChange")
5038 def _notifyDeletion(self):
5039 """ To be implemented by inheriting classes
5040 Notifies the observer that the Conference object it is attached to has been deleted
5042 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyDeletion")
5044 class TitleChangeObserver(Observer):
5045 """ Base class for objects who want to be notified of a Conference object being deleted.
5046 Inheriting classes have to implement the notifyTitleChange method, and probably the __init__ method too.
5049 def notifyTitleChange(self, oldTitle, newTitle):
5050 """ To be implemented by inheriting classes
5051 Notifies the observer that the Conference object's title has changed
5053 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTitleChange")
5056 class SessionChair(ConferenceParticipation):
5058 def __init__(self):
5059 self._session=None
5060 self._id=""
5061 ConferenceParticipation.__init__(self)
5063 def _notifyModification( self ):
5064 if self._session != None:
5065 self._session.notifyModification()
5067 def clone(self):
5068 chair = SessionChair()
5069 chair.setValues(self.getValues())
5070 return chair
5072 def getSession(self):
5073 return self._session
5075 def getConference(self):
5076 s=self.getSession()
5077 if s is None:
5078 return None
5079 return s.getConference()
5081 def includeInSession(self,session,id):
5082 if self.getSession()==session and self.getId()==id.strip():
5083 return
5084 self._session=session
5085 self._id=id
5087 def delete( self ):
5088 self._session=None
5089 ConferenceParticipation.delete(self)
5091 def getLocator(self):
5092 if self.getSession() is None:
5093 return None
5094 loc=self.getSession().getLocator()
5095 loc["convId"]=self.getId()
5096 return loc
5099 class SlotChair(ConferenceParticipation):
5101 def __init__(self):
5102 self._slot=None
5103 self._id=""
5104 ConferenceParticipation.__init__(self)
5106 def _notifyModification( self ):
5107 if self._slot != None:
5108 self._slot.notifyModification()
5110 def clone(self):
5111 chair = SlotChair()
5112 chair.setValues(self.getValues())
5113 return chair
5115 def getSlot(self):
5116 return self._slot
5118 def getSession(self):
5119 s=self.getSlot()
5120 if s is None:
5121 return None
5122 return s.getSession()
5124 def getConference(self):
5125 s=self.getSlot()
5126 if s is None:
5127 return None
5128 return s.getConference()
5130 def includeInSlot(self,slot,id):
5131 if self.getSlot()==slot and self.getId()==id.strip():
5132 return
5133 self._slot=slot
5134 self._id=id
5136 def delete( self ):
5137 self._slot=None
5138 ConferenceParticipation.delete(self)
5140 def getLocator(self):
5141 if self.getSlot() is None:
5142 return None
5143 loc=self.getSlot().getLocator()
5144 loc["convId"]=self.getId()
5145 return loc
5147 class SessionCoordinatorRights:
5149 def __init__(self):
5150 self._rights = {"modifContribs": _("Modify the contributions"), \
5151 "unrestrictedSessionTT": _("Unrestricted session timetable management")
5154 def hasRight(self, r):
5155 return self._rights.has_key(r)
5157 def getRights(self):
5158 return self._rights
5160 def getRightList(self, sort=False):
5161 l=self._rights.values()
5162 if sort:
5163 l.sort()
5164 return l
5166 def getRightKeys(self):
5167 return self._rights.keys()
5169 def getRight(self, id):
5170 if self._rights.has_key(id):
5171 return self._rights[id]
5172 return None
5174 class SCIndex(Persistent):
5175 """Index for conference session coordinators.
5177 This class allows to index conference session coordinators so the owner
5178 can answer optimally to the query if a user is coordinating
5179 any conference session.
5180 It is implemented by simply using a BTree where the Avatar id is used
5181 as key (because it is unique and non variable) and a list of
5182 coordinated sessions is kept as keys. It is the responsability of the
5183 index owner (conference) to keep it up-to-date i.e. notify session
5184 coordinator additions and removals.
5187 def __init__( self ):
5188 self._idx=OOBTree()
5191 def getSessions(self,av):
5192 """Gives a list with the sessions a user is coordinating.
5194 if av == None:
5195 return []
5196 return self._idx.get(av.getId(),[])
5198 def index(self,av,session):
5199 """Registers in the index a coordinator of a session.
5201 if av == None or session == None:
5202 return
5203 if not self._idx.has_key(av.getId()):
5204 l=[]
5205 self._idx[av.getId()]=l
5206 else:
5207 l=self._idx[av.getId()]
5208 if session not in l:
5209 l.append(session)
5210 self.notifyModification()
5212 def unindex(self,av,session):
5213 if av==None or session==None:
5214 return
5215 l=self._idx.get(av.getId(),[])
5216 if session in l:
5217 l.remove(session)
5218 self.notifyModification()
5220 def notifyModification(self):
5221 self._idx._p_changed=1
5224 class Session(CommonObjectBase, Locatable):
5225 """This class implements a conference session, being the different parts
5226 in which the conference can be divided and the contributions can be
5227 organised in. The class contains necessary attributes to store session
5228 basic data and provides the operations related to sessions. In
5229 principle, a session has no sense to exist without being related to a
5230 conference but it is allowed for flexibility.
5233 fossilizes(ISessionFossil)
5236 def __init__(self, **sessionData):
5237 """Class constructor. Initialise the class attributes to the default
5238 values.
5239 Params:
5240 sessionData -- (Dict) Contains the data the session object has to
5241 be initialised to.
5243 self.conference=None
5244 self.id="not assigned"
5245 self.title=""
5246 self.description=""
5247 #################################
5248 # Fermi timezone awareness #
5249 #################################
5250 self.startDate = nowutc()
5251 #################################
5252 # Fermi timezone awareness(end) #
5253 #################################
5255 self.duration=timedelta(minutes=1)
5256 self.places=[]
5257 self.rooms=[]
5258 self.conveners=[] # This attribute must not be used and should disappear someday
5259 self._conveners=[]
5260 self._convenerGen=Counter()
5261 self.convenerText=""
5262 self.contributions={}
5263 self._contributionDuration=timedelta(minutes=20)
5264 self.__ac=AccessController(self)
5265 self.materials={}
5266 self.__materialGenerator=Counter()
5267 self.minutes=None
5268 self._comments = ""
5269 self.slots={}
5270 self.__slotGenerator=Counter()
5271 self._setSchedule()
5272 self._coordinators=OOBTree()
5273 self._coordinatorsEmail = []
5274 self._code=""
5275 self._color="#e3f2d3"
5276 self._textColor="#202020"
5277 self._textColorToLinks=False
5278 self._ttType=SlotSchTypeFactory.getDefaultId()
5279 self._closed = False
5280 self._registrationSession = None
5281 self._creationDS = nowutc()
5282 self._modificationDS = nowutc()
5283 self._keywords = ""
5285 def getTimezone( self ):
5286 return self.getConference().getTimezone()
5288 def isFullyPublic( self ):
5289 if hasattr(self, "_fullyPublic"):
5290 return self._fullyPublic
5291 else:
5292 self.setFullyPublic()
5293 return self._fullyPublic
5295 def setFullyPublic( self ):
5296 if self.isProtected():
5297 self._fullyPublic = False
5298 self._p_changed = 1
5299 return
5300 for res in self.getAllMaterialList():
5301 if not res.isFullyPublic():
5302 self._fullyPublic = False
5303 self._p_changed = 1
5304 return
5305 for res in self.getContributionList():
5306 if not res.isFullyPublic():
5307 self._fullyPublic = False
5308 self._p_changed = 1
5309 return
5310 self._fullyPublic = True
5311 self._p_changed = 1
5313 def updateFullyPublic( self ):
5314 self.setFullyPublic()
5315 self.getOwner().updateFullyPublic()
5317 def getKeywords(self):
5318 try:
5319 return self._keywords
5320 except:
5321 self._keywords = ""
5322 return ""
5324 def setKeywords(self, keywords):
5325 self._keywords = keywords
5327 def notifyModification( self, date = None ):
5328 """Method called to notify the current session has been modified.
5330 self.setModificationDate(date)
5332 parent = self.getConference()
5333 if parent:
5334 parent.setModificationDate(date)
5335 self._p_changed=1
5337 def getModificationDate( self ):
5338 """Returns the date in which the session was last modified"""
5339 try:
5340 return self._modificationDS
5341 except:
5342 self._modificationDS = nowutc()
5343 return self._modificationDS
5345 def getCreationDate( self ):
5346 """Returns the date in which the session was created"""
5347 try:
5348 return self._creationDS
5349 except:
5350 self._creationDS = nowutc()
5351 return self._creationDS
5353 def getLogInfo(self):
5354 data = {}
5355 data["subject"] = self.title
5356 data["session id"] = self.id
5357 data["session code"] = self._code
5358 data["title"] = self.title
5359 data["description"] = self.description
5360 data["start date"] = self.startDate
5361 data["duration"] = self.duration
5362 for p in self.places :
5363 data["place"] = p.getName()
5364 for r in self.rooms :
5365 data["room"] = r.getName()
5366 for sc in self.getConvenerList() :
5367 data["convener %s"%sc.getId()] = sc.getFullName()
5368 for co in self.getCoordinatorList() :
5369 data["contribution %s"%co.getId()] = co.getFullName()
5370 for s in self.getSlotList() :
5371 data["contribution %s"%s.getId()] = s.getTitle()
5372 for c in self.getContributionList() :
5373 data["contribution %s"%c.getId()] = c.getTitle()
5375 return data
5377 def getEnableSessionSlots(self):
5378 try:
5379 return self.getConference().getEnableSessionSlots()
5380 except:
5381 return True
5383 def cmpSessionByTitle(session1, session2):
5384 return cmp(session1.getTitle(), session2.getTitle())
5385 cmpSessionByTitle = staticmethod(cmpSessionByTitle)
5387 def hasRegistrationSession(self):
5388 return self.getRegistrationSession() is not None
5390 def getRegistrationSession(self):
5391 try:
5392 if self._registrationSession:
5393 pass
5394 except AttributeError, e:
5395 self._registrationSession = None
5396 return self._registrationSession
5398 def setRegistrationSession(self, rs):
5399 self._registrationSession = rs
5401 def isClosed( self ):
5402 if self.getConference().isClosed():
5403 return True
5404 try:
5405 return self._closed
5406 except:
5407 self._closed = False
5408 return False
5410 def setClosed( self, closed=True ):
5411 self._closed = closed
5412 self.notifyModification()
5414 def includeInConference(self,conf,newId):
5415 self.conference=conf
5416 self.id=newId
5417 for slot in self.getSlotList():
5418 conf.getSchedule().addEntry(slot.getConfSchEntry(),2)
5419 self.getConference().addSession(self)
5420 self.notifyModification()
5422 def delete(self):
5423 while len(self.getConvenerList()) > 0:
5424 self.removeConvener(self.getConvenerList()[0])
5425 while len(self.getMaterialList()) > 0:
5426 self.removeMaterial(self.getMaterialList()[0])
5427 self.removeMinutes()
5428 for c in self.getCoordinatorList()[:]:
5429 self.removeCoordinator(c)
5430 while len(self.contributions.values())>0:
5431 self.removeContribution(self.contributions.values()[0])
5432 while len(self.slots.values())>0:
5433 self._removeSlot(self.slots.values()[0])
5434 if self.getConference() is not None:
5435 self.getConference().removeSession(self)
5436 if self.hasRegistrationSession():
5437 self.getConference().getRegistrationForm().getSessionsForm().removeSession(self.getId())
5438 self.getRegistrationSession().setRegistrationForm(None)
5439 TrashCanManager().add(self.getRegistrationSession())
5440 self.conference=None
5441 TrashCanManager().add(self)
5443 def recover(self, isCancelled):
5444 if self.hasRegistrationSession():
5445 if not isCancelled:
5446 self.getRegistrationSession().setRegistrationForm(self.getConference().getRegistrationForm())
5447 self.getConference().getRegistrationForm().getSessionsForm().addSession(self.getRegistrationSession())
5448 TrashCanManager().remove(self.getRegistrationSession())
5449 TrashCanManager().remove(self)
5451 def getLocator( self ):
5452 """Gives back a globaly unique identification encapsulated in a Locator
5453 object for the session instance
5455 if self.conference == None:
5456 return Locator()
5457 lconf = self.conference.getLocator()
5458 lconf["sessionId"] = self.getId()
5459 return lconf
5461 def getConference( self ):
5462 return self.conference
5464 def getSession( self ):
5465 return self
5467 def getOwner( self ):
5468 return self.getConference()
5470 def getId( self ):
5471 return self.id
5473 def getUniqueId( self ):
5474 """returns (string) the unique identiffier of the item"""
5475 """used mainly in the web session access key table"""
5476 return "%ss%s" % (self.getConference().getUniqueId(),self.id)
5478 def getModifKey( self ):
5479 return self.getConference().getModifKey()
5481 def getAccessKey( self ):
5482 return self.getConference().getAccessKey()
5484 def getContribDuration(self):
5485 try:
5486 return self._contributionDuration
5487 except:
5488 self._contributionDuration = timedelta(minutes=20)
5489 return self._contributionDuration
5491 def setContribDuration(self, hour=0, min=20, dur=None):
5492 if dur is not None:
5493 self._contributionDuration=dur
5494 else:
5495 self._contributionDuration = timedelta(hours=hour,minutes=min)
5497 def fit(self):
5498 #if not self.getConference().getEnableSessionSlots():
5499 # self.getSlotList()[0].fit()
5500 self.setStartDate(self.getMinSlotStartDate(),0,0)
5501 self.setEndDate(self.getMaxSlotEndDate(),0)
5503 def addSlot(self,newSlot):
5504 id = newSlot.getId()
5505 if id == "not assigned":
5506 newSlot.setId(str(self.__slotGenerator.newCount()))
5507 self.slots[newSlot.getId()]=newSlot
5508 self.fit()
5509 self.getSchedule().addEntry(newSlot.getSessionSchEntry(),2)
5510 if self.getConference() is not None:
5511 self.getConference().getSchedule().addEntry(newSlot.getConfSchEntry(),2)
5512 self.notifyModification()
5514 def _removeSlot(self,slot):
5515 del self.slots[slot.getId()]
5516 self.getSchedule().removeEntry(slot.getSessionSchEntry())
5517 if self.getConference() is not None:
5518 self.getConference().getSchedule().removeEntry(slot.getConfSchEntry())
5519 slot.delete()
5521 def removeSlot(self, slot, force=False):
5522 if self.slots.has_key(slot.getId()):
5523 if len(self.slots)==1 and not force:
5524 raise MaKaCError( _("A session must have at least one slot"), _("Session"))
5525 self._removeSlot(slot)
5526 self.fit()
5527 self.notifyModification()
5529 def recoverSlot(self, slot):
5530 self.addSlot(slot)
5531 slot.recover()
5533 def getSlotById(self,slotId):
5534 return self.slots.get(slotId,None)
5536 def getSlotList(self):
5537 return self.slots.values()
5539 def getSortedSlotList(self):
5540 sl = self.getSlotList()
5541 sl.sort(utils.sortSlotByDate)
5542 return sl
5544 def getMinSlotStartTime(self):
5545 min = (25,61)
5546 for slot in self.getSlotList():
5547 if slot.isMoreThanDay():
5548 return (0,0)
5549 shour = slot.getStartDate().hour
5550 smin = slot.getStartDate().minute
5551 if (shour, smin) < min:
5552 min = (shour, smin)
5553 return min
5555 def getMaxSlotEndTime(self):
5556 max = (-1,-1)
5557 for slot in self.getSlotList():
5558 if slot.isMoreThanDay():
5559 return (23, 59)
5560 endDate = slot.getEndDate()
5561 if (endDate.hour, endDate.minute) > max:
5562 newEndDate = endDate - timedelta(0, 0, 0)
5563 max = (newEndDate.hour, newEndDate.minute)
5564 return max
5566 def getMinSlotStartDate(self):
5567 slotList = self.getSlotList()
5568 if len(slotList)==0:
5569 return self.getStartDate()
5570 else:
5571 sDate = self.getEndDate()
5572 for slot in slotList:
5573 if slot.getStartDate() < sDate:
5574 sDate = slot.getStartDate()
5575 return sDate
5577 def getMaxSlotEndDate(self):
5578 slotList = self.getSlotList()
5579 if len(slotList)==0:
5580 return self.getEndDate()
5581 else:
5582 eDate = self.getStartDate()
5583 for slot in slotList:
5584 if slot.getEndDate() > eDate:
5585 eDate = slot.getEndDate()
5586 return eDate
5588 def _getCorrectColor(self, color):
5589 if not color.startswith("#"):
5590 color = "#%s"%color
5591 m = re.match("^#[0-9A-Fa-f]{6}$", color)
5592 if m:
5593 return color
5594 return None
5596 def _getCorrectBgColor(self, color):
5597 color=self._getCorrectColor(color)
5598 if color is None:
5599 return self._color
5600 return color
5602 def _getCorrectTextColor(self, color):
5603 color=self._getCorrectColor(color)
5604 if color is None:
5605 return self._textColor
5606 return color
5608 def setValues( self, sessionData,check=2,moveEntries=0 ):
5609 """Sets all the values of the current session object from a dictionary
5610 containing the following key-value pairs:
5611 title-(str)
5612 description-(str)
5613 locationName-(str) => name of the location, if not specified
5614 it will be set to the conference location name.
5615 locationAddress-(str)
5616 roomName-(str) => name of the room, if not specified it will
5617 be set to the conference room name.
5618 sDate - (datetime) => starting date of the session, if not
5619 specified it will be set to now.
5620 eDate - (datetime) => ending date of the session, if not
5621 specified the end date will be set to the start one
5622 durHour - (int) => hours of duration for each entry in the session
5623 by default.
5624 durMin - (int) => hours of duration for each entry in the session
5625 by default.
5626 _conveners - (str)
5627 check parameter:
5628 0: no check at all
5629 1: check and raise error in case of problem
5630 2: check and adapt the owner dates
5631 Please, note that this method sets ALL values which means that if
5632 the given dictionary doesn't contain any of the keys the value
5633 will set to a default value.
5636 self.setTitle( sessionData.get("title", _("NO TITLE ASSIGNED")) )
5637 self.setDescription( sessionData.get("description", "") )
5638 code = sessionData.get("code", "")
5639 if code.strip() == "":
5640 if self.getId()=="not assigned":
5641 self.setCode("no code")
5642 else:
5643 self.setCode(self.getId())
5644 else:
5645 self.setCode(code)
5646 bgcolor = sessionData.get("backgroundColor", "")
5647 if bgcolor.strip() != "":
5648 self.setColor(self._getCorrectBgColor(bgcolor))
5649 textcolor = sessionData.get("textColor", "")
5650 if textcolor.strip() != "":
5651 if sessionData.has_key("autotextcolor"):
5652 self.setTextColor(utils.getTextColorFromBackgroundColor(self.getColor()))
5653 else:
5654 self.setTextColor(self._getCorrectTextColor(textcolor))
5655 self.setTextColorToLinks(sessionData.has_key("textcolortolinks"))
5657 if "locationName" in sessionData:
5658 loc = self.getOwnLocation()
5659 if not loc:
5660 loc = CustomLocation()
5661 self.setLocation( loc )
5662 loc.setName( sessionData["locationName"] )
5663 loc.setAddress( sessionData.get("locationAddress", "") )
5664 else:
5665 self.setLocation(None)
5667 #same as for the location
5668 if "roomName" in sessionData:
5669 room = self.getOwnRoom()
5670 if not room:
5671 room = CustomRoom()
5672 self.setRoom( room )
5673 room.setName( sessionData["roomName"] )
5674 else:
5675 self.setRoom(None)
5677 if sessionData.get("sDate",None) is not None:
5678 self.setStartDate(sessionData["sDate"],check,moveEntries=moveEntries)
5679 if sessionData.get("eDate",None) is not None:
5680 self.setEndDate(sessionData["eDate"],check)
5681 self._checkInnerSchedule()
5682 if sessionData.get("contribDuration","")!="":
5683 self._contributionDuration = sessionData.get("contribDuration")
5684 else:
5685 self._contributionDuration = timedelta(hours=int(sessionData.get("durHour",0)), minutes=int(sessionData.get("durMin",20)))
5686 self.notifyModification()
5688 def move(self, sDate):
5690 Move a session from the old start date to a new start date, and
5691 it moves all the entries of the session as well, without date validations.
5693 if sDate is not None:
5694 oldStartDate=self.startDate
5695 self.startDate=copy.copy(sDate)
5696 diff=self.startDate-oldStartDate
5697 # Check date to not be prior conference start date and to not surpass conference end date
5698 # The schedule is returning the datetime object as timezone aware relative to the conference
5699 # timezone. Must adjust the startdate accordingly for comparison. JMF
5700 conftz = self.getConference().getTimezone()
5701 if self.getStartDate() < self.getConference().getSchedule().getStartDate() or \
5702 self.getEndDate() > self.getConference().getSchedule().getEndDate():
5703 raise MaKaCError( _("Impossible to move the session because it would be out of the conference dates"))
5704 for entry in self.getSchedule().getEntries():
5705 if isinstance(entry,LinkedTimeSchEntry) and \
5706 isinstance(entry.getOwner(), SessionSlot):
5707 e = entry.getOwner()
5708 e.move(e.getStartDate() + diff)
5709 self.getSchedule().reSchedule()
5710 self.getConference().getSchedule().reSchedule()
5711 self.notifyModification()
5713 def clone(self, deltaTime, conf, options):
5714 ses = Session()
5715 conf.addSession(ses,check=0)
5716 ses.setTitle(self.getTitle())
5717 ses.setDescription(self.getDescription())
5718 startDate = self.getStartDate() + deltaTime
5719 ses.setStartDate(startDate, check=1)
5720 ses.setDuration(dur=self.getDuration())
5722 if self.getOwnLocation() is not None:
5723 ses.addLocation(self.getOwnLocation().clone())
5724 if self.getOwnRoom() is not None:
5725 ses.setRoom(self.getOwnRoom().clone())
5726 for conv in self.getConvenerList():
5727 ses.addConvener(conv.clone())
5728 ses.setConvenerText(self.getConvenerText())
5729 ses.setColor(self.getColor())
5730 ses.setTextColor(self.getTextColor())
5731 ses.setTextColorToLinks(self.isTextColorToLinks())
5732 ses.setCode(self.getCode())
5733 ses.setContribDuration(dur=self.getContribDuration())
5734 ses.setScheduleType(self.getScheduleType())
5735 ses.setComments(self.getComments())
5737 # Access Control cloning
5738 if options.get("access", False) :
5739 ses.setProtection(self.getAccessController()._getAccessProtection())
5740 for mgr in self.getManagerList() :
5741 ses.grantModification(mgr)
5742 for user in self.getAllowedToAccessList() :
5743 ses.grantAccess(user)
5744 for domain in self.getDomainList():
5745 ses.requireDomain(domain)
5746 for coord in self.getCoordinatorList():
5747 ses.addCoordinator(coord)
5749 #slots in timeschedule
5750 for slot in self.getSlotList() :
5751 newslot = slot.clone(ses, options)
5752 ses.addSlot(newslot)
5754 ses.notifyModification()
5756 return ses
5759 def setTitle( self, newTitle ):
5760 self.title = newTitle
5761 self.notifyModification()
5763 def getTitle( self ):
5764 return self.title
5766 def setDescription(self, newDescription ):
5767 self.description = newDescription
5768 self.notifyModification()
5770 def getDescription(self):
5771 return self.description
5773 def getCode(self):
5774 try:
5775 if self._code:
5776 pass
5777 except AttributeError:
5778 self._code=self.id
5779 return self._code
5781 def setCode(self,newCode):
5782 self._code=str(newCode).strip()
5784 def getColor(self):
5785 try:
5786 if self._color:
5787 pass
5788 except AttributeError:
5789 self._color="#e3f2d3"
5790 return self._color
5791 getBgColor=getColor
5793 def setColor(self,newColor):
5794 self._color=str(newColor).strip()
5795 setBgColor=setColor
5797 def getTextColor(self):
5798 try:
5799 if self._textColor:
5800 pass
5801 except AttributeError:
5802 self._textColor="#202020"
5803 return self._textColor
5805 def setTextColor(self,newColor):
5806 self._textColor=str(newColor).strip()
5808 def isTextColorToLinks(self):
5809 try:
5810 if self._textColorToLink:
5811 pass
5812 except AttributeError:
5813 self._textColorToLink=False
5814 return self._textColorToLink
5816 def setTextColorToLinks(self, v):
5817 self._textColorToLink=v
5819 def getStartDate(self):
5820 return self.startDate
5822 def getAdjustedStartDate(self,tz=None):
5823 if not tz:
5824 tz = self.getConference().getTimezone()
5825 if tz not in all_timezones:
5826 tz = 'UTC'
5827 return self.startDate.astimezone(timezone(tz))
5829 def verifyStartDate(self, sdate, check=2):
5830 """check parameter:
5831 0: no check at all
5832 1: check and raise error in case of problem (default)
5833 2: check and adapt the owner dates
5836 conf=self.getConference()
5838 if conf is not None and sdate < conf.getSchedule().getStartDate():
5839 if check==1:
5840 raise ParentTimingError( _("The session starting date cannot be prior to the event starting date"), _("Session"))
5841 elif check==2:
5842 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
5843 conf, sdate.astimezone(timezone(conf.getTimezone()))))
5844 conf.setStartDate(sdate,check=0,moveEntries=0)
5846 def setStartDate(self,newDate,check=2,moveEntries=0):
5848 moveEntries parameter:
5849 0: do not move inner slots
5850 1: move
5851 2: do not move but check that session is not out of the conference dates
5854 if not newDate.tzname():
5855 raise MaKaCError("date should be timezone aware")
5856 if check != 0:
5857 self.verifyStartDate(newDate,check)
5858 oldSdate = self.getStartDate()
5859 try:
5860 tz = str(self.getStartDate().tzinfo)
5861 except:
5862 tz = 'UTC'
5863 diff = newDate - oldSdate
5864 self.startDate=copy.copy(newDate)
5865 if moveEntries == 1 and diff is not None and diff != timedelta(0):
5866 # If the start date changed, we move entries inside the timetable
5867 newDateTz = newDate.astimezone(timezone(tz))
5868 if oldSdate.astimezone(timezone(tz)).date() != newDateTz.date():
5869 entries = self.getSchedule().getEntries()[:]
5870 else:
5871 entries = self.getSchedule().getEntriesOnDay(newDateTz)[:]
5872 self.getSchedule().moveEntriesBelow(diff, entries)
5874 if moveEntries != 0 and self.getConference() and \
5875 not self.getConference().getEnableSessionSlots() and \
5876 self.getSlotList() != [] and \
5877 self.getSlotList()[0].getStartDate() != newDate:
5878 self.getSlotList()[0].startDate = newDate
5880 if check == 1:
5881 self._checkInnerSchedule()
5882 self.notifyModification()
5884 def _checkInnerSchedule( self ):
5885 self.getSchedule().checkSanity()
5887 def getEndDate(self):
5888 return self.startDate+self.duration
5890 ####################################
5891 # Fermi timezone awareness #
5892 ####################################
5894 def getAdjustedEndDate(self,tz=None):
5895 return self.getAdjustedStartDate(tz) + self.duration
5897 ####################################
5898 # Fermi timezone awareness(end) #
5899 ####################################
5901 def verifyEndDate(self, edate,check=1):
5902 """check parameter:
5903 0: no check at all
5904 1: check and raise error in case of problem
5905 2: check and adapt the owner dates
5907 try:
5908 tz = timezone(self.getConference().getTimezone())
5909 except:
5910 tz = timezone('UTC')
5911 # compare end date with start date
5912 if edate<=self.getStartDate():
5913 if check == 1:
5914 raise MaKaCError( _("End date cannot be prior to the Start date"), _("Session"))
5915 if check == 2:
5916 self.setStartDate(edate)
5917 # check conference dates
5918 if (self.getConference()):
5919 conf=self.getConference()
5920 confStartDate = conf.getSchedule().getStartDate()
5921 confEndDate = conf.getSchedule().getEndDate()
5922 if conf is not None and (edate>confEndDate or edate<=confStartDate):
5923 if check==1:
5924 raise ParentTimingError( _("The end date has to be between the event dates (%s - %s)")%\
5925 (confStartDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
5926 confEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
5927 _("Session"))
5928 if check==2:
5929 if edate>confEndDate:
5930 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
5931 self.getConference(),
5932 edate.astimezone(tz)))
5933 self.getConference().setEndDate(edate)
5934 if edate<=confStartDate:
5935 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
5936 self.getConference(),
5937 edate.astimezone(tz)))
5938 self.getConference().setStartDate(edate)
5939 # check inner schedule
5940 if len(self.getSlotList()) != 0 and self.getSlotList()[-1].getSchedule().hasEntriesAfter(edate):
5941 raise TimingError( _("Cannot change end date: some entries in the session schedule end after the new date"), _("Session"))
5943 def setEndDate(self,newDate,check=2):
5944 if not newDate.tzname():
5945 raise MaKaCError("date should be timezone aware")
5946 if check != 0:
5947 self.verifyEndDate(newDate,check)
5948 self.duration=newDate-self.getStartDate()
5949 # A session is not always linked to a conference (for eg. at creation time)
5950 #if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSlotList()[0].getEndDate() != newDate:
5951 # self.getSlotList()[0].duration = self.duration
5952 self.notifyModification()
5954 def setDates(self,sDate,eDate,check=1,moveEntries=0):
5955 if eDate<=sDate:
5956 tz = timezone(self.getConference().getTimezone())
5957 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"))
5958 self.setStartDate(sDate,check,moveEntries)
5959 self.setEndDate(eDate,check)
5960 self._checkInnerSchedule()
5962 def getDuration( self ):
5963 return self.duration
5965 def setDuration(self,hours=0,minutes=15,dur=0):
5966 if dur==0:
5967 dur = timedelta(hours=int(hours),minutes=int(minutes))
5968 if dur.seconds <= 0:
5969 raise MaKaCError( _("The duration cannot be less than zero"), _("Session"))
5970 self.duration = dur
5971 self.verifyEndDate(self.getEndDate())
5972 self.notifyModification()
5974 def getStartOnDay(self, day, tz=None):
5975 if not tz:
5976 tz = self.getConference().getTimezone()
5977 if type(day) is datetime:
5978 day = day.astimezone(timezone(tz))
5979 if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() :
5980 return None
5981 minTime = self.getEndDate()
5982 for e in self.getSchedule().getEntriesOnDay(day) :
5983 if e.getStartDate() < minTime :
5984 minTime = e.getStartDate()
5985 if minTime == self.getEndDate() :
5986 minTime = day.replace(hour=8, minute=0)#datetime.combine(day,time(hour=8, minute=0))
5987 if minTime < self.getStartDate() :
5988 return self.getStartDate()
5989 return minTime
5991 def getEndOnDay(self, day, tz=None):
5992 if not tz:
5993 tz = self.getConference().getTimezone()
5994 if type(day) is datetime:
5995 day = day.astimezone(timezone(tz))
5996 if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() :
5997 return None
5998 maxTime = self.getStartDate();
5999 for e in self.getSchedule().getEntriesOnDay(day) :
6000 if e.getEndDate() > maxTime :
6001 maxTime = e.getEndDate()
6002 if maxTime == self.getStartDate() :
6003 maxTime = day.replace(hour=19, minute=0)#datetime.combine(day,time(19,0))
6004 if maxTime > self.getEndDate() :
6005 return self.getEndDate()
6006 return maxTime
6008 def getLocationParent( self ):
6010 Returns the object from which the room/location
6011 information should be inherited
6013 return self.getConference()
6015 def getLocationList(self):
6016 """Method returning a list of "location" objects which contain the
6017 information about the different places the conference is gonna
6018 happen
6020 return self.places
6022 def addLocation(self, newPlace):
6023 self.places.append( newPlace )
6024 self.notifyModification()
6026 def _resetConveners(self):
6027 try:
6028 if self._conveners:
6029 return
6030 except AttributeError:
6031 self._conveners=[]
6032 for oc in self.conveners:
6033 newConv=SessionChair()
6034 newConv.setDataFromAvatar(oc)
6035 self._addConvener(newConv)
6037 def getConvenerList(self):
6038 self._resetConveners()
6039 return self._conveners
6041 def _addConvener(self,newConv):
6042 if newConv in self._conveners:
6043 return
6044 try:
6045 if self._convenerGen:
6046 pass
6047 except AttributeError:
6048 self._convenerGen=Counter()
6049 id = newConv.getId()
6050 if id == "":
6051 id=int(self._convenerGen.newCount())
6052 newConv.includeInSession(self,id)
6053 self._conveners.append(newConv)
6054 self.notifyModification()
6056 def addConvener(self,newConv):
6057 self._resetConveners()
6058 self._addConvener(newConv)
6059 if isinstance(newConv, MaKaC.user.Avatar):
6060 conv.unlinkTo(self, "convener")
6062 def removeConvener(self,conv):
6063 self._resetConveners()
6064 if conv not in self._conveners:
6065 return
6066 #--Pending queue: remove pending Convener waiting to became manager if anything
6067 self.getConference().getPendingQueuesMgr().removePendingManager(conv)
6069 #--Pending queue: remove pending Convener waiting to became coordinator if anything
6070 self.getConference().getPendingQueuesMgr().removePendingCoordinator(conv)
6072 self._conveners.remove(conv)
6073 if isinstance(conv, MaKaC.user.Avatar):
6074 conv.linkTo(self, "convener")
6075 conv.delete()
6076 self.notifyModification()
6078 def recoverConvener(self, con):
6079 self.addConvener(con)
6080 con.recover()
6082 def getConvenerById(self,id):
6083 id=int(id)
6084 for conv in self._conveners:
6085 if conv.getId()==id:
6086 return conv
6087 return None
6089 def getConvenerText( self ):
6090 #to be removed
6091 try:
6092 if self.convenerText:
6093 pass
6094 except AttributeError, e:
6095 self.convenerText = ""
6096 return self.convenerText
6098 def setConvenerText( self, newText ):
6099 self.convenerText = newText.strip()
6101 def appendConvenerText( self, newText ):
6102 self.setConvenerText( "%s, %s"%(self.getConvenerText(), newText.strip()) )
6104 def addContribution(self, newContrib, id=None):
6105 """Registers the contribution passed as parameter within the session
6106 assigning it a unique id.
6108 if self.hasContribution(newContrib):
6109 return
6110 self.getConference().addContribution(newContrib,id)
6111 self.contributions[newContrib.getId()]=newContrib
6112 newContrib.setSession(self)
6113 self.notifyModification()
6115 def hasContribution(self,contrib):
6116 return contrib.getSession()==self and \
6117 self.contributions.has_key(contrib.getId())
6119 def removeContribution(self,contrib):
6120 """Removes the indicated contribution from the session
6122 if not self.hasContribution(contrib):
6123 return
6124 if contrib.isScheduled():
6125 # unschedule the contribution
6126 sch=contrib.getSchEntry().getSchedule()
6127 sch.removeEntry(contrib.getSchEntry())
6128 del self.contributions[contrib.getId()]
6129 contrib.setSession(None)
6131 self.notifyModification()
6133 def newContribution( self, params = None, id=None ):
6134 c = Contribution()
6135 if params:
6136 c.setValues(params)
6137 self.addContribution( c, id )
6138 return c
6140 def getContributionById(self,id):
6141 id=str(id).strip()
6142 if self.contributions.has_key( id ):
6143 return self.contributions[ id ]
6144 return None
6146 def getContributionList( self ):
6147 return self.contributions.values()
6149 def getNumberOfContributions( self ):
6150 return len(self.contributions)
6152 def canIPAccess( self, ip ):
6153 if not self.__ac.canIPAccess( ip ):
6154 return False
6155 if self.getOwner() != None:
6156 return self.getOwner().canIPAccess(ip)
6157 return True
6159 def isProtected( self ):
6160 # tells if a session is protected or not
6161 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
6163 def getAccessProtectionLevel( self ):
6164 return self.__ac.getAccessProtectionLevel()
6166 def isItselfProtected( self ):
6167 return self.__ac.isItselfProtected()
6169 def hasAnyProtection( self ):
6170 """Tells whether a session has any kind of protection over it:
6171 access or domain protection.
6173 if self.__ac.isProtected():
6174 return True
6175 if self.getDomainList():
6176 return True
6177 if self.getAccessProtectionLevel() == -1:
6178 return False
6180 return self.getOwner().hasAnyProtection()
6182 def hasProtectedOwner( self ):
6183 if self.getOwner() != None:
6184 return self.getOwner().isProtected()
6185 return False
6187 def setProtection( self, private ):
6188 self.__ac.setProtection( private )
6189 self.updateFullyPublic()
6191 def grantAccess( self, prin ):
6192 self.__ac.grantAccess( prin )
6193 if isinstance(prin, MaKaC.user.Avatar):
6194 prin.linkTo(self, "access")
6196 def revokeAccess( self, prin ):
6197 self.__ac.revokeAccess( prin )
6198 if isinstance(prin, MaKaC.user.Avatar):
6199 prin.unlinkTo(self, "access")
6201 def canView( self, aw ):
6202 """tells whether the specified user has access to the current object
6203 or any of its sub-objects
6205 if self.canAccess( aw ):
6206 return True
6207 ### TODO: Replace this code when plugins allow extension points+notifications ##################
6208 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
6209 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
6210 RCCollaborationPluginAdmin.hasRights(user = aw.getUser(), plugins = "any"):
6211 return True
6212 ################################################################################################
6213 for contrib in self.getContributionList():
6214 if contrib.canView( aw ):
6215 return True
6216 return False
6218 def isAllowedToAccess( self, user ):
6219 if not user:
6220 return False
6221 if user in self.getCoordinatorList() or self.__ac.canUserAccess( user ) \
6222 or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess(user)):
6223 return True
6224 return False
6226 def canAccess( self, aw ):
6227 # Allow harvesters (Invenio, offline cache) to access
6228 # protected pages
6229 if self.__ac.isHarvesterIP(aw.getIP()):
6230 return True
6231 #####################################################
6233 if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ):
6234 return False
6235 if not self.isProtected():
6236 return True
6237 flag = self.isAllowedToAccess( aw.getUser() )
6238 return flag or self.conference.canKeyAccess( aw )
6240 def grantModification( self, sb, sendEmail=True ):
6241 if isinstance(sb, SessionChair):
6242 ah = AvatarHolder()
6243 results=ah.match({"email":sb.getEmail()}, exact=1)
6244 r=None
6245 for i in results:
6246 if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]:
6248 break
6249 if r is not None and r.isActivated():
6250 self.__ac.grantModification( r )
6251 r.linkTo(self, "manager")
6252 elif sb.getEmail() != "":
6253 modificationEmailGranted = self.__ac.grantModificationEmail(sb.getEmail())
6254 if modificationEmailGranted and sendEmail:
6255 notif = pendingQueues._PendingManagerNotification( [sb] )
6256 mail.GenericMailer.sendAndLog( notif, self.getConference() )
6257 else:
6258 self.__ac.grantModification( sb )
6259 if isinstance(sb, MaKaC.user.Avatar):
6260 sb.linkTo(self, "manager")
6262 def revokeModification( self, prin ):
6263 self.__ac.revokeModification( prin )
6264 if isinstance(prin, MaKaC.user.Avatar):
6265 prin.unlinkTo(self, "manager")
6267 def canModify( self, aw ):
6268 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
6270 def canUserModify( self, av ):
6271 """Tells whether a user is allowed to modify the current session:
6272 only if the user is granted to modify the session or the user
6273 can modify the corresponding conference.
6275 return self.getConference().canUserModify( av ) or self.__ac.canModify( av )
6277 def getManagerList( self ):
6278 return self.__ac.getModifierList()
6280 def getAllowedToAccessList( self ):
6281 return self.__ac.getAccessList()
6283 def addMaterial( self, newMat ):
6284 newMat.setId( str(self.__materialGenerator.newCount()) )
6285 newMat.setOwner( self )
6286 self.materials[ newMat.getId() ] = newMat
6287 self.notifyModification()
6289 def removeMaterial( self, mat ):
6290 if mat.getId() in self.materials.keys():
6291 self.materials[mat.getId()].setOwner(None)
6292 del self.materials[ mat.getId() ]
6293 mat.delete()
6294 self.notifyModification()
6295 return "done: %s"%mat.getId()
6296 elif mat.getId().lower() == 'minutes':
6297 self.removeMinutes()
6298 return "done: %s"%mat.getId()
6299 return "not done: %s"%mat.getId()
6301 def recoverMaterial(self, recMat):
6302 # Id must already be set in recMat.
6303 recMat.setOwner( self )
6304 self.materials[ recMat.getId() ] = recMat
6305 recMat.recover()
6306 self.notifyModification()
6308 def getMaterialRegistry(self):
6310 Return the correct material registry for this type
6312 from MaKaC.webinterface.materialFactories import SessionMFRegistry
6313 return SessionMFRegistry
6315 def getMaterialById( self, matId ):
6316 if matId.lower() == 'minutes':
6317 return self.getMinutes()
6318 elif self.materials.has_key(matId):
6319 return self.materials[ matId ]
6320 return None
6322 def getMaterialList( self ):
6323 return self.materials.values()
6325 def getAllMaterialList( self ):
6326 l = self.getMaterialList()
6327 if self.getMinutes():
6328 l.append( self.getMinutes() )
6329 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
6330 return l
6332 def _setSchedule(self):
6333 self.__schedule=SessionSchedule(self)
6334 sl=self.getSlotList()
6335 for slot in self.getSlotList():
6336 self.__schedule.addEntry(slot.getSchEntry())
6338 def getSchedule( self ):
6339 try:
6340 if self.__schedule is None or not isinstance(self.__schedule,SessionSchedule):
6341 self._setSchedule()
6342 except AttributeError, e:
6343 self._setSchedule()
6344 return self.__schedule
6346 def getMasterSchedule( self ):
6347 return self.getOwner().getSchedule()
6349 def requireDomain( self, dom ):
6350 self.__ac.requireDomain( dom )
6352 def freeDomain( self, dom ):
6353 self.__ac.freeDomain( dom )
6355 def getDomainList( self ):
6356 return self.__ac.getRequiredDomainList()
6358 def setComments(self,comm):
6359 self._comments = comm.strip()
6361 def getComments(self):
6362 try:
6363 if self._comments:
6364 pass
6365 except AttributeError,e:
6366 self._comments=""
6367 return self._comments
6369 def createMinutes( self ):
6370 if self.getMinutes() != None:
6371 raise MaKaCError( _("The minutes for this session have already been created"), _("Session"))
6372 self.minutes = Minutes()
6373 self.minutes.setOwner( self )
6374 self.notifyModification()
6375 return self.minutes
6377 def removeMinutes( self ):
6378 if self.minutes is None:
6379 return
6380 self.minutes.delete()
6381 self.minutes.setOwner( None )
6382 self.minutes = None
6383 self.notifyModification()
6385 def recoverMinutes(self, min):
6386 self.removeMinutes() # To ensure that the current minutes are put in
6387 # the trash can.
6388 self.minutes = min
6389 self.minutes.setOwner( self )
6390 min.recover()
6391 self.notifyModification()
6392 return self.minutes
6394 def getMinutes( self ):
6395 #To be removed
6396 try:
6397 if self.minutes:
6398 pass
6399 except AttributeError, e:
6400 self.minutes = None
6402 return self.minutes
6404 def _addCoordinator(self, av):
6405 if av is None or self._coordinators.has_key(av.getId()):
6406 return
6407 self._coordinators[av.getId()]=av
6408 if self.getConference() is not None:
6409 self.getConference().addSessionCoordinator(self,av)
6411 def getCoordinatorEmailList(self):
6412 try:
6413 return self._coordinatorsEmail
6414 except:
6415 self._coordinatorsEmail = []
6416 return self._coordinatorsEmail
6418 def _addCoordinatorEmail(self, email):
6419 if not email in self.getCoordinatorEmailList():
6420 self.getCoordinatorEmailList().append(email)
6422 def removeCoordinatorEmail(self, email):
6423 if email in self.getCoordinatorEmailList():
6424 if email in self.getCoordinatorEmailList():
6425 self.getCoordinatorEmailList().remove(email)
6426 self._p_changed = 1
6428 def addCoordinator( self, sb, sendEmail=True ):
6429 """Grants coordination privileges to user.
6431 Arguments:
6432 sb -- It can be either:
6433 (MaKaC.user.Avatar) the user to which
6434 coordination privileges must be granted.
6436 (MaKaC.conference.SessionChair) a non-existing which
6437 has to become indico user before to be granted with privileges.
6439 try:
6440 if self._coordinators:
6441 pass
6442 except AttributeError, e:
6443 self._coordinators=OOBTree()
6445 if isinstance(sb, SessionChair):
6446 ah = AvatarHolder()
6447 results=ah.match({"email":sb.getEmail()}, exact=1)
6448 r=None
6450 for i in results:
6451 if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]:
6453 break
6455 if r is not None and r.isActivated():
6457 self._addCoordinator(r)
6458 r.linkTo(self, "coordinator")
6459 else:
6460 self.getConference().getPendingQueuesMgr().addPendingCoordinator(sb)
6461 else:
6462 self._addCoordinator(sb)
6463 if isinstance(sb, MaKaC.user.Avatar):
6464 sb.linkTo(self, "coordinator")
6466 def removeCoordinator( self, av ):
6467 """Revokes coordination privileges to user.
6469 Arguments:
6470 av -- (MaKaC.user.Avatar) user for which coordination privileges
6471 must be revoked
6473 try:
6474 if self._coordinators:
6475 pass
6476 except AttributeError, e:
6477 self._coordinators=OOBTree()
6479 if av is None or not self._coordinators.has_key(av.getId()):
6480 return
6481 del self._coordinators[av.getId()]
6482 if isinstance(av, MaKaC.user.Avatar):
6483 av.unlinkTo(self, "coordinator")
6484 if self.getConference() is not None:
6485 self.getConference().removeSessionCoordinator(self,av)
6487 def isCoordinator( self, av ):
6488 """Tells whether the specified user is a coordinator of the session.
6490 Arguments:
6491 av -- (MaKaC.user.Avatar) user to be checked
6493 Return value: (boolean)
6495 try:
6496 if self._coordinators:
6497 pass
6498 except AttributeError, e:
6499 self._coordinators=OOBTree()
6500 if (av is not None) and self._coordinators.has_key(av.getId()):
6501 return True
6502 ret = False
6503 if isinstance(av, MaKaC.user.Avatar):
6504 for email in av.getEmails():
6505 if email in self.getCoordinatorEmailList():
6506 self.addCoordinator(av)
6507 self.removeCoordinatorEmail(email)
6508 ret = True
6509 return ret
6512 def getCoordinatorList( self ):
6513 """Return all users which have privileges to coordinate the session.
6515 Return value: (list)
6517 try:
6518 if self._coordinators:
6519 pass
6520 except AttributeError, e:
6521 self._coordinators=OOBTree()
6523 return self._coordinators.values()
6525 def canCoordinate(self,aw, right=""):
6526 """Tells if a user has coordination privileges.
6528 Only session coordinators have coordination privileges over a
6529 session.
6531 Params:
6532 aw -- (MaKaC.accessControl.AccessWrapper) User access
6533 information for which the coordination privileges must be
6534 checked.
6536 Return value: (boolean)
6538 if right != "":
6539 return self.isCoordinator(aw.getUser()) and self.getConference().hasSessionCoordinatorRight(right)
6540 return self.isCoordinator(aw.getUser())
6543 def getScheduleType(self):
6544 try:
6545 if self._ttType:
6546 pass
6547 except AttributeError:
6548 self._ttType=SlotSchTypeFactory.getDefaultId()
6549 return self._ttType
6551 def setScheduleType(self,t):
6552 try:
6553 if self._ttType:
6554 pass
6555 except AttributeError:
6556 self._ttType=SlotSchTypeFactory.getDefaultId()
6557 t=str(t).strip().lower()
6558 if t not in SlotSchTypeFactory.getIdList() or t==self._ttType:
6559 return
6560 self._ttType=t
6561 for slot in self.getSlotList():
6562 slot.setScheduleType(t)
6564 def getAccessController(self):
6565 return self.__ac
6568 def _cmpTitle( s1, s2 ):
6569 s1=s1.getTitle().lower().strip()
6570 s2=s2.getTitle().lower().strip()
6571 return cmp( s1, s2 )
6572 _cmpTitle=staticmethod(_cmpTitle)
6574 class SessionSlot(Persistent, Fossilizable, Locatable):
6576 fossilizes(ISessionSlotFossil)
6578 def __init__(self,session,**sessionSlotData):
6579 self.session = session
6580 self.id = "not assigned"
6581 self.title = ""
6582 self.startDate=None
6583 self.duration = timedelta(minutes=1)
6584 self.places = []
6585 self.rooms = []
6586 self._conveners = []
6587 self._convenerGen=Counter()
6588 self._schedule=SlotSchTypeFactory.getDefaultKlass()(self)
6589 self._sessionSchEntry=LinkedTimeSchEntry(self)
6590 self._confSchEntry=LinkedTimeSchEntry(self)
6591 self._contributionDuration = None
6593 def getTimezone( self ):
6594 return self.getConference().getTimezone()
6596 def getLogInfo(self):
6597 data = {}
6598 data["id"] = self.id
6599 data["title"] = self.title
6600 data["session"] = self.session.getTitle()
6601 data["start date"] = self.startDate
6602 data["duration"] = self.duration
6603 i = 0
6604 for p in self.places :
6605 data["place %s"%i] = p.getName()
6606 i+=1
6607 i = 0
6608 for r in self.rooms :
6609 data["room %s"%i] = r.getName()
6610 i+=1
6611 for c in self._conveners :
6612 data["convener %s"%c.getId()] = c.getFullName()
6613 return data
6615 def clone(self,session, options):
6617 slot = SessionSlot(session)
6618 slot.session = session
6619 slot.setTitle(self.getTitle())
6620 timeDifference = session.getConference().getStartDate() - self.getSession().getConference().getStartDate()
6621 slot.setStartDate(self.getStartDate() + timeDifference)
6622 slot.setDuration(dur=self.getDuration(), check=2)
6624 #places
6625 if self.getOwnLocation() is not None:
6626 slot.setLocation(self.getOwnLocation().clone())
6627 #rooms
6628 if self.getOwnRoom() is not None:
6629 slot.setRoom(self.getOwnRoom().clone())
6631 #chairs = conveners
6632 for ch in self.getOwnConvenerList() :
6633 slot.addConvener(ch.clone())
6635 #populate the timetable
6636 if options.get("contributions", False) :
6637 for entry in self.getEntries() :
6638 if isinstance(entry, BreakTimeSchEntry) :
6639 newentry = entry.clone(slot)
6640 slot.getSchedule().addEntry(newentry,0)
6641 elif isinstance(entry, ContribSchEntry) :
6642 contrib = entry.getOwner()
6643 newcontrib = contrib.clone(session, options, timeDifference)
6644 slot.getSchedule().addEntry(newcontrib.getSchEntry(),0)
6646 slot.setContribDuration(0, 0, self.getContribDuration())
6647 slot.notifyModification()
6649 return slot
6651 def fit( self ):
6653 sets the start date of the slot to the start date of the first son
6654 and the end date to the end date of the last son
6656 sch = self.getSchedule()
6657 entries = sch.getEntries()
6658 if len(entries) > 0:
6659 self.setStartDate(entries[0].getStartDate(),0,0)
6660 self.setEndDate(sch.calculateEndDate(), check=0)
6662 def recalculateTimes( self, type, diff ):
6664 recalculate and reschedule the contributions of the session slot with a time "diff" of separation.
6666 if type=="duration":
6667 entries = self.getSchedule().getEntries()[:]
6669 while i<len(entries):
6670 entry=entries[i]
6671 if i+1 == len(entries):
6672 dur=self.getEndDate()-entry.getStartDate()
6673 else:
6674 nextentry=entries[i+1]
6675 dur=nextentry.getStartDate()-entry.getStartDate()-diff
6676 if dur<timedelta(0):
6677 raise EntryTimingError( _("""With the time between entries you've chosen, the entry "%s" will have a duration less than zero minutes. Please, choose another time""")%entry.getTitle())
6678 entry.setDuration(dur=dur)
6679 i+=1
6680 if len(entries) != 0 and self.getEndDate() < entry.getEndDate():
6681 self.setEndDate(entry.getEndDate(),2)
6682 elif type=="startingTime":
6683 st = self.getStartDate()
6684 entries = self.getSchedule().getEntries()[:]
6685 for entry in entries:
6686 entry.setStartDate(st,0,0)
6687 # add diff to last item end date if and only if the item is
6688 # not a break
6689 #if not isinstance(entry, BreakTimeSchEntry):
6690 # st=entry.getEndDate()+diff
6691 #else:
6692 # st=entry.getEndDate()
6693 st=entry.getEndDate()+diff
6694 if len(entries) != 0 and self.getEndDate() < st:
6695 self.setEndDate(st,2)
6697 def setValues(self,data,check=2, moveEntriesBelow=0):
6698 """check parameter:
6699 0: no check at all
6700 1: check and raise error in case of problem
6701 2: check and adapt the owner dates
6704 # In order to move the entries below, it is needed to know the diff (we have to move them)
6705 # and the list of entries to move. It's is needed to take those datas in advance because they
6706 # are going to be modified before the moving.
6707 if moveEntriesBelow == 1:
6708 oldStartDate=copy.copy(self.getStartDate())
6709 oldDuration=copy.copy(self.getDuration())
6710 i=self.getConfSchEntry().getSchedule().getEntries().index(self.getConfSchEntry())+1
6711 entriesList = self.getConfSchEntry().getSchedule().getEntries()[i:]
6712 self.title=data.get("title", _("NO TITLE ASSIGNED"))
6713 # Do we move all entries in the slot
6714 move = int(data.get("move",0))
6716 if "locationName" in data:
6717 loc = self.getOwnLocation()
6718 if not loc:
6719 loc = CustomLocation()
6720 self.setLocation( loc )
6721 loc.setName( data["locationName"] )
6722 loc.setAddress( data.get("locationAddress", "") )
6723 else:
6724 self.setLocation( None )
6726 if "roomName" in data:
6727 room = self.getOwnRoom()
6728 if not room:
6729 room = CustomRoom()
6730 self.setRoom( room )
6731 room.setName( data["roomName"] )
6732 else:
6733 self.setRoom( None )
6734 sDate = eDate = None
6735 confTZ = self.getOwner().getConference().getTimezone()
6736 if data.get("sDate",None) is not None:
6737 sd = data.get("sDate")
6738 sDate = timezone(confTZ).localize(datetime(sd.year,sd.month,sd.day,sd.hour,sd.minute))
6739 elif data.get("sYear","")!="" and data.get("sMonth","")!="" and \
6740 data.get("sDay","")!="" and data.get("sHour","")!="" and \
6741 data.get("sMinute","")!="":
6742 sDate = timezone(confTZ).localize(datetime(int(data["sYear"]),int(data["sMonth"]),
6743 int(data["sDay"]),int(data["sHour"]),
6744 int(data["sMinute"])))
6745 if data.get("eDate",None) is not None:
6746 ed = data.get("eDate")
6747 eDate = timezone(confTZ).localize(datetime(ed.year,ed.month,ed.day,ed.hour,ed.minute))
6748 elif data.get("eYear","")!="" and data.get("eMonth","")!="" and \
6749 data.get("eDay","")!="" and data.get("eHour","")!="" and \
6750 data.get("eMinute","")!="":
6751 eDate = timezone(confTZ).localize(datetime(int(data["eYear"]),int(data["eMonth"]),
6752 int(data["eDay"]),int(data["eHour"]),
6753 int(data["eMinute"])))
6754 if sDate != None and eDate != None:
6755 sDateUTC = sDate.astimezone(timezone('UTC'))
6756 eDateUTC = eDate.astimezone(timezone('UTC'))
6757 self.setDates(sDateUTC,eDateUTC,check,moveEntries=move)
6758 elif sDate != None:
6759 sDateUTC = sDate.astimezone(timezone('UTC'))
6760 self.setStartDate(sDateUTC,check,moveEntries=move)
6761 if data.get("durHours","")!="" and data.get("durMins","")!="":
6762 self.setDuration(hours=data["durHours"],minutes=data["durMins"],check=check)
6763 if data.get("contribDurHours","")!="" and data.get("contribDurMins","")!="":
6764 self.setContribDuration(int(data["contribDurHours"]),int(data["contribDurMins"]))
6765 elif data.get("contribDuration","")!="":
6766 self.setContribDuration(dur=data.get("contribDuration"))
6767 else:
6768 self.setContribDuration(None,None)
6769 conveners = data.get("conveners",None)
6770 if conveners is not None:
6771 self.clearConvenerList()
6772 for conv in conveners:
6773 sc = SlotChair()
6774 sc.setTitle(conv.getTitle())
6775 sc.setFirstName(conv.getFirstName())
6776 sc.setFamilyName(conv.getFamilyName())
6777 sc.setAffiliation(conv.getAffiliation())
6778 sc.setEmail(conv.getEmail())
6779 self.addConvener(sc)
6780 if moveEntriesBelow == 1:
6781 diff = (self.getStartDate() - oldStartDate) + (self.getDuration() - oldDuration)
6782 self.getSchedule().moveEntriesBelow(diff, entriesList)
6783 self._checkInnerSchedule()
6784 self.notifyModification()
6786 def _checkInnerSchedule( self ):
6787 self.getSchedule().checkSanity()
6789 def setContribDuration(self, hour=0, min=0, dur=None):
6790 self._contributionDuration = None
6791 if dur is not None:
6792 self._contributionDuration=dur
6793 elif hour != None and min != None:
6794 self._contributionDuration = timedelta(hours=hour,minutes=min)
6796 def getContribDuration(self):
6798 Duration by default for contributions within the slots.
6800 try:
6801 if self._contributionDuration:
6802 pass
6803 except AttributeError, e:
6804 self._contributionDuration = None
6805 return self._contributionDuration
6807 def notifyModification( self ):
6808 self.getSession().notifyModification()
6809 self._p_changed = 1
6811 def getLocator( self ):
6812 l=self.getSession().getLocator()
6813 l["slotId"]=self.getId()
6814 return l
6816 def getConference( self ):
6817 return self.getSession().getConference()
6819 def getSession(self):
6820 return self.session
6822 def getOwner( self ):
6823 return self.session
6825 def _setSchedule(self,klass):
6826 old_sch=self.getSchedule()
6827 self._schedule=klass(self)
6828 #after removing old entries, one could try to fit them into the new
6829 # schedule, but there are several things to consider which are left
6830 # for later implementation (breaks, entries not fitting in the
6831 # slots,...)
6832 while len(old_sch.getEntries())>0:
6833 entry=old_sch.getEntries()[0]
6834 old_sch.removeEntry(entry)
6835 self.notifyModification()
6837 def getSchedule(self):
6838 return self._schedule
6840 def getMasterSchedule( self ):
6841 return self.getOwner().getSchedule()
6843 def getConfSchEntry( self ):
6844 try:
6845 if self._confSchEntry:
6846 pass
6847 except AttributeError:
6848 self._confSchEntry=LinkedTimeSchEntry(self)
6849 return self._confSchEntry
6851 def getSessionSchEntry( self ):
6852 try:
6853 if self._sessionSchEntry:
6854 pass
6855 except AttributeError:
6856 self._sessionSchEntry=self._schEntry
6857 return self._sessionSchEntry
6859 def setId( self, newId ):
6860 self.id=str(newId)
6861 self.notifyModification()
6863 def getId( self ):
6864 return self.id
6866 def setTitle( self, newTitle ):
6867 self.title=newTitle
6868 self.notifyModification()
6870 def getTitle( self ):
6871 try:
6872 if self.title:
6873 pass
6874 except AttributeError,e:
6875 self.title=""
6876 return self.title
6878 def getName(self):
6879 return "slot %s"%self.getId()
6881 def getDescription(self):
6882 return self.getSession().getDescription()
6884 def setDates(self,sDate,eDate,check=2,moveEntries=0):
6885 """check parameter:
6886 0: no check at all
6887 1: check and raise error in case of problem
6888 2: check and adapt the owner dates"""
6890 if sDate>eDate:
6891 raise MaKaCError(_("End date cannot be prior to Start date"),_("Slot"))
6893 self.setStartDate(sDate, check, moveEntries, checkDuration=False)
6894 self.setDuration(0, 0, 0, eDate-sDate, check)
6895 self.notifyModification()
6897 def getEntries(self):
6898 entriesList = self.getSchedule().getEntries()
6899 return entriesList
6901 def move(self, sDate):
6902 diff=sDate-self.startDate
6903 self.startDate = sDate
6904 for slotEntry in self.getSchedule().getEntries():
6905 if isinstance(slotEntry, BreakTimeSchEntry):
6906 slotEntry.startDate = slotEntry.getStartDate() + diff
6907 else:
6908 se = slotEntry.getOwner()
6909 se.startDate = se.getStartDate() + diff
6910 self.getSchedule().reSchedule()
6912 def verifyStartDate(self, sDate,check=2):
6913 """check parameter:
6914 0: no check at all
6915 1: check and raise error in case of problem
6916 2: check and adapt the owner dates"""
6918 tz = timezone(self.getConference().getTimezone())
6920 if sDate < self.getSession().getStartDate():
6921 if check == 1:
6922 raise ParentTimingError(_("The slot \"%s\" cannot start (%s) before its parent session starts (%s)")%\
6923 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
6924 self.getSession().getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
6925 _("Slot"))
6926 elif check == 2:
6927 self.getSession().setStartDate(sDate, check, 0)
6929 def setStartDate(self,sDate,check=2,moveEntries=0,checkDuration=True):
6930 """check parameter:
6931 0: no check at all
6932 1: check and raise error in case of problem
6933 2: check and adapt the owner dates"""
6934 if sDate is None:
6935 return
6936 if not sDate.tzname():
6937 raise MaKaCError("date should be timezone aware")
6938 if check != 0:
6939 #If not using .fit() at the end of this method, comment it out
6940 #if self.getSession().getStartDate() > sDate:
6941 # self.getSession().duration += self.getSession().getStartDate() - sDate
6942 self.verifyStartDate(sDate,check)
6944 # calculate the difference betwwen old and new date
6945 difference = None
6946 if self.startDate is not None:
6947 difference = sDate - self.getStartDate()
6949 self.startDate=copy.copy(sDate)
6951 if difference != None and difference != timedelta(0) and moveEntries:
6952 ContextManager.get('autoOps').append((self, "ENTRIES_MOVED",
6953 self, sDate.astimezone(timezone(self.getTimezone()))))
6954 self.getSchedule().moveEntriesBelow(difference,self.getSchedule().getEntries()[:])
6956 if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getStartDate() != sDate:
6957 self.getSession().setStartDate(sDate, check, 0)
6958 if check != 0 and self.getSession() and checkDuration:
6959 self.verifyDuration(self.getDuration(), check=check)
6961 # synchronize with other timetables
6962 self.getSessionSchEntry().synchro()
6963 self.getConfSchEntry().synchro()
6964 self.getSession().fit()
6965 self.notifyModification()
6967 def setEndDate(self,eDate,check=2):
6968 if not eDate.tzname():
6969 raise MaKaCError("date should be timezone aware")
6970 if check != 0:
6971 self.verifyDuration(eDate-self.startDate, check)
6972 self.setDuration(dur=eDate-self.startDate,check=check)
6973 if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getEndDate() != eDate:
6974 self.getSession().setEndDate(eDate, check)
6975 self.getSession().fit()
6976 self.notifyModification()
6978 def getStartDate( self ):
6979 return self.startDate
6981 def getAdjustedStartDate(self,tz=None):
6982 if not tz:
6983 tz = self.getConference().getTimezone()
6984 if tz not in all_timezones:
6985 tz = 'UTC'
6986 return self.startDate.astimezone(timezone(tz))
6988 def getEndDate( self ):
6989 if self.startDate is None:
6990 return None
6991 return self.startDate+self.duration
6993 def getAdjustedEndDate( self, tz=None ):
6994 if not tz:
6995 tz = self.getConference().getTimezone()
6996 if tz not in all_timezones:
6997 tz = 'UTC'
6998 if self.getEndDate():
6999 return self.getEndDate().astimezone(timezone(tz))
7000 return None
7002 def getDuration( self ):
7003 return self.duration
7005 def isMoreThanDay(self):
7006 if self.getDuration() >= timedelta(days=1):
7007 return True
7008 return False
7010 def verifyDuration(self, dur, check=1):
7011 """check parameter:
7012 0: no check at all
7013 1: check and raise error in case of problem
7014 2: check and adapt the owner dates"""
7016 tz = timezone(self.getConference().getTimezone())
7017 if dur <= timedelta(0):
7018 raise MaKaCError( _("The duration cannot be less than zero"), _("Slot"))
7019 if dur.days > 1:
7020 raise MaKaCError( _("The duration cannot be more than one day"), _("Slot"))
7021 if self.startDate is not None:
7022 sessionStartDate = self.getSession().getStartDate()
7023 sessionEndDate = self.getSession().getEndDate()
7024 # end date has to be between the session dates
7025 eDate = self.startDate + dur
7026 if eDate > sessionEndDate:
7027 if check==1:
7028 raise EntryTimingError(_("The session slot cannot end (%s) after its parent session (%s)") \
7029 % (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7030 sessionEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7031 _("Slot"))
7032 elif check==2:
7033 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
7034 self.getSession(), eDate.astimezone(tz)))
7035 self.getSession().setEndDate(eDate,check)
7036 if eDate.astimezone(tz).date() > self.startDate.astimezone(tz).date():
7037 raise TimingError( _("The time slot must end on the same day it has started"), _("Slot"))
7038 # do not modify if slot entries will be affected
7039 sch = self.getSchedule()
7040 entries = sch.getEntries()
7041 if entries != []:
7042 if eDate < sch.calculateEndDate():
7043 raise TimingError(_("The session slot cannot end at (%s) because there is a contribution (%s) ending after that time. ")%\
7044 (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7045 sch.calculateEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7046 _("Slot"))
7048 def setDuration(self, days=0,hours=0,minutes=0,dur=0,check=1):
7049 """check parameter:
7050 0: no check at all
7051 1: check and raise error in case of problem
7052 2: check and adapt the owner dates"""
7054 if dur==0:
7055 dur = timedelta(days=int(days),hours=int(hours),minutes=int(minutes))
7056 if dur==0 and check==2:
7057 ContextManager.get('autoOps').append((self, "DURATION_SET",
7058 self, 1))
7059 dur = timedelta(minutes=1)
7060 if dur > timedelta(days=1) and check==2:
7061 pass#dur = timedelta(days=1)
7062 if check != 0:
7063 self.verifyDuration(dur, check)
7064 self.duration = dur
7065 self.getSessionSchEntry().synchro()
7066 self.getConfSchEntry().synchro()
7067 self.getSession().fit()
7068 self.notifyModification()
7070 def getLocationParent( self ):
7072 Returns the object from which the room/location
7073 information should be inherited
7075 return self.session
7077 def delete(self):
7078 self.getSchedule().clear()
7079 if self.getSession() is not None:
7080 self.getSession().removeSlot(self)
7081 self.session=None
7082 TrashCanManager().add(self)
7084 def recover(self):
7085 TrashCanManager().remove(self)
7087 def canAccess(self,aw):
7088 return self.getSession().canAccess(aw)
7090 def canView(self,aw):
7091 return self.getSession().canView(aw)
7093 def setScheduleType(self,id):
7094 id=str(id).strip().lower()
7095 currentId=SlotSchTypeFactory.getId(self.getSchedule())
7096 if id not in SlotSchTypeFactory.getIdList() or id==currentId:
7097 return
7098 self._setSchedule(SlotSchTypeFactory.getScheduleKlass(id))
7100 def getConvenerList(self):
7101 try:
7102 if self._conveners:
7103 pass
7104 except AttributeError:
7105 self._conveners = []
7106 if self._conveners == []:
7107 return self.getSession().getConvenerList()
7108 return self._conveners
7110 def addConvener(self,newConv):
7111 if newConv in self._conveners:
7112 return
7113 try:
7114 if self._convenerGen:
7115 pass
7116 except AttributeError:
7117 self._convenerGen=Counter()
7118 id = newConv.getId()
7119 if id == "":
7120 id=int(self._convenerGen.newCount())
7121 newConv.includeInSlot(self,id)
7122 self._conveners.append(newConv)
7123 self.notifyModification()
7125 def removeConvener(self,conv):
7126 if conv not in self._conveners:
7127 return
7128 self._conveners.remove(conv)
7129 conv.delete()
7130 self.notifyModification()
7132 def recoverConvener(self, con):
7133 self.addConvener(con)
7134 con.recover()
7136 def getConvenerById(self,id):
7137 id=int(id)
7138 for conv in self._conveners:
7139 if conv.getId()==id:
7140 return conv
7141 return None
7143 def getOwnConvenerList(self):
7144 try:
7145 if self._conveners:
7146 pass
7147 except AttributeError:
7148 self._conveners = []
7149 return self._conveners
7151 def clearConvenerList(self):
7152 while len(self.getOwnConvenerList()) > 0:
7153 self._conveners.pop()
7154 self.notifyModification()
7156 def getColor(self):
7157 res=""
7158 if self.getSession() is not None:
7159 res=self.getSession().getColor()
7160 return res
7162 def getTextColor(self):
7163 res=""
7164 if self.getSession() is not None:
7165 res=self.getSession().getTextColor()
7166 return res
7169 class ContributionParticipation(Persistent, Fossilizable):
7171 fossilizes(IContributionParticipationFossil, IContributionParticipationMinimalFossil,\
7172 IContributionParticipationTTDisplayFossil,\
7173 IContributionParticipationTTMgmtFossil)
7175 def __init__( self ):
7176 self._contrib = None
7177 self._id = ""
7178 self._firstName = ""
7179 self._surName = ""
7180 self._email = ""
7181 self._affiliation = ""
7182 self._address = ""
7183 self._phone = ""
7184 self._title = ""
7185 self._fax = ""
7187 def _notifyModification( self ):
7188 if self._contrib != None:
7189 self._contrib.notifyModification()
7191 def setValues(self, data):
7192 self.setFirstName(data.get("firstName", ""))
7193 self.setFamilyName(data.get("familyName",""))
7194 self.setAffiliation(data.get("affilation",""))
7195 self.setAddress(data.get("address",""))
7196 self.setEmail(data.get("email",""))
7197 self.setFax(data.get("fax",""))
7198 self.setTitle(data.get("title",""))
7199 self.setPhone(data.get("phone",""))
7200 self._notifyModification()
7202 def getValues(self):
7203 data={}
7204 data["firstName"]=self.getFirstName()
7205 data["familyName"]=self.getFamilyName()
7206 data["affilation"]=self.getAffiliation()
7207 data["address"]=self.getAddress()
7208 data["email"]=self.getEmail()
7209 data["fax"]=self.getFax()
7210 data["title"]=self.getTitle()
7211 data["phone"]=self.getPhone()
7212 return data
7214 def clone(self):
7215 part = ContributionParticipation()
7216 part.setValues(self.getValues())
7217 return part
7219 def setDataFromAvatar(self,av):
7220 # av is an Avatar object.
7221 if av is None:
7222 return
7223 self.setFirstName(av.getName())
7224 self.setFamilyName(av.getSurName())
7225 self.setEmail(av.getEmail())
7226 self.setAffiliation(av.getOrganisation())
7227 self.setAddress(av.getAddress())
7228 self.setPhone(av.getTelephone())
7229 self.setTitle(av.getTitle())
7230 self.setFax(av.getFax())
7231 self._notifyModification()
7233 def setDataFromOtherCP(self,cp):
7234 # cp is a ContributionParticipation object.
7235 if cp is None:
7236 return
7237 self.setFirstName(cp.getFirstName())
7238 self.setFamilyName(cp.getFamilyName())
7239 self.setEmail(cp.getEmail())
7240 self.setAffiliation(cp.getAffiliation())
7241 self.setAddress(cp.getAddress())
7242 self.setPhone(cp.getPhone())
7243 self.setTitle(cp.getTitle())
7244 self.setFax(cp.getFax())
7245 self._notifyModification()
7247 def includeInContribution( self, contrib, id ):
7248 if self.getContribution() == contrib and self.getId()==id.strip():
7249 return
7250 self._contrib = contrib
7251 self._id = id
7253 def delete( self ):
7254 self._contrib = None
7255 TrashCanManager().add(self)
7257 def recover(self):
7258 TrashCanManager().remove(self)
7260 def setId(self, newId):
7261 self._id = newId
7263 def getId( self ):
7264 return self._id
7266 def getContribution( self ):
7267 return self._contrib
7269 def getConference(self):
7270 return self._contrib.getConference()
7272 def getLocator(self):
7273 if self.getContribution() is None:
7274 return None
7275 loc=self.getContribution().getLocator()
7276 loc["authId"]=self.getId()
7277 return loc
7279 def _unindex(self):
7280 contrib=self.getContribution()
7281 if contrib is not None:
7282 conf=contrib.getConference()
7283 if conf is not None:
7284 conf.unindexAuthor(self)
7285 conf.unindexSpeaker(self)
7287 def _index(self):
7288 contrib=self.getContribution()
7289 if contrib is not None:
7290 conf=contrib.getConference()
7291 if conf is not None:
7292 conf.indexAuthor(self)
7293 conf.indexSpeaker(self)
7295 @Updates ('MaKaC.conference.ContributionParticipation', 'firstName')
7296 def setFirstName( self, newName ):
7297 tmp=newName.strip()
7298 if tmp==self._firstName:
7299 return
7300 self._unindex()
7301 self._firstName=tmp
7302 self._index()
7303 self._notifyModification()
7305 def getFirstName( self ):
7306 return self._firstName
7308 def getName( self ):
7309 return self._firstName
7312 @Updates ('MaKaC.conference.ContributionParticipation', 'familyName')
7313 def setFamilyName( self, newName ):
7314 tmp=newName.strip()
7315 if tmp==self._surName:
7316 return
7317 self._unindex()
7318 self._surName=tmp
7319 self._index()
7320 self._notifyModification()
7322 def getFamilyName( self ):
7323 return self._surName
7325 def getSurName( self ):
7326 return self._surName
7329 @Updates ('MaKaC.conference.ContributionParticipation', 'email')
7330 def setEmail( self, newMail ):
7331 tmp=newMail.strip()
7332 if tmp==self._email:
7333 return
7334 self._unindex()
7335 self._email=newMail.strip()
7336 self._index()
7337 self._notifyModification()
7339 def getEmail( self ):
7340 return self._email
7342 @Updates ('MaKaC.conference.ContributionParticipation', 'affiliation')
7343 def setAffiliation( self, newAffil ):
7344 self._affiliation = newAffil.strip()
7345 self._notifyModification()
7347 def getAffiliation( self ):
7348 if self._affiliation.lower() == "unknown":
7349 return ""
7350 return self._affiliation
7352 @Updates ('MaKaC.conference.ContributionParticipation', 'address')
7353 def setAddress( self, newAddr ):
7354 self._address = newAddr.strip()
7355 self._notifyModification()
7357 def getAddress( self ):
7358 return self._address
7360 @Updates ('MaKaC.conference.ContributionParticipation', 'telephone')
7361 def setPhone( self, newPhone ):
7362 self._phone = newPhone.strip()
7363 self._notifyModification()
7365 def getPhone( self ):
7366 return self._phone
7368 @Updates ('MaKaC.conference.ContributionParticipation', 'title')
7369 def setTitle( self, newTitle ):
7370 self._title = newTitle.strip()
7371 self._notifyModification()
7373 def getTitle( self ):
7374 return self._title
7376 @Updates ('MaKaC.conference.ContributionParticipation', 'fax')
7377 def setFax( self, newFax ):
7378 self._fax = newFax.strip()
7379 self._notifyModification()
7381 def getFax( self ):
7382 try:
7383 if self._fax:
7384 pass
7385 except AttributeError:
7386 self._fax=""
7387 return self._fax
7389 def getDirectFullName( self ):
7390 res = "%s %s"%( self.getFirstName(), self.getFamilyName().upper() )
7391 res=res.strip()
7392 if self.getTitle() != "":
7393 res = "%s %s"%( self.getTitle(), res )
7394 return res
7396 def getFullName( self ):
7397 res = self.getFullNameNoTitle()
7398 if self.getTitle() != "":
7399 res = "%s %s"%( self.getTitle(), res )
7400 return res
7402 def getFullNameNoTitle( self ):
7403 res = self.getFamilyName().decode('utf-8').upper().encode('utf-8')
7404 if self.getFirstName() != "":
7405 if res.strip() != "":
7406 res = "%s, %s"%( res, self.getFirstName() )
7407 else:
7408 res = self.getFirstName()
7409 return res
7411 def getAbrName(self):
7412 res = self.getFamilyName()
7413 if self.getFirstName() != "":
7414 if res != "":
7415 res = "%s, "%res
7416 res = "%s%s."%(res, self.getFirstName()[0].upper())
7417 return res
7420 def isPendingSubmitter(self):
7421 if self.getContribution() is None:
7422 return False
7423 if self.getContribution().getConference() is None:
7424 return False
7425 return self.getContribution().getConference().getPendingQueuesMgr().isPendingSubmitter(self)
7427 def _cmpFamilyName( cp1, cp2 ):
7428 o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName())
7429 o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName())
7430 o1=o1.lower().strip()
7431 o2=o2.lower().strip()
7432 return cmp( o1, o2 )
7433 _cmpFamilyName=staticmethod(_cmpFamilyName)
7436 class AuthorIndex(Persistent):
7438 def __init__(self):
7439 self._idx=OOBTree()
7441 def _getKey(self,author):
7442 k = "%s %s %s"%(author.getFamilyName().lower(),author.getFirstName().lower(),author.getEmail().lower())
7443 return k.strip()
7445 def index(self,author):
7446 key=self._getKey(author)
7447 if not self._idx.has_key(key):
7448 self._idx[key]=[]
7449 l = self._idx[key]
7450 l.append(author)
7451 self._idx[key] = l
7452 self.notifyModification()
7454 def unindex(self,author):
7455 key=self._getKey(author)
7456 if self._idx.has_key(key):
7457 if author in self._idx[key]:
7458 l = self._idx[key]
7459 l.remove(author)
7460 self._idx[key] = l
7461 if len(self._idx[key])<=0:
7462 del self._idx[key]
7463 self.notifyModification()
7465 def getParticipations(self):
7466 return self._idx.values()
7468 def getById(self, id):
7469 return self._idx.get(id,None)
7471 def getByAuthorObj(self, auth):
7472 return self.getById(self._getKey(auth))
7474 def getParticipationKeys(self):
7475 return self._idx.keys()
7477 def notifyModification(self):
7478 self._idx._p_changed = 1
7479 self._p_changed = 1
7481 def match(self, criteria, exact=0):
7482 self._options = ['organisation', 'surName', 'name', 'email']
7483 l = []
7484 for item in self.getParticipations():
7485 if len(item)>0:
7486 ok = []
7487 for f,v in criteria.items():
7488 if f == 'organisation' and v != '':
7489 if (exact == 0 and item[0].getAffiliation().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getAffiliation().lower() != v.lower()):
7490 ok.append(False)
7491 else:
7492 ok.append(True)
7493 if f == 'surName' and v!= '':
7494 if (exact == 0 and item[0].getSurName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getSurName().lower() != v.lower()):
7495 ok.append(False)
7496 else:
7497 ok.append(True)
7498 if f == 'name' and v!= '':
7499 if (exact == 0 and item[0].getName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getName().lower() != v.lower()):
7500 ok.append(False)
7501 else:
7502 ok.append(True)
7503 if f == 'email' and v!= '':
7504 if (exact == 0 and item[0].getEmail().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getEmail().lower() != v.lower()):
7505 ok.append(False)
7506 else:
7507 ok.append(True)
7508 if len(ok) > 0 and not False in ok:
7509 l.append(item[0])
7510 return l
7512 class _AuthIdx(Persistent):
7514 def __init__(self,conf):
7515 self._conf=conf
7516 self._idx=OOBTree()
7518 def _getKey(self,auth):
7519 return "%s %s"%(auth.getFamilyName().lower(),auth.getFirstName().lower())
7521 def index(self,auth):
7522 if auth.getContribution() is None:
7523 raise MaKaCError( _("Cannot index an author of a contribution which has not been included in a Conference"), _("Author Index"))
7524 if auth.getContribution().getConference()!=self._conf:
7525 raise MaKaCError( _("cannot index an author of a contribution which does not belong to this Conference"), _("Author Index"))
7526 key=self._getKey(auth)
7527 contribId=str(auth.getContribution().getId())
7528 if not self._idx.has_key(key):
7529 self._idx[key]=OIBTree()
7530 if not self._idx[key].has_key(contribId):
7531 self._idx[key][contribId]=0
7532 self._idx[key][contribId]+=1
7534 def unindex(self,auth):
7535 if auth.getContribution() is None:
7536 raise MaKaCError( _("Cannot unindex an author of a contribution which is not included in a conference"), _("Author Index"))
7537 if auth.getContribution().getConference()!=self._conf:
7538 raise MaKaCError( _("Cannot unindex an author of a contribution which does not belong to this conference"), _("Author Index"))
7539 key=self._getKey(auth)
7540 if not self._idx.has_key(key):
7541 return
7542 contribId=str(auth.getContribution().getId())
7543 self._idx[key][contribId]-=1
7544 if self._idx[key][contribId]<=0:
7545 del self._idx[key][contribId]
7546 if len(self._idx[key])<=0:
7547 del self._idx[key]
7549 def match(self,query):
7550 query=query.lower().strip()
7551 res=OISet()
7552 for k in self._idx.keys():
7553 if k.find(query)!=-1:
7554 res=union(res,self._idx[k])
7555 return res
7558 class _PrimAuthIdx(_AuthIdx):
7560 def __init__(self,conf):
7561 _AuthIdx.__init__(self,conf)
7562 for contrib in self._conf.getContributionList():
7563 for auth in contrib.getPrimaryAuthorList():
7564 self.index(auth)
7566 class Contribution(CommonObjectBase, Locatable):
7567 """This class implements a conference contribution, being the concrete
7568 contributes of the conference participants. The class contains
7569 necessary attributes to store contribution basic meta data and provides
7570 the useful operations to access and manage them. A contribution can be
7571 attached either to a session or to a conference.
7574 fossilizes(IContributionFossil, IContributionWithSpeakersFossil,\
7575 IContributionWithSubContribsFossil)
7577 def __init__(self,**contribData):
7578 self.parent = None
7579 self._session=None
7580 self.id = ""
7581 self.title = ""
7582 self._fields = {}
7583 self.description = ""
7584 self.startDate=None
7585 self.duration = timedelta(0)
7586 self.speakers = []
7587 self.speakerText = ""
7588 self.place = None
7589 self.room = None
7590 self._boardNumber=""
7591 self._resetSchEntry()
7592 self.__ac = AccessController(self)
7593 self.materials = {}
7594 self.__materialGenerator = Counter()
7595 self._subConts = []
7596 self.__subContGenerator = Counter()
7597 self.paper = None
7598 self.slides = None
7599 self.video = None
7600 self.poster = None
7601 self.minutes = None
7602 self.reviewing = None
7603 self._authorGen = Counter()
7604 self._authors = OOBTree()
7605 self._primaryAuthors = []
7606 self._coAuthors = []
7607 self._speakers = []
7608 self._track = None
7609 self._type = None
7610 self._status=ContribStatusNotSch(self)
7611 #List of allowed users to submit material
7612 self._submitters=[]
7613 self._submittersEmail=[]
7614 self._modificationDS = nowutc()
7615 self._keywords = ""
7616 self._reviewManager = ReviewManager(self)
7618 def __str__(self):
7619 if self.parent:
7620 parentId = self.parent.getId()
7621 else:
7622 parentId = None
7623 return "<Contribution %s:%s@%s>" % (parentId, self.getId(), hex(id(self)))
7625 def getTimezone( self ):
7626 return self.getConference().getTimezone()
7628 def getReviewManager(self):
7629 if not hasattr(self, "_reviewManager"):
7630 self._reviewManager = ReviewManager(self)
7631 return self._reviewManager
7633 def isFullyPublic( self ):
7634 if hasattr(self, "_fullyPublic"):
7635 return self._fullyPublic
7636 else:
7637 self.setFullyPublic()
7638 return self._fullyPublic
7640 def setFullyPublic( self ):
7641 if self.isProtected():
7642 self._fullyPublic = False
7643 self._p_changed = 1
7644 return
7645 for res in self.getAllMaterialList():
7646 if not res.isFullyPublic():
7647 self._fullyPublic = False
7648 self._p_changed = 1
7649 return
7650 for res in self.getSubContributionList():
7651 if not res.isFullyPublic():
7652 self._fullyPublic = False
7653 self._p_changed = 1
7654 return
7655 self._fullyPublic = True
7656 self._p_changed = 1
7658 def updateFullyPublic( self ):
7659 self.setFullyPublic()
7660 self.getOwner().updateFullyPublic()
7662 def getKeywords(self):
7663 try:
7664 return self._keywords
7665 except:
7666 self._keywords = ""
7667 return ""
7669 def setKeywords(self, keywords):
7670 if type(keywords) is list:
7671 self._keywords = keywords[0]
7672 else:
7673 self._keywords = keywords
7674 self.notifyModification()
7676 def getFields( self ):
7677 try:
7678 return self._fields
7679 except:
7680 self._fields = {}
7681 try:
7682 if self.summary != "":
7683 self._fields["summary"] = self.summary
7684 del self.summary
7685 except:
7686 pass
7687 return self._fields
7689 def removeField( self, field ):
7690 if self.getFields().has_key(field):
7691 del self.getFields()[field]
7692 self.notifyModification()
7694 def setField( self, field, value ):
7695 try:
7696 self.getFields()[field] = value
7697 self.notifyModification()
7698 except:
7699 pass
7701 def getField( self, field ):
7702 if self.getFields().has_key(field):
7703 value = self.getFields()[field]
7704 if type(value) is list:
7705 return "".join(value)
7706 elif value is None:
7707 return ""
7708 else:
7709 return value
7710 else:
7711 return ""
7713 def getLogInfo(self):
7714 data = {}
7715 data["subject"] = self.getTitle()
7716 data["id"] = self.id
7717 data["title"] = self.title
7718 data["parent title"] = self.parent.getTitle()
7719 if self._session is not None :
7720 data["session title"] = self._session.getTitle()
7721 data["description"] = self.description
7722 if self.getConference():
7723 afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr()
7724 for f in afm.getFields():
7725 id = f.getId()
7726 data[id] = self.getField(id)
7727 data["start date"] = "%s"%self.startDate
7728 data["duration"] = "%s"%self.duration
7729 if self._track is not None :
7730 data["track"] = self._track.getTitle()
7731 if self._type is not None :
7732 data["type"] = self._type
7733 data["speaker text"] = self.speakerText
7734 if self.place is not None :
7735 data["place"] = self.place.getName()
7736 if self.room is not None :
7737 data["room"] = self.room.getName()
7738 data["board number"] = self._boardNumber
7739 for sc in self.getSubContributionList() :
7740 data["subcontribution %s"%sc.getId()] = sc.getTitle()
7741 for pa in self._primaryAuthors :
7742 data["primary author %s"%pa.getId()] = pa.getFullName()
7743 for ca in self._coAuthors :
7744 data["co-author %s"%ca.getId()] = ca.getFullName()
7745 for sp in self._speakers :
7746 data["speaker %s"%sp.getId()] = sp.getFullName()
7747 for s in self._submitters :
7748 if isinstance(s, MaKaC.user.Avatar):
7749 data["submitter"] = s.getFullName()
7750 else:
7751 data["submitter"] = s.getName()
7752 return data
7755 def setValues( self, data, check=2, moveEntriesBelow=0):
7756 """Sets all the values of the current contribution object from a
7757 dictionary containing the following key-value pairs:
7758 title-(str)
7759 description-(str)
7760 locationName-(str) => name of the location, if not specified
7761 it will be set to the parent location name.
7762 locationAddress-(str)
7763 roomName-(str) => name of the room, if not specified it will
7764 be set to the parent room name.
7765 year, month, day, sHour, sMinute - (str) => components of the
7766 starting date of the session, if not specified it will
7767 be set to now.
7768 durationHours, durationMinutes - (str)
7769 speakers - (str)
7770 check parameter:
7771 0: no check at all
7772 1: check and raise error in case of problem
7773 2: check and adapt the owner dates
7774 moveEntries:
7775 0: no move
7776 1: moveEntries below the contribution
7777 Please, note that this method sets ALL values which means that if
7778 the given dictionary doesn't contain any of the keys the value
7779 will set to a default value.
7782 # In order to move the entries below, it is needed to know the diff (we have to move them)
7783 # and the list of entries to move. It's is needed to take those datas in advance because they
7784 # are going to be modified before the moving.
7785 if moveEntriesBelow == 1:
7786 oldStartDate=copy.copy(self.getStartDate())
7787 oldDuration=copy.copy(self.getDuration())
7788 i=self.getSchEntry().getSchedule().getEntries().index(self.getSchEntry())+1
7789 entriesList = self.getSchEntry().getSchedule().getEntries()[i:]
7790 if data.has_key("title"):
7791 self.setTitle(data["title"])
7792 if data.has_key("keywords"):
7793 self.setKeywords(data["keywords"])
7794 if data.has_key("description"):
7795 self.setDescription(data["description"])
7796 if data.has_key("type") and self.getConference():
7797 self.setType(self.getConference().getContribTypeById(data["type"]))
7798 if self.getConference():
7799 afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr()
7800 for f in afm.getFields():
7801 id = f.getId()
7802 if data.has_key("f_%s"%id):
7803 self.setField(id, data["f_%s"%id])
7805 if "locationName" in data:
7806 loc=self.getOwnLocation()
7807 if not loc:
7808 loc=CustomLocation()
7809 self.setLocation(loc)
7810 loc.setName(data["locationName"])
7811 loc.setAddress(data.get("locationAddress", ""))
7812 else:
7813 self.setLocation(None)
7815 #same as for the location
7816 if "roomName" in data:
7817 room=self.getOwnRoom()
7818 if not room:
7819 room=CustomRoom()
7820 self.setRoom(room)
7821 room.setName(data["roomName"])
7822 else:
7823 self.setRoom(None)
7824 tz = 'UTC'
7825 if self.getConference():
7826 tz = self.getConference().getTimezone()
7827 if data.get("targetDay","")!="" and data.get("sHour","")!="" and data.get("sMinute","")!="" and check==2:
7828 ############################################
7829 # Fermi timezone awareness #
7830 ############################################
7831 me = timezone(tz).localize(datetime(int(data["targetDay"][0:4]), \
7832 int(data["targetDay"][5:7]),int(data["targetDay"][8:])))
7833 sdate = timezone(tz).localize(datetime(me.year,me.month, \
7834 me.day,int(data["sHour"]),int(data["sMinute"])))
7835 self.setStartDate(sdate.astimezone(timezone('UTC')),check=2)
7836 if data.get("sYear","")!="" and data.get("sMonth","")!="" and \
7837 data.get("sDay","")!="" and data.get("sHour","")!="" and \
7838 data.get("sMinute","")!="":
7839 self.setStartDate(timezone(tz).localize(datetime(int(data["sYear"]),
7840 int(data["sMonth"]), int(data["sDay"]),
7841 int(data["sHour"]), int(data["sMinute"]))).astimezone(timezone('UTC')),
7842 check=2)
7843 ############################################
7844 # Fermi timezone awareness(end) #
7845 ############################################
7846 if data.get("durTimedelta", "") != "":
7847 self.setDuration(check=check, dur=data["durTimedelta"])
7848 elif data.get("durHours","")!="" and data.get("durMins","")!="":
7849 self.setDuration(data["durHours"],data["durMins"],check)
7850 else:
7851 h=data.get("durHours","").strip()
7852 m=data.get("durMins","").strip()
7853 if h!="" or m!="":
7854 h=h or "0"
7855 m=m or "0"
7856 if h!="0" or m!="0":
7857 self.setDuration(int(h), int(m),check)
7858 if data.has_key("boardNumber"):
7859 self.setBoardNumber(data.get("boardNumber",""))
7860 if moveEntriesBelow == 1:
7861 diff = (self.getStartDate() - oldStartDate) + (self.getDuration() - oldDuration)
7862 self.getConference().getSchedule().moveEntriesBelow(diff, entriesList)
7863 self.notifyModification()
7865 def clone(self, parent, options, deltaTime = 0):
7866 cont = Contribution()
7867 parent.addContribution(cont)
7868 cont.setTitle( self.getTitle() )
7869 cont.setDescription( self.getDescription() )
7870 for k in self.getFields().keys():
7871 cont.setField(k, self.getField(k))
7872 cont.setKeywords( self.getKeywords() )
7873 if deltaTime == 0 :
7874 deltaTime = parent.getStartDate() - self.getOwner().getStartDate()
7876 startDate = None
7877 if self.startDate is not None :
7878 startDate = self.getStartDate() + deltaTime
7879 cont.setStartDate( startDate )
7881 cont.setDuration( dur=self.getDuration() )
7883 if self.getOwnLocation() is not None:
7884 cont.setLocation(self.getOwnLocation().clone())
7885 if self.getOwnRoom() is not None:
7886 cont.setRoom(self.getOwnRoom().clone())
7887 cont.setBoardNumber(self.getBoardNumber())
7888 cont.setReportNumberHolder(self.getReportNumberHolder().clone(self))
7890 cont.setStatus(self.getCurrentStatus())
7892 if self.getType() is not None :
7893 for ct in cont.getConference().getContribTypeList() :
7894 if ct.getName() == self.getType().getName() :
7895 cont.setType(ct)
7896 break
7898 if options.get("tracks", False) :
7899 if self.getTrack() is not None :
7900 for tr in cont.getConference().getTrackList() :
7901 if tr.getTitle() == self.getTrack().getTitle() :
7902 cont.setTrack(tr)
7903 break
7904 else :
7905 cont.setTrack(None)
7907 if options.get("access", False) :
7908 cont.setProtection(self.getAccessController()._getAccessProtection())
7909 for u in self.getAllowedToAccessList() :
7910 cont.grantAccess(u)
7911 for mgr in self.getManagerList() :
7912 cont.grantModification(mgr)
7913 for sub in self.getSubmitterList() :
7914 cont.grantSubmission(sub)
7915 for domain in self.getDomainList():
7916 cont.requireDomain(domain)
7918 if options.get("authors", False) :
7919 for a in self.getPrimaryAuthorList() :
7920 cont.addPrimaryAuthor(a.clone())
7921 for ca in self.getCoAuthorList() :
7922 cont.addCoAuthor(ca.clone())
7923 for sp in self.getSpeakerList():
7924 cont.newSpeaker(sp.clone())
7925 cont.setSpeakerText(self.getSpeakerText())
7927 if options.get("materials", False) :
7928 for m in self.getMaterialList() :
7929 cont.addMaterial(m.clone(cont))
7930 if self.getPaper() is not None:
7931 cont.setPaper(self.getPaper().clone(cont))
7932 if self.getSlides() is not None:
7933 cont.setSlides(self.getSlides().clone(cont))
7934 if self.getVideo() is not None:
7935 cont.setVideo(self.getVideo().clone(cont))
7936 if self.getPoster() is not None:
7937 cont.setPoster(self.getPoster().clone(cont))
7938 if self.getMinutes() is not None:
7939 cont.setMinutes(self.getMinutes().clone(cont))
7940 if self.getReviewing() is not None:
7941 cont.setReviewing(self.getReviewing().clone(cont))
7943 if options.get("subcontribs", False) :
7944 for sc in self.getSubContributionList() :
7945 cont.addSubContribution(sc.clone(cont, self, options))
7946 return cont
7948 def notifyModification( self, date = None, raiseEvent = True):
7950 self.setModificationDate(date)
7952 if raiseEvent:
7953 self._notify('infoChanged')
7955 parent = self.getParent()
7956 if parent:
7957 parent.setModificationDate()
7958 self._p_changed = 1
7960 def getCategoriesPath(self):
7961 return self.getConference().getCategoriesPath()
7963 def getModifKey( self ):
7964 return self.getConference().getModifKey()
7966 def getAccessKey( self ):
7967 return self.getConference().getAccessKey()
7969 def getLocator( self ):
7970 """Gives back a globaly unique identification encapsulated in a Locator
7971 object for the contribution instance
7973 if self.getConference() == None:
7974 return Locator()
7975 lconf = self.getConference().getLocator()
7976 if self.getSession() is not None:
7977 lconf["sessionId"] = self.getSession().getId()
7978 lconf["contribId"] = self.getId()
7979 return lconf
7981 def _setConference( self, conf ):
7982 self.parent = conf
7984 def _setId( self, id ):
7985 self.id = id
7987 def includeInConference( self, conf, id ):
7988 """sets the conference of a contribution
7990 if self.getConference() is not None:
7991 #raise MaKaCError("the contribution is already included in a conference")
7992 pass
7993 else:
7994 self._setConference( conf )
7995 self._setId( id )
7997 def delete( self ):
7998 """deletes a contribution and all of its subitems
8001 oldParent = self.getConference()
8003 if oldParent != None:
8004 self._notify('deleted', oldParent)
8006 self.setTrack(None)
8007 self.setSession(None)
8008 for mat in self.getMaterialList():
8009 self.removeMaterial(mat)
8010 self.removePaper()
8011 self.removeSlides()
8012 self.removeVideo()
8013 self.removePoster()
8014 self.removeMinutes()
8015 self.removeReviewing()
8017 while len(self.getSubContributionList()) > 0:
8019 sc = self.getSubContributionList()[0]
8021 self.removeSubContribution(sc)
8024 # delete it from parent session (if it exists)
8025 if self.getOwner() != self.getConference():
8027 self.getOwner().removeContribution( self )
8029 # (always) delete it from the parent conference
8030 self.getConference().removeContribution( self, callDelete=False )
8032 self._setConference( None )
8034 self.setStatus(ContribStatusNone(self))
8035 TrashCanManager().add(self)
8037 def recover(self):
8038 TrashCanManager().remove(self)
8040 def setId( self, newId ):
8041 self._setId(newId)
8043 def getId( self ):
8044 return self.id
8046 def getUniqueId( self ):
8047 """returns (string) the unique identifier of the item"""
8048 """used mainly in the web session access key table"""
8049 return "%st%s" % (self.getConference().getUniqueId(),self.id)
8051 def setTitle( self, newTitle, notify = True ):
8052 oldTitle = self.title
8053 self.title = newTitle.strip()
8055 if notify:
8056 self._notify('contributionTitleChanged', oldTitle, newTitle)
8057 self.notifyModification()
8059 def getTitle( self ):
8060 if self.title.strip() == "":
8061 return "(no title)"
8062 return self.title
8064 #def setDescription( self, newDesc ):
8065 # self.description = newDesc.strip()
8066 # self.notifyModification()
8068 #def getDescription( self ):
8069 # return self.description
8071 def getDescription(self):
8072 return self.getField("content")
8074 def setDescription(self, desc):
8075 self.setField("content", desc)
8077 def setParent(self,parent):
8078 self.parent=parent
8079 self.notifyModification()
8080 if self.parent==None:
8081 return
8083 def getParent( self ):
8084 if self.getSession() is not None:
8085 return self.getSession()
8086 return self.getConference()
8088 def getOwner( self ):
8089 return self.getParent()
8091 def setOwner(self, owner):
8092 self.setParent(owner)
8094 def getConference( self ):
8095 return self.parent
8097 def getSession( self ):
8098 try:
8099 if self._session:
8100 pass
8101 except AttributeError:
8102 self._session=None
8103 return self._session
8105 def setSession(self,session):
8106 if self.getSession()==session:
8107 return
8108 if self.isScheduled():
8109 schEntry=self.getSchEntry()
8110 schEntry.getSchedule().removeEntry(schEntry)
8111 oldSession=self.getSession()
8112 if oldSession is not None:
8113 oldSession.removeContribution(self)
8114 self._session=session
8115 if session is not None:
8116 session.addContribution(self)
8118 def getContribution(self):
8119 return self
8121 def _resetSchEntry(self):
8122 self.__schEntry=ContribSchEntry(self)
8124 def getSchEntry(self):
8125 if self.__schEntry is None or \
8126 not isinstance(self.__schEntry,ContribSchEntry):
8127 self._resetSchEntry()
8128 return self.__schEntry
8130 def isScheduled(self):
8131 #For the moment we do it like this
8132 return self.getSchEntry().getSchedule() is not None
8134 def isWithdrawn(self):
8135 return isinstance(self.getCurrentStatus(), ContribStatusWithdrawn)
8137 def getLocationParent( self ):
8139 Returns the object from which the room/location
8140 information should be inherited
8142 if not self.getConference().getEnableSessionSlots() and self.getSession():
8143 return self.getSession()
8144 if self.isScheduled():
8145 return self.getSchEntry().getSchedule().getOwner()
8146 return self.getOwner()
8148 def getOwnLocation( self ):
8149 return self.place
8151 def setLocation( self, newLocation ):
8152 oldLocation = self.place
8153 self.place = newLocation
8154 self._notify('locationChanged', oldLocation, newLocation)
8155 self.notifyModification()
8157 def getOwnRoom( self ):
8158 return self.room
8160 def setRoom( self, newRoom ):
8161 oldRoom = self.room
8162 self.room = newRoom
8163 self._notify('roomChanged', oldRoom, newRoom)
8164 self.notifyModification()
8166 def setBoardNumber(self,newBoardNum):
8167 self._boardNumber=str(newBoardNum).strip()
8169 def getBoardNumber(self):
8170 try:
8171 if self._boardNumber:
8172 pass
8173 except AttributeError:
8174 self._boardNumber=""
8175 return self._boardNumber
8177 def verifyStartDate(self, sDate, check=2):
8178 """check parameter:
8179 0: no check at all
8180 1: check and raise error in case of problem
8181 2: check and adapt the owner dates"""
8183 tz = timezone(self.getConference().getTimezone())
8184 if self.getSchEntry().getSchedule():
8185 owner = self.getSchEntry().getSchedule().getOwner()
8186 else:
8187 owner = self.getOwner()
8188 if sDate < owner.getStartDate():
8189 if check == 1:
8190 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start before (%s) its parent (%s)") %\
8191 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8192 owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8193 _("Contribution"))
8194 if check == 2:
8195 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
8196 owner, sDate.astimezone(tz)))
8197 owner.setDates(sDate,owner.getEndDate(), check)
8198 if sDate > owner.getEndDate():
8199 if check == 1:
8200 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start after (%s) its parent end date(%s)") %\
8201 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8202 owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8203 _("Contribution"))
8204 if check == 2:
8205 owner.setEndDate(sDate+self.getDuration(),check)
8206 # Check that after modifying the start date, the end date is still within the limits of the slot
8207 if self.getDuration() and sDate + self.getDuration() > owner.getEndDate():
8208 if check==1:
8209 raise ParentTimingError("The contribution cannot end after (%s) its parent ends (%s)"%\
8210 ((sDate + self.getDuration()).astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8211 owner.getAdjustedEndDate().strftime('%Y-%m-%d %H:%M')),\
8212 _("Contribution"))
8213 elif check==2:
8214 # update the schedule
8215 owner.setEndDate(sDate + self.getDuration(),check)
8216 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
8217 owner, owner.getAdjustedEndDate()))
8219 def setStartDate(self, newDate, check=2, moveEntries=0):
8220 """check parameter:
8221 0: no check at all
8222 1: check and raise error in case of problem
8223 2: check and adapt the owner dates"""
8225 if newDate == None:
8226 self.startDate=None
8227 return
8228 if not newDate.tzname():
8229 raise MaKaCError("date should be timezone aware")
8231 if newDate != None and check != 0:
8232 self.verifyStartDate(newDate, check)
8233 self.startDate=copy.copy(newDate)
8234 self.getSchEntry().synchro()
8235 self.notifyModification()
8237 def getStartDate( self ):
8238 return self.startDate
8240 def getAdjustedStartDate(self,tz=None):
8241 if self.getStartDate() is None:
8242 return None
8243 if not tz:
8244 tz = self.getConference().getTimezone()
8245 if tz not in all_timezones:
8246 tz = 'UTC'
8247 return self.getStartDate().astimezone(timezone(tz))
8249 def getEndDate( self ):
8250 if self.getStartDate() is None:
8251 return None
8252 return self.getStartDate()+self.getDuration()
8254 def getAdjustedEndDate(self,tz=None):
8255 if not tz:
8256 tz = self.getConference().getTimezone()
8257 if tz not in all_timezones:
8258 tz = 'UTC'
8259 if self.getEndDate():
8260 return self.getEndDate().astimezone(timezone(tz))
8261 return None
8263 def getDuration( self ):
8264 return self.duration
8266 def verifyDuration(self, check=2):
8267 """check parameter:
8268 0: no check at all
8269 1: check and raise error in case of problem
8270 2: check and adapt the owner dates"""
8272 tz = timezone(self.getConference().getTimezone())
8274 endDate = self.getEndDate()
8276 if self.getSchEntry().getSchedule() is not None:
8277 owner = self.getSchEntry().getSchedule().getOwner()
8278 if endDate > owner.getEndDate():
8279 if check==1:
8280 raise ParentTimingError(_("The contribution \"%s\" ending date (%s) has to fit between its parent's dates (%s - %s)") %\
8281 (self.getTitle(), endDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8282 owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8283 owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8284 _("Contribution"))
8285 elif check==2:
8286 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
8287 owner, self.getAdjustedEndDate()))
8288 owner.setEndDate(endDate, check)
8290 def setDuration(self,hours=0,minutes=15,check=2,dur=0):
8291 """check parameter:
8292 0: no check at all
8293 1: check and raise error in case of problem
8294 2: check and adapt the owner dates"""
8296 if dur!=0:
8297 self.duration=dur
8298 else:
8299 self.duration=timedelta(hours=int(hours),minutes=int(minutes))
8300 if check != 0:
8301 self.verifyDuration(check)
8302 self.getSchEntry().synchro()
8303 self.notifyModification()
8305 def _addAuthor( self, part ):
8308 try:
8309 if self._authors:
8310 pass
8311 except AttributeError:
8312 self._authors = OOBTree()
8313 try:
8314 if self._authorGen:
8315 pass
8316 except AttributeError:
8317 self._authorGen=Counter()
8318 newId = part.getId()
8319 if newId == "":
8320 newId = str( self._authorGen.newCount() )
8321 self._authors[newId] = part
8322 part.includeInContribution( self, newId )
8324 def _removeAuthor( self, part ):
8327 try:
8328 if self._authors:
8329 pass
8330 except AttributeError:
8331 self._authors = OOBTree()
8332 if not self._authors.has_key( part.getId() ):
8333 return
8334 del self._authors[ part.getId() ]
8335 part.delete()
8337 def addPrimaryAuthor( self, part ):
8340 try:
8341 if self._primaryAuthors:
8342 pass
8343 except AttributeError:
8344 self._primaryAuthors = []
8345 self._addAuthor( part )
8346 self._primaryAuthors.append( part )
8347 if self.getConference() is not None:
8348 self.getConference().indexAuthor(part)
8349 self.notifyModification()
8351 def removePrimaryAuthor( self, part, removeSpeaker=1, removePendingSubm=True):
8354 try:
8355 if self._primaryAuthors:
8356 pass
8357 except AttributeError:
8358 self._primaryAuthors = []
8359 if part not in self._primaryAuthors:
8360 return
8361 if self.getConference() is not None:
8362 self.getConference().unindexAuthor(part)
8363 self._primaryAuthors.remove( part )
8364 if removeSpeaker:
8365 self.removeSpeaker( part )
8366 self._removeAuthor( part )
8367 if removePendingSubm:
8368 #--Pending queue: remove pending participant waiting to became submitter if anything
8369 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8371 self.notifyModification()
8373 def recoverPrimaryAuthor(self, pa, isPendingSubmitter):
8374 self.addPrimaryAuthor(pa)
8375 pa.recover()
8376 if isPendingSubmitter:
8377 self.getConference().getPendingQueuesMgr().addPendingSubmitter(pa, False)
8379 def isPrimaryAuthor( self, part ):
8382 try:
8383 if self._primaryAuthors:
8384 pass
8385 except AttributeError:
8386 self._primaryAuthors = []
8387 return part in self._primaryAuthors
8389 def upPrimaryAuthor(self,part):
8392 try:
8393 if self._primaryAuthors:
8394 pass
8395 except AttributeError:
8396 self._primaryAuthors=[]
8397 try:
8398 idx=self._primaryAuthors.index(part)
8399 except ValueError:
8400 return
8401 if idx==0:
8402 return
8403 self._primaryAuthors.remove(part)
8404 self._primaryAuthors.insert(idx-1,part)
8405 self.notifyModification()
8407 def downPrimaryAuthor(self,part):
8410 try:
8411 if self._primaryAuthors:
8412 pass
8413 except AttributeError:
8414 self._primaryAuthors=[]
8415 try:
8416 idx=self._primaryAuthors.index(part)
8417 except ValueError:
8418 return
8419 if idx>len(self._primaryAuthors):
8420 return
8421 self._primaryAuthors.remove(part)
8422 self._primaryAuthors.insert(idx+1,part)
8423 self.notifyModification()
8425 def upCoAuthor(self,part):
8428 try:
8429 if self._coAuthors:
8430 pass
8431 except AttributeError:
8432 self._coAuthors=[]
8433 try:
8434 idx=self._coAuthors.index(part)
8435 except ValueError:
8436 return
8437 if idx==0:
8438 return
8439 self._coAuthors.remove(part)
8440 self._coAuthors.insert(idx-1,part)
8441 self.notifyModification()
8443 def downCoAuthor(self,part):
8446 try:
8447 if self._coAuthors:
8448 pass
8449 except AttributeError:
8450 self._coAuthors=[]
8451 try:
8452 idx=self._coAuthors.index(part)
8453 except ValueError:
8454 return
8455 if idx>len(self._coAuthors):
8456 return
8457 self._coAuthors.remove(part)
8458 self._coAuthors.insert(idx+1,part)
8459 self.notifyModification()
8461 def getPrimaryAuthorList( self ):
8464 try:
8465 if self._primaryAuthors:
8466 pass
8467 except AttributeError:
8468 self._primaryAuthors = []
8469 return self._primaryAuthors
8471 getPrimaryAuthorsList = getPrimaryAuthorList
8473 def getAuthorList( self ):
8476 try:
8477 if self._authors:
8478 pass
8479 except AttributeError:
8480 self._authors = OOBTree()
8481 return self._authors.values()
8483 def addCoAuthor( self, part ):
8486 try:
8487 if self._coAuthors:
8488 pass
8489 except AttributeError:
8490 self._coAuthors = []
8491 self._addAuthor( part )
8492 self._coAuthors.append( part )
8493 if self.getConference() is not None:
8494 self.getConference().indexAuthor(part)
8495 self.notifyModification()
8497 def removeCoAuthor( self, part, removeSpeaker=1, removePendingSubm=True):
8500 try:
8501 if self._coAuthors:
8502 pass
8503 except AttributeError:
8504 self._coAuthors = []
8505 if part not in self._coAuthors:
8506 return
8507 if self.getConference() is not None:
8508 self.getConference().unindexAuthor(part)
8509 self._coAuthors.remove( part )
8510 if removeSpeaker:
8511 self.removeSpeaker( part )
8512 self._removeAuthor( part )
8513 if removePendingSubm:
8514 #--Pending queue: remove pending participant waiting to became submitter if anything
8515 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8517 self.notifyModification()
8519 def recoverCoAuthor(self, ca, isPendingSubmitter):
8520 self.addCoAuthor(ca)
8521 ca.recover()
8522 if isPendingSubmitter:
8523 self.getConference().getPendingQueuesMgr().addPendingSubmitter(ca, False)
8525 def isCoAuthor( self, part ):
8528 try:
8529 if self._primaryAuthors:
8530 pass
8531 except AttributeError:
8532 self._primaryAuthors = []
8533 return part in self._coAuthors
8535 def getCoAuthorList( self ):
8538 try:
8539 if self._coAuthors:
8540 pass
8541 except AttributeError:
8542 self._coAuthors = []
8543 return self._coAuthors
8545 def getAuthorById( self, id ):
8548 try:
8549 if self._authors:
8550 pass
8551 except AttributeError:
8552 self._authors = OOBTree()
8553 return self._authors.get( id.strip(), None )
8555 def isAuthor( self, part ):
8558 try:
8559 if self._authors:
8560 pass
8561 except AttributeError:
8562 self._authors = OOBTree()
8563 return self._authors.has_key( part.getId() )
8565 def getSpeakerById( self, id ):
8568 try:
8569 if self._speakers:
8570 pass
8571 except AttributeError:
8572 self._speakers = []
8573 for spk in self._speakers:
8574 if spk.getId() == id:
8575 return spk
8576 return None
8578 def addSpeaker( self, part ):
8580 Adds a speaker (ContributionParticipation object) to the contribution
8581 forcing it to be one of the authors of the contribution
8583 try:
8584 if self._speakers:
8585 pass
8586 except AttributeError:
8587 self._speakers = []
8588 if not self.isAuthor( part ):
8589 raise MaKaCError( _("The Specified speaker is not the Author"), _("Contribution"))
8590 self._speakers.append( part )
8591 if self.getConference() is not None:
8592 self.getConference().indexSpeaker(part)
8593 self.notifyModification()
8595 def newSpeaker( self, part ):
8597 Adds a new speaker (ContributionParticipation object) to the contribution
8598 setting the speakers ID and the fact it belongs to that contribution
8600 try:
8601 if self._speakers:
8602 pass
8603 except AttributeError:
8604 self._speakers = []
8605 try:
8606 if self._authorGen:
8607 pass
8608 except AttributeError:
8609 self._authorGen=Counter()
8610 self._speakers.append( part )
8611 newId = part.getId()
8612 if newId == "":
8613 newId = str( self._authorGen.newCount() )
8614 part.includeInContribution(self, newId)
8615 if self.getConference() is not None:
8616 self.getConference().indexSpeaker(part)
8617 self.notifyModification()
8619 def removeSpeaker( self, part ):
8622 try:
8623 if self._speakers:
8624 pass
8625 except AttributeError:
8626 self._speakers = []
8627 if part not in self._speakers:
8628 return
8629 self._speakers.remove( part )
8630 if self.getConference() is not None:
8631 self.getConference().unindexSpeaker(part)
8632 if part not in self.getAuthorList():
8633 part.delete()
8634 #--Pending queue: remove pending participant waiting to became submitter if anything
8635 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8637 self.notifyModification()
8639 def recoverSpeaker(self, spk, isPendingSubmitter):
8640 self.newSpeaker(spk)
8641 spk.recover()
8642 if isPendingSubmitter:
8643 self.getConference().getPendingQueuesMgr().addPendingSubmitter(spk, False)
8645 def isSpeaker( self, part ):
8648 try:
8649 if self._speakers:
8650 pass
8651 except AttributeError:
8652 self._speakers = []
8653 return part in self._speakers
8655 def getSpeakerList ( self ):
8658 try:
8659 if self._speakers:
8660 pass
8661 except AttributeError:
8662 self._speakers = []
8663 return self._speakers
8665 def getSpeakerText( self ):
8666 #to be removed
8667 try:
8668 if self.speakerText:
8669 pass
8670 except AttributeError, e:
8671 self.speakerText = ""
8672 return self.speakerText
8674 def setSpeakerText( self, newText ):
8675 self.speakerText = newText.strip()
8677 def appendSpeakerText( self, newText ):
8678 self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) )
8680 def canIPAccess( self, ip ):
8681 if not self.__ac.canIPAccess( ip ):
8682 return False
8683 if self.getOwner() != None:
8684 return self.getOwner().canIPAccess(ip)
8685 return True
8687 def isProtected( self ):
8688 # tells if a contribution is protected or not
8689 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
8691 def getAccessProtectionLevel( self ):
8692 return self.__ac.getAccessProtectionLevel()
8694 def isItselfProtected( self ):
8695 return self.__ac.isItselfProtected()
8697 def hasAnyProtection( self ):
8698 """Tells whether a contribution has any kind of protection over it:
8699 access or domain protection.
8701 if self.__ac.isProtected():
8702 return True
8703 if self.getDomainList():
8704 return True
8705 if self.getAccessProtectionLevel() == -1:
8706 return False
8707 if self.getOwner():
8708 return self.getOwner().hasAnyProtection()
8709 else:
8710 return False
8712 def hasProtectedOwner( self ):
8713 if self.getOwner() != None:
8714 return self.getOwner().isProtected()
8715 return False
8717 def setProtection( self, private ):
8719 oldValue = 1 if self.isProtected() else -1
8721 self.__ac.setProtection( private )
8722 self.updateFullyPublic()
8724 if oldValue != private:
8725 # notify listeners
8726 self._notify('protectionChanged', oldValue, private)
8728 def grantAccess( self, prin ):
8729 self.__ac.grantAccess( prin )
8730 if isinstance(prin, MaKaC.user.Avatar):
8731 prin.linkTo(self, "access")
8733 def revokeAccess( self, prin ):
8734 self.__ac.revokeAccess( prin )
8735 if isinstance(prin, MaKaC.user.Avatar):
8736 prin.unlinkTo(self, "access")
8738 def canView( self, aw ):
8739 """tells whether the specified user has access to the current object
8740 or any of its sub-objects
8742 if self.canAccess( aw ):
8743 return True
8744 ### TODO: Replace this code when plugins allow extension points+notifications ##################
8745 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
8746 if RCCollaborationAdmin.hasRights(user=aw.getUser()) or \
8747 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
8748 return True
8749 ################################################################################################
8750 for sc in self.getSubContributionList():
8751 if sc.canView( aw ):
8752 return True
8753 return False
8755 def isAllowedToAccess( self, user ):
8756 if not user:
8757 return False
8758 return (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or\
8759 self.__ac.canUserAccess( user ) or\
8760 self.canUserModify( user ) or \
8761 self.canUserSubmit(user)
8763 def canAccess( self, aw ):
8764 # Allow harvesters (Invenio, offline cache) to access
8765 # protected pages
8766 if self.__ac.isHarvesterIP(aw.getIP()):
8767 return True
8768 #####################################################
8770 if self.canModify(aw):
8771 return True
8773 if not self.canIPAccess(aw.getIP()) and not self.isAllowedToAccess( aw.getUser() ):
8774 return False
8775 if not self.isProtected():
8776 return True
8777 flag = self.isAllowedToAccess( aw.getUser() )
8778 return flag or self.getConference().canKeyAccess(aw)
8780 def grantModification( self, prin ):
8781 self.__ac.grantModification( prin )
8782 if isinstance(prin, MaKaC.user.Avatar):
8783 prin.linkTo(self, "manager")
8785 def revokeModification( self, prin ):
8786 self.__ac.revokeModification( prin )
8787 if isinstance(prin, MaKaC.user.Avatar):
8788 prin.unlinkTo(self, "manager")
8790 def canModify( self, aw ):
8791 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
8793 def canUserModify( self, av ):
8794 """Tells whether a user is allowed to modify the current contribution:
8795 only if the user is granted to modify the contribution or the user
8796 can modify any of its upper objects (i.e. conference or session).
8798 return self.getParent().canUserModify( av ) or self.__ac.canModify( av )
8800 def getManagerList( self ):
8801 return self.__ac.getModifierList()
8803 def getAllowedToAccessList( self ):
8804 return self.__ac.getAccessList()
8806 def addMaterial( self, newMat ):
8807 newMat.setId( str(self.__materialGenerator.newCount()) )
8808 newMat.setOwner( self )
8809 self.materials[ newMat.getId() ] = newMat
8810 self.notifyModification()
8812 def removeMaterial( self, mat ):
8813 if mat.getId() in self.materials.keys():
8814 self.materials[mat.getId()].setOwner(None)
8815 del self.materials[ mat.getId() ]
8816 mat.delete()
8817 self.notifyModification()
8818 elif mat.getId().lower() == 'paper':
8819 self.removePaper()
8820 self.notifyModification()
8821 elif mat.getId().lower() == 'slides':
8822 self.removeSlides()
8823 self.notifyModification()
8824 elif mat.getId().lower() == 'minutes':
8825 self.removeMinutes()
8826 self.notifyModification()
8827 elif mat.getId().lower() == 'video':
8828 self.removeVideo()
8829 self.notifyModification()
8830 elif mat.getId().lower() == 'poster':
8831 self.removePoster()
8832 self.notifyModification()
8834 def recoverMaterial(self, recMat):
8835 # Id must already be set in recMat.
8836 recMat.setOwner( self )
8837 self.materials[ recMat.getId() ] = recMat
8838 recMat.recover()
8839 self.notifyModification()
8841 def getMaterialRegistry(self):
8843 Return the correct material registry for this type
8845 from MaKaC.webinterface.materialFactories import ContribMFRegistry
8846 return ContribMFRegistry
8848 def getMaterialById( self, matId ):
8849 if matId.lower() == 'paper':
8850 return self.getPaper()
8851 elif matId.lower() == 'slides':
8852 return self.getSlides()
8853 elif matId.lower() == 'video':
8854 return self.getVideo()
8855 elif matId.lower() == 'poster':
8856 return self.getPoster()
8857 elif matId.lower() == 'minutes':
8858 return self.getMinutes()
8859 elif self.materials.has_key(matId):
8860 return self.materials[ matId ]
8861 return None
8863 def getMaterialList( self ):
8864 return self.materials.values()
8866 def getAllMaterialList( self ):
8867 l = self.getMaterialList()
8868 if self.getPaper():
8869 l.append( self.getPaper() )
8870 if self.getSlides():
8871 l.append( self.getSlides() )
8872 if self.getVideo():
8873 l.append( self.getVideo() )
8874 if self.getPoster():
8875 l.append( self.getPoster() )
8876 if self.getMinutes():
8877 l.append( self.getMinutes() )
8878 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
8879 return l
8881 def newSubContribution(self):
8882 newSub = SubContribution()
8883 self.addSubContribution(newSub)
8884 newSub._notify('created', self)
8885 return newSub
8887 def addSubContribution( self, newSubCont ):
8888 newSubCont.setId(str( self.__subContGenerator.newCount()) )
8889 newSubCont.setOwner( self )
8890 self._subConts.append( newSubCont )
8891 self.notifyModification()
8893 def removeSubContribution( self, subCont ):
8894 if subCont in self._subConts:
8895 subCont.delete()
8896 subCont.setOwner(None)
8897 self._subConts.remove(subCont)
8898 self.notifyModification()
8900 def recoverSubContribution( self, recSubCont ):
8901 # Id must already be set in recSubCont.
8902 recSubCont.setOwner( self )
8903 self._subConts.append( recSubCont )
8904 recSubCont.recover()
8905 self.notifyModification()
8907 def getSubContributionById(self, SCId):
8908 for sb in self._subConts:
8909 if sb.getId() == SCId:
8910 return sb
8912 def getSubContributionList(self):
8913 return self._subConts
8915 def iterSubContributions(self):
8916 return iter(self._subConts)
8918 def getNumberOfSubcontributions(self):
8919 return len(self._subConts)
8921 def upSubContribution(self, subcont):
8922 if subcont in self._subConts:
8923 if self._subConts.index(subcont) != 0:
8924 index = self._subConts.index(subcont)
8925 sb = self._subConts.pop(index)
8926 self._subConts.insert(index-1, sb)
8927 self.notifyModification()
8929 def downSubContribution(self, subCont):
8930 if subCont in self._subConts:
8931 if self._subConts.index(subCont) < len(self._subConts)-1:
8932 index = self._subConts.index(subCont)
8933 sb = self._subConts.pop(index)
8934 self._subConts.insert(index+1, sb)
8935 self.notifyModification()
8937 def setPaper( self, newPaper ):
8938 if self.getPaper() != None:
8939 raise MaKaCError( _("The paper for this contribution has already been set"), _("Contribution"))
8940 self.paper=newPaper
8941 self.paper.setOwner( self )
8942 self.notifyModification()
8944 def removePaper( self ):
8945 if self.paper is None:
8946 return
8947 self.paper.delete()
8948 self.paper.setOwner(None)
8949 self.paper = None
8950 self.notifyModification()
8952 def recoverPaper(self, p):
8953 self.setPaper(p)
8954 p.recover()
8956 def getPaper( self ):
8957 return self.paper
8959 def setSlides( self, newSlides ):
8960 if self.getSlides() != None:
8961 raise MaKaCError( _("The slides for this contribution have already been set"), _("contribution"))
8962 self.slides=newSlides
8963 self.slides.setOwner( self )
8964 self.notifyModification()
8966 def removeSlides( self ):
8967 if self.slides is None:
8968 return
8969 self.slides.delete()
8970 self.slides.setOwner( None )
8971 self.slides= None
8972 self.notifyModification()
8974 def recoverSlides(self, s):
8975 self.setSlides(s)
8976 s.recover()
8978 def getSlides( self ):
8979 return self.slides
8981 def setVideo( self, newVideo ):
8982 if self.getVideo() != None:
8983 raise MaKaCError( _("the video for this contribution has already been set"))
8984 self.video=newVideo
8985 self.video.setOwner( self )
8986 self.notifyModification()
8988 def removeVideo( self ):
8989 if self.getVideo() is None:
8990 return
8991 self.video.delete()
8992 self.video.setOwner(None)
8993 self.video = None
8994 self.notifyModification()
8996 def recoverVideo(self, v):
8997 self.setVideo(v)
8998 v.recover()
9000 def getVideo( self ):
9001 try:
9002 if self.video:
9003 pass
9004 except AttributeError:
9005 self.video = None
9006 return self.video
9008 def setPoster( self, newPoster ):
9009 if self.getPoster() != None:
9010 raise MaKaCError( _("the poster for this contribution has already been set"))
9011 self.poster=newPoster
9012 self.poster.setOwner( self )
9013 self.notifyModification()
9015 def removePoster( self ):
9016 if self.getPoster() is None:
9017 return
9018 self.poster.delete()
9019 self.poster.setOwner(None)
9020 self.poster = None
9021 self.notifyModification()
9023 def recoverPoster(self, p):
9024 self.setPoster(p)
9025 p.recover()
9027 def getPoster( self ):
9028 try:
9029 if self.poster:
9030 pass
9031 except AttributeError:
9032 self.poster = None
9033 return self.poster
9035 def setMinutes( self, newMinutes ):
9036 if self.getMinutes() != None:
9037 raise MaKaCError( _("the Minutes for this contribution has already been set"))
9038 self.minutes=newMinutes
9039 self.minutes.setOwner( self )
9040 self.notifyModification()
9042 def createMinutes( self ):
9043 if self.getMinutes() != None:
9044 raise MaKaCError( _("The minutes for this contribution have already been created"), _("Contribution"))
9045 self.minutes = Minutes()
9046 self.minutes.setOwner( self )
9047 self.notifyModification()
9048 return self.minutes
9050 def removeMinutes( self ):
9051 if self.getMinutes() is None:
9052 return
9053 self.minutes.delete()
9054 self.minutes.setOwner( None )
9055 self.minutes = None
9056 self.notifyModification()
9058 def recoverMinutes(self, min):
9059 self.removeMinutes() # To ensure that the current minutes are put in
9060 # the trash can.
9061 self.minutes = min
9062 self.minutes.setOwner( self )
9063 min.recover()
9064 self.notifyModification()
9065 return self.minutes
9067 def getMinutes( self ):
9068 #To be removed
9069 try:
9070 if self.minutes:
9071 pass
9072 except AttributeError, e:
9073 self.minutes = None
9074 return self.minutes
9076 def setReviewing( self, newReviewing ):
9077 if self.getReviewing() != None:
9078 raise MaKaCError( _("The reviewing maretial for this contribution has already been set"), _("Contribution"))
9079 self.reviewing=newReviewing
9080 self.reviewing.setOwner( self )
9081 self.notifyModification()
9083 def removeReviewing( self ):
9084 if self.getReviewing() is None:
9085 return
9086 self.reviewing.delete()
9087 self.reviewing.setOwner(None)
9088 self.reviewing = None
9089 self.notifyModification()
9091 def recoverReviewing(self, p):
9092 self.setReviewing(p)
9093 p.recover()
9095 def getReviewing( self ):
9096 try:
9097 if self.reviewing:
9098 pass
9099 except AttributeError, e:
9100 self.reviewing = None
9101 return self.reviewing
9103 def getMasterSchedule( self ):
9104 return self.getOwner().getSchedule()
9106 def requireDomain( self, dom ):
9107 self.__ac.requireDomain( dom )
9108 self._notify('domainAdded', dom)
9110 def freeDomain( self, dom ):
9111 self.__ac.freeDomain( dom )
9112 self._notify('domainRemoved', dom)
9114 def getDomainList( self ):
9115 return self.__ac.getRequiredDomainList()
9117 def getTrack( self ):
9118 try:
9119 if self._track:
9120 pass
9121 except AttributeError:
9122 self._track = None
9123 return self._track
9125 def setTrack( self, newTrack ):
9126 currentTrack = self.getTrack()
9127 if newTrack == currentTrack:
9128 return
9129 if currentTrack:
9130 currentTrack.removeContribution( self )
9131 self._track = newTrack
9132 if self._track:
9133 self._track.addContribution( self )
9135 def removeTrack(self, track):
9136 if track == self._track:
9137 self._track = None
9139 def setType( self, newType ):
9140 self._type = newType
9142 def getType( self ):
9143 try:
9144 if self._type:
9145 pass
9146 except AttributeError:
9147 self._type = None
9148 return self._type
9150 def getModificationDate( self ):
9151 """Returns the date in which the contribution was last modified"""
9152 try:
9153 return self._modificationDS
9154 except:
9155 if self.getConference():
9156 self._modificationDS = self.getConference().getModificationDate()
9157 else:
9158 self._modificationDS = nowutc()
9159 return self._modificationDS
9161 def getCurrentStatus(self):
9162 try:
9163 if self._status:
9164 pass
9165 except AttributeError:
9166 self._status=ContribStatusNotSch(self)
9167 return self._status
9168 getStatus = getCurrentStatus
9170 def setStatus(self,newStatus):
9173 self._status=newStatus
9175 def withdraw(self,resp,comment):
9176 """ Remove or put a contribution in a conference
9179 if self.isWithdrawn():
9180 #put back the authors in the author index
9181 for auth in self.getAuthorList():
9182 self.getConference().getAuthorIndex().index(auth)
9183 for spk in self.getSpeakerList():
9184 self.getConference().getSpeakerIndex().index(spk)
9185 #change the status of the contribution
9186 self._status=ContribStatusNotSch(self)
9188 else:
9189 #remove the authors from the author index
9190 if self.getConference() is not None:
9191 for auth in self.getAuthorList():
9192 self.getConference().getAuthorIndex().unindex(auth)
9193 for spk in self.getSpeakerList():
9194 self.getConference().unindexSpeaker(spk)
9195 #remove the contribution from any schedule it is included
9196 if self.isScheduled():
9197 self.getSchEntry().getSchedule().removeEntry(self.getSchEntry())
9198 self.getCurrentStatus().withdraw(resp,comment)
9201 def _initSubmissionPrivileges(self):
9202 """Initialises submission privileges list for a contribution.
9204 This is a temporary function used for creating the attribute in the
9205 case it does not exist into the DB
9207 try:
9208 if self._submitters:
9209 pass
9210 except AttributeError:
9211 self._submitters=[] #create the attribute
9212 self.notifyModification(raiseEvent = False)
9214 def _grantSubmission(self,av):
9215 if av not in self._submitters:
9216 self._submitters.append(av)
9217 if self.getConference() is not None:
9218 self.getConference().addContribSubmitter(self,av)
9219 if isinstance(av, MaKaC.user.Avatar):
9220 av.linkTo(self, "submission")
9221 self.notifyModification(raiseEvent = False)
9223 def _grantSubmissionEmail(self, email):
9225 Returns True if submission email was granted. False if email was already in the list.
9227 if not email.lower() in map(lambda x: x.lower(), self.getSubmitterEmailList()):
9228 self.getSubmitterEmailList().append(email)
9229 return True
9230 return False
9232 def revokeSubmissionEmail(self, email):
9233 if email in self.getSubmitterEmailList():
9234 self.getSubmitterEmailList().remove(email)
9235 self._p_changed=1
9237 def grantSubmission(self,sb, sendEmail=True):
9238 """Grants a user with submission privileges for the contribution
9239 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9241 self._initSubmissionPrivileges()
9242 if isinstance(sb, ContributionParticipation) or isinstance(sb, SubContribParticipation):
9243 ah = AvatarHolder()
9244 results=ah.match({"email":sb.getEmail()}, exact=1)
9245 r=None
9246 for i in results:
9247 if i.hasEmail(sb.getEmail()):
9249 break
9250 if r is not None and r.isActivated():
9251 self._grantSubmission(r)
9252 elif sb.getEmail() != "":
9253 self.getConference().getPendingQueuesMgr().addPendingSubmitter(sb, False)
9254 submissionEmailGranted = self._grantSubmissionEmail(sb.getEmail())
9255 if submissionEmailGranted and sendEmail:
9256 notif = pendingQueues._PendingSubmitterNotification( [sb] )
9257 mail.GenericMailer.sendAndLog( notif, self.getConference() )
9258 if self.getConference() is not None:
9259 self.getConference()._getSubmitterIdx().indexEmail(sb.getEmail(),self)
9260 else:
9261 self._grantSubmission(sb)
9263 def _revokeSubmission(self,av):
9264 if av in self._submitters:
9265 self._submitters.remove(av)
9266 if self.getConference() is not None:
9267 self.getConference().removeContribSubmitter(self,av)
9268 if isinstance(av, MaKaC.user.Avatar):
9269 av.unlinkTo(self, "submission")
9270 self.notifyModification(raiseEvent = False)
9272 def revokeSubmission(self,av):
9273 """Removes submission privileges for the specified user
9275 self._initSubmissionPrivileges()
9276 self._revokeSubmission(av)
9278 def revokeAllSubmitters(self):
9279 self._submitters=[]
9280 self.notifyModification(raiseEvent = False)
9282 def getSubmitterList(self):
9283 """Gives the list of users granted with submission privileges
9285 self._initSubmissionPrivileges()
9286 return self._submitters
9288 def getSubmitterEmailList(self):
9289 try:
9290 return self._submittersEmail
9291 except:
9292 self._submittersEmail = []
9293 return self._submittersEmail
9295 def canUserSubmit(self,av):
9296 """Tells whether a user can submit material for the current contribution
9298 if av is None:
9299 return False
9300 self._initSubmissionPrivileges()
9301 for principal in self._submitters:
9302 if principal != None and principal.containsUser( av ):
9303 return True
9304 ret = False
9305 #TODO: Remove this and use pending list
9306 if isinstance(av, MaKaC.user.Avatar):
9307 for email in av.getEmails():
9308 if email.lower() in self.getSubmitterEmailList():
9309 self.grantSubmission(av)
9310 self.revokeSubmissionEmail(email)
9311 ret = True
9312 return ret
9314 def getAccessController(self):
9315 return self.__ac
9317 def getReportNumberHolder(self):
9318 try:
9319 if self._reportNumberHolder:
9320 pass
9321 except AttributeError, e:
9322 self._reportNumberHolder=ReportNumberHolder(self)
9323 return self._reportNumberHolder
9325 def setReportNumberHolder(self, rnh):
9326 self._reportNumberHolder=rnh
9328 @classmethod
9329 def contributionStartDateForSort(cls, contribution):
9330 """ Function that can be used as "key" argument to sort a list of contributions by start date
9331 The contributions with no start date will be at the end with this sort
9333 if contribution.getStartDate():
9334 return contribution.getStartDate()
9335 else:
9336 return maxDatetime()
9338 def getColor(self):
9339 res=""
9340 if self.getSession() is not None:
9341 res=self.getSession().getColor()
9342 return res
9344 def getTextColor(self):
9345 res=""
9346 if self.getSession() is not None:
9347 res=self.getSession().getTextColor()
9348 return res
9350 def getCSBookingManager(self):
9351 return self.getConference().getCSBookingManager()
9353 class AcceptedContribution( Contribution ):
9354 """This class represents a contribution which has been created from an
9355 abstract
9358 def __init__(self,abstract):
9359 Contribution.__init__(self)
9360 abstract.getConference().addContribution(self,abstract.getId())
9361 self._abstract = abstract
9362 self.setTitle( abstract.getTitle() )
9363 #self.setDescription(abstract.getField("content"))
9364 for key in abstract.getFields().keys():
9365 #if key != "content":
9366 self.setField(key, abstract.getField(key))
9367 if isinstance( abstract.getCurrentStatus(),review.AbstractStatusAccepted ):
9368 self.setTrack( abstract.getCurrentStatus().getTrack() )
9369 self.setType( abstract.getCurrentStatus().getType() )
9370 for auth in abstract.getAuthorList():
9371 c_auth = ContributionParticipation()
9372 self._setAuthorValuesFromAbstract( c_auth, auth )
9373 if abstract.isPrimaryAuthor( auth ):
9374 self.addPrimaryAuthor( c_auth )
9375 else:
9376 self.addCoAuthor( c_auth )
9377 if abstract.isSpeaker( auth ):
9378 self.addSpeaker( c_auth )
9379 self._grantSubmission(self.getAbstract().getSubmitter().getUser())
9381 def _setAuthorValuesFromAbstract( self, cAuth, aAuth ):
9382 cAuth.setTitle( aAuth.getTitle() )
9383 cAuth.setFirstName( aAuth.getFirstName() )
9384 cAuth.setFamilyName( aAuth.getSurName() )
9385 cAuth.setEmail( aAuth.getEmail() )
9386 cAuth.setAffiliation( aAuth.getAffiliation() )
9387 cAuth.setAddress( aAuth.getAddress() )
9388 cAuth.setPhone( aAuth.getTelephone() )
9390 def getAbstract( self ):
9391 return self._abstract
9393 def setAbstract(self, abs):
9394 self._abstract = abs
9396 def _initSubmissionPrivileges(self):
9397 """Initialises submission privileges list for a contribution.
9399 In the case of an AcceptedContribution, the list of submitters
9400 must be initialised with the abstract's one.
9402 This is a temporary function used for creating the attribute in the
9403 case it does not exist into the DB
9405 try:
9406 if self._submitters:
9407 pass
9408 except AttributeError:
9409 self._submitters=[]#create the attribute
9410 self._grantSubmission(self.getAbstract().getSubmitter().getUser())
9412 def delete( self ):
9413 """deletes a contribution and all of their subitems
9415 abs = self.getAbstract()
9416 if abs:
9417 cs=abs.getCurrentStatus()
9418 if isinstance(cs, review.AbstractStatusAccepted):
9419 if cs.getTrack() is not None:
9420 abs.addTrack(cs.getTrack())
9421 abs.setCurrentStatus(review.AbstractStatusSubmitted(abs))
9422 abs._setContribution(None)
9423 self.setAbstract(None)
9424 Contribution.delete(self)
9428 class ContribStatus(Persistent):
9432 def __init__(self,contribution,responsible):
9433 self._setContrib(contribution)
9434 self._setResponsible(responsible)
9435 self._setDate()
9437 def clone(self, contribution, responsible):
9438 cs = ContribStatus(contribution, responsible)
9439 cs.setDate(self.getDate())
9440 return cs
9442 def _setContrib(self,newContrib):
9443 self._contrib=newContrib
9445 def getContrib(self):
9446 return self._contrib
9448 def _setResponsible(self,newResp):
9449 self._responsible=newResp
9451 def getResponsible(self):
9452 return self._responsible
9454 def _setDate(self):
9455 self._date=nowutc()
9457 def setDate(self, date):
9458 self._date = date
9460 def getDate(self):
9461 return self._date
9463 def withdraw(self,resp,comments=""):
9464 self._contrib.setStatus(ContribStatusWithdrawn(self.getContrib(),resp,comments))
9466 class ContribStatusNotSch(ContribStatus):
9469 def __init__(self,contrib):
9470 ContribStatus.__init__(self,contrib,None)
9472 def clone(self, contribution):
9473 csns = ContribStatusNotSch(contribution)
9474 csns.setDate(self.getDate())
9475 return csns
9477 ContribStatusSubmitted=ContribStatusNotSch
9479 class ContribStatusSch(ContribStatus):
9482 def __init__(self,contrib):
9483 ContribStatus.__init__(self,contrib,None)
9485 def clone(self, contribution):
9486 css = ContribStatusSch(contribution)
9487 css.setDate(self.getDate())
9488 return css
9490 class ContribStatusWithdrawn(ContribStatus):
9493 def __init__(self,contrib,resp,comments):
9494 ContribStatus.__init__(self,contrib,resp)
9495 self._setComment(comments)
9497 def clone(self, contribution):
9498 csw = ContribStatusWithdrawn(contribution)
9499 csw.setDate(self.getDate())
9500 csw.setComment(self.getComment())
9501 return csw
9503 def _setComment(self,text):
9504 self._comment=text.strip()
9506 def getComment(self):
9507 return self._comment
9509 class ContribStatusNone(ContribStatus):
9510 # This is a special status we assign to contributions that are put in the trash can.
9512 def __init__(self,contrib):
9513 ContribStatus.__init__(self,contrib,None)
9515 def clone(self, contribution):
9516 csn = ContribStatusNone(contribution)
9517 csn.setDate(self.getDate())
9518 return csn
9520 class SubContribParticipation(Persistent, Fossilizable):
9522 fossilizes(ISubContribParticipationFossil)
9524 def __init__( self ):
9525 self._subContrib = None
9526 self._id = ""
9527 self._firstName = ""
9528 self._surName = ""
9529 self._email = ""
9530 self._affiliation = ""
9531 self._address = ""
9532 self._phone = ""
9533 self._title = ""
9534 self._fax = ""
9536 def getConference(self):
9537 if self._subContrib is not None:
9538 return self._subContrib.getConference()
9539 return None
9541 def _notifyModification( self ):
9542 if self._subContrib != None:
9543 self._subContrib.notifyModification()
9545 def setValues(self, data):
9546 self.setFirstName(data.get("firstName", ""))
9547 self.setFamilyName(data.get("familyName",""))
9548 self.setAffiliation(data.get("affilation",""))
9549 self.setAddress(data.get("address",""))
9550 self.setEmail(data.get("email",""))
9551 self.setFax(data.get("fax",""))
9552 self.setTitle(data.get("title",""))
9553 self.setPhone(data.get("phone",""))
9554 self._notifyModification()
9556 def getValues(self):
9557 data={}
9558 data["firstName"]=self.getFirstName()
9559 data["familyName"]=self.getFamilyName()
9560 data["affilation"]=self.getAffiliation()
9561 data["address"]=self.getAddress()
9562 data["email"]=self.getEmail()
9563 data["fax"]=self.getFax()
9564 data["title"]=self.getTitle()
9565 data["phone"]=self.getPhone()
9566 return data
9568 def clone(self):
9569 part = SubContribParticipation()
9570 part.setValues(self.getValues())
9571 return part
9573 def setDataFromAvatar(self,av):
9574 # av is an Avatar object.
9575 if av is None:
9576 return
9577 self.setFirstName(av.getName())
9578 self.setFamilyName(av.getSurName())
9579 self.setEmail(av.getEmail())
9580 self.setAffiliation(av.getOrganisation())
9581 self.setAddress(av.getAddress())
9582 self.setPhone(av.getTelephone())
9583 self.setTitle(av.getTitle())
9584 self.setFax(av.getFax())
9585 self._notifyModification()
9587 def setDataFromAuthor(self,au):
9588 # au is a ContributionParticipation object.
9589 if au is None:
9590 return
9591 self.setFirstName(au.getFirstName())
9592 self.setFamilyName(au.getFamilyName())
9593 self.setEmail(au.getEmail())
9594 self.setAffiliation(au.getAffiliation())
9595 self.setAddress(au.getAddress())
9596 self.setPhone(au.getPhone())
9597 self.setTitle(au.getTitle())
9598 self.setFax(au.getFax())
9599 self._notifyModification()
9601 def setDataFromSpeaker(self,spk):
9602 # spk is a SubContribParticipation object.
9603 if spk is None:
9604 return
9605 self.setFirstName(spk.getFirstName())
9606 self.setFamilyName(spk.getFamilyName())
9607 self.setEmail(spk.getEmail())
9608 self.setAffiliation(spk.getAffiliation())
9609 self.setAddress(spk.getAddress())
9610 self.setPhone(spk.getPhone())
9611 self.setTitle(spk.getTitle())
9612 self.setFax(spk.getFax())
9613 self._notifyModification()
9615 def includeInSubContrib( self, subcontrib, id ):
9616 if self.getSubContrib() == subcontrib and self.getId()==id.strip():
9617 return
9618 self._subContrib = subcontrib
9619 self._id = id
9621 def delete( self ):
9622 self._subContrib = None
9623 TrashCanManager().add(self)
9625 def recover(self):
9626 TrashCanManager().remove(self)
9628 @Updates ('MaKaC.conference.SubContribParticipation', 'id')
9629 def setId(self, newId):
9630 self._id = newId
9632 def getId( self ):
9633 return self._id
9635 def getSubContrib( self ):
9636 return self._subContrib
9638 def getContribution( self ):
9639 if self._subContrib is not None:
9640 return self._subContrib.getContribution()
9641 return None
9643 # def getLocator(self):
9644 # if self.getSubContrib() is None:
9645 # return None
9646 # loc=self.getSubContrib().getLocator()
9647 # loc["authId"]=self.getId()
9648 # return loc
9650 def _unindex(self):
9651 contrib=self.getContribution()
9652 if contrib is not None:
9653 conf=contrib.getConference()
9654 if conf is not None:
9655 conf.unindexAuthor(self)
9656 conf.unindexSpeaker(self)
9658 def _index(self):
9659 contrib=self.getContribution()
9660 if contrib is not None:
9661 conf=contrib.getConference()
9662 if conf is not None:
9663 conf.indexAuthor(self)
9664 conf.indexSpeaker(self)
9666 @Updates ('MaKaC.conference.SubContribParticipation', 'firstName')
9667 def setFirstName( self, newName ):
9668 tmp=newName.strip()
9669 if tmp==self._firstName:
9670 return
9671 self._unindex()
9672 self._firstName=tmp
9673 self._index()
9674 self._notifyModification()
9676 def getFirstName( self ):
9677 return self._firstName
9679 def getName( self ):
9680 return self._firstName
9682 @Updates ('MaKaC.conference.SubContribParticipation', 'familyName')
9683 def setFamilyName( self, newName ):
9684 tmp=newName.strip()
9685 if tmp==self._surName:
9686 return
9687 self._unindex()
9688 self._surName=tmp
9689 self._index()
9690 self._notifyModification()
9692 def getFamilyName( self ):
9693 return self._surName
9695 def getSurName( self ):
9696 return self._surName
9698 @Updates ('MaKaC.conference.SubContribParticipation', 'email')
9699 def setEmail( self, newMail ):
9700 tmp=newMail.strip()
9701 if tmp==self._email:
9702 return
9703 self._unindex()
9704 self._email=newMail.strip()
9705 self._index()
9706 self._notifyModification()
9708 def getEmail( self ):
9709 return self._email
9711 @Updates ('MaKaC.conference.SubContribParticipation', 'affiliation')
9712 def setAffiliation( self, newAffil ):
9713 self._affiliation = newAffil.strip()
9714 self._notifyModification()
9716 def getAffiliation( self ):
9717 return self._affiliation
9719 @Updates ('MaKaC.conference.SubContribParticipation', 'address')
9720 def setAddress( self, newAddr ):
9721 self._address = newAddr.strip()
9722 self._notifyModification()
9724 def getAddress( self ):
9725 return self._address
9727 @Updates ('MaKaC.conference.SubContribParticipation', 'phone')
9728 def setPhone( self, newPhone ):
9729 self._phone = newPhone.strip()
9730 self._notifyModification()
9732 def getPhone( self ):
9733 return self._phone
9735 @Updates ('MaKaC.conference.SubContribParticipation', 'title')
9736 def setTitle( self, newTitle ):
9737 self._title = newTitle.strip()
9738 self._notifyModification()
9740 def getTitle( self ):
9741 return self._title
9743 def setFax( self, newFax ):
9744 self._fax = newFax.strip()
9745 self._notifyModification()
9747 def getFax( self ):
9748 try:
9749 if self._fax:
9750 pass
9751 except AttributeError:
9752 self._fax=""
9753 return self._fax
9755 def getFullName( self ):
9756 res = self.getFullNameNoTitle()
9757 if self.getTitle() != "":
9758 res = "%s %s"%( self.getTitle(), res )
9759 return res
9761 def getFullNameNoTitle( self ):
9762 res = self.getFamilyName().decode('utf-8').upper().encode('utf-8')
9763 if self.getFirstName() != "":
9764 if res.strip() != "":
9765 res = "%s, %s"%( res, self.getFirstName() )
9766 else:
9767 res = self.getFirstName()
9768 return res
9770 def getAbrName(self):
9771 res = self.getFamilyName()
9772 if self.getFirstName() != "":
9773 if res != "":
9774 res = "%s, "%res
9775 res = "%s%s."%(res, self.getFirstName()[0].upper())
9776 return res
9778 class SubContribution(CommonObjectBase, Locatable):
9782 fossilizes(ISubContributionFossil, ISubContributionWithSpeakersFossil)
9784 def __init__( self, **subContData ):
9785 self.parent = None
9786 self.id = ""
9787 self.title = ""
9788 self.description = ""
9789 self.__schEntry = None
9790 self.duration = timedelta( minutes=15 )
9791 self.speakers = []
9792 self.speakerText = ""
9794 self.materials = {}
9795 self.__materialGenerator = Counter() # Provides material unique
9796 # identifiers whithin the current
9797 self.poster = None # contribution
9798 self.paper = None
9799 self.slides = None
9800 self.video = None
9801 self.poster = None
9802 self.minutes = None
9803 self._authorGen = Counter()
9804 self._keywords = ""
9806 def __str__(self):
9807 if self.parent:
9808 parentId = self.parent.getId()
9809 if self.getConference():
9810 grandpaId = self.getConference().getId()
9811 else:
9812 grandpaId = None
9813 else:
9814 parentId = None
9815 grandpaId = None
9816 return "<SubCont %s:%s:%s@%s>" % (grandpaId, parentId, self.getId(), hex(id(self)))
9818 def isFullyPublic( self ):
9819 if hasattr(self, "_fullyPublic"):
9820 return self._fullyPublic
9821 else:
9822 self.setFullyPublic()
9823 return self._fullyPublic
9825 def setFullyPublic( self ):
9826 for res in self.getAllMaterialList():
9827 if not res.isFullyPublic():
9828 self._fullyPublic = False
9829 self._p_changed = 1
9830 return
9831 self._fullyPublic = True
9832 self._p_changed = 1
9834 def updateFullyPublic( self ):
9835 self.setFullyPublic()
9836 self.getOwner().updateFullyPublic()
9838 def getAccessController(self):
9839 return self.getOwner().getAccessController()
9841 def getKeywords(self):
9842 try:
9843 return self._keywords
9844 except:
9845 self._keywords = ""
9846 return ""
9848 def setKeywords(self, keywords):
9849 self._keywords = keywords
9851 def getLogInfo(self):
9852 data = {}
9854 data["subject"] = self.getTitle()
9855 data["id"] = self.id
9856 data["title"] = self.title
9857 data["parent title"] = self.getParent().getTitle()
9858 data["description"] = self.description
9859 data["duration"] = "%s"%self.duration
9860 data["minutes"] = self.minutes
9862 for sp in self.speakers :
9863 data["speaker %s"%sp.getId()] = sp.getFullName()
9865 return data
9868 def clone(self, deltaTime, parent, options):
9869 sCont = SubContribution()
9870 sCont.setParent(parent)
9871 sCont.setTitle(self.getTitle())
9872 sCont.setDescription(self.getDescription())
9873 sCont.setKeywords(self.getKeywords())
9874 dur = self.getDuration()
9875 hours = dur.seconds / 3600
9876 minutes = (dur.seconds % 3600) / 60
9877 sCont.setDuration(hours, minutes)
9878 sCont.setReportNumberHolder(self.getReportNumberHolder().clone(self))
9880 # There is no _order attribute in this class
9882 if options.get("authors", False) :
9883 for s in self.getSpeakerList() :
9884 sCont.newSpeaker(s.clone())
9885 sCont.setSpeakerText(self.getSpeakerText())
9887 if options.get("materials", False) :
9888 for m in self.getMaterialList() :
9889 sCont.addMaterial(m.clone(sCont))
9890 if self.getPaper() is not None:
9891 sCont.setPaper(self.getPaper().clone(sCont))
9892 if self.getSlides() is not None:
9893 sCont.setSlides(self.getSlides().clone(sCont))
9894 if self.getVideo() is not None:
9895 sCont.setVideo(self.getVideo().clone(sCont))
9896 if self.getPoster() is not None:
9897 sCont.setPoster(self.getPoster().clone(sCont))
9898 if self.getMinutes() is not None:
9899 sCont.setMinutes(self.getMinutes().clone(sCont))
9902 sCont.notifyModification()
9903 return sCont
9905 def notifyModification( self ):
9906 parent = self.getParent()
9907 if parent:
9908 parent.setModificationDate()
9909 self._notify('infoChanged')
9910 self._p_changed = 1
9912 def getCategoriesPath(self):
9913 return self.getConference().getCategoriesPath()
9915 def getLocator( self ):
9916 """Gives back a globaly unique identification encapsulated in a Locator
9917 object for the contribution instance
9920 lconf = self.getOwner().getLocator()
9921 lconf["subContId"] = self.getId()
9922 return lconf
9925 def setId( self, newId ):
9926 self.id = newId
9928 def getId( self ):
9929 return self.id
9931 def getUniqueId( self ):
9932 """returns (string) the unique identifier of the item"""
9933 """used mainly in the web session access key table"""
9934 return "%ssc%s" % (self.getParent().getUniqueId(),self.id)
9936 def setTitle( self, newTitle ):
9937 self.title = newTitle.strip()
9938 self.notifyModification()
9940 def getTitle( self ):
9941 if self.title.strip() == "":
9942 return "(no title)"
9943 return self.title
9945 def setDescription( self, newDesc ):
9946 self.description = newDesc.strip()
9947 self.notifyModification()
9949 def getDescription( self ):
9950 return self.description
9952 def setParent(self,parent):
9953 self.parent = parent
9954 if self.parent == None:
9955 return
9957 def getParent( self ):
9958 return self.parent
9960 def setOwner(self, owner):
9961 self.setParent(owner)
9963 def getOwner( self ):
9964 return self.getParent()
9966 def getConference( self ):
9967 return self.parent.getConference()
9969 def getSession( self ):
9970 return self.parent.getSession()
9972 def getContribution(self):
9973 return self.parent
9975 def getDuration( self ):
9976 return self.duration
9978 def setDuration( self, hours, minutes=0, dur=0 ):
9979 if dur!=0:
9980 self.duration=dur
9981 else:
9982 hours = int( hours )
9983 minutes = int( minutes )
9984 self.duration = timedelta(hours=hours,minutes=minutes )
9985 self.notifyModification()
9987 def getLocation( self ):
9988 return self.getOwner().getLocation()
9990 def getRoom( self ):
9991 return self.getOwner().getRoom()
9993 def getSpeakerById( self, id ):
9996 for spk in self.speakers:
9997 if spk.getId() == id:
9998 return spk
9999 return None
10001 def newSpeaker( self, spk ):
10004 self.speakers.append( spk )
10005 try:
10006 if self._authorGen:
10007 pass
10008 except AttributeError:
10009 self._authorGen=Counter()
10010 newId = spk.getId()
10011 if newId == "":
10012 newId = str( self._authorGen.newCount() )
10013 spk.includeInSubContrib(self, newId)
10014 if self.getConference() is not None:
10015 self.getConference().indexSpeaker(spk)
10016 self.notifyModification()
10018 def removeSpeaker( self, spk ):
10021 if spk not in self.speakers:
10022 return
10023 self.speakers.remove( spk )
10024 if self.getConference() is not None:
10025 self.getConference().unindexSpeaker(spk)
10026 spk.delete()
10027 self.notifyModification()
10029 def recoverSpeaker(self, spk):
10030 self.newSpeaker(spk)
10031 spk.recover()
10033 def isSpeaker( self, spk):
10036 return spk in self._speakers
10038 def getSpeakerList ( self ):
10041 return self.speakers
10043 def getSpeakerText( self ):
10044 #to be removed
10045 try:
10046 if self.speakerText:
10047 pass
10048 except AttributeError, e:
10049 self.speakerText = ""
10050 return self.speakerText
10052 def setSpeakerText( self, newText ):
10053 self.speakerText = newText.strip()
10055 def appendSpeakerText( self, newText ):
10056 self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) )
10058 # """
10059 # There is no _order attribute in this class -
10060 # the methods below are either obsolate or the feature has not been implemented
10061 # """
10062 # def setOrder( self, order ):
10063 # self._order = order
10064 # self.notifyModification()
10066 # def getOrder(self):
10067 # return self._order
10069 def canIPAccess( self, ip ):
10070 return self.getOwner().canIPAccess(ip)
10072 def isProtected( self ):
10073 return self.hasProtectedOwner()
10075 def getAccessProtectionLevel( self ):
10076 return self.getOwner().getAccessProtectionLevel()
10078 def hasAnyProtection( self ):
10079 """Tells whether a subContribution has any kind of protection over it:
10080 access or domain protection.
10082 return self.getOwner().hasAnyProtection()
10084 def getManagerList( self ):
10085 return self.parent.getManagerList()
10087 def hasProtectedOwner( self ):
10088 if self.getOwner() != None:
10089 return self.getOwner().isProtected()
10090 return False
10092 def getAccessKey( self ):
10093 return self.getOwner().getAccessKey()
10095 def getModifKey( self ):
10096 return self.getConference().getModifKey()
10098 def canView( self, aw ):
10099 """tells whether the specified user has access to the current object
10100 or any of its sub-objects
10102 if self.canAccess( aw ):
10103 return True
10104 return False
10106 def isAllowedToAccess( self, user ):
10107 return self.parent.isAllowedToAccess( user )
10109 def canAccess( self, aw ):
10110 return self.getOwner().canAccess(aw)
10112 def canModify( self, aw ):
10113 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
10115 def canUserModify( self, av ):
10116 """Tells whether a user is allowed to modify the current contribution:
10117 only if the user is granted to modify the contribution or the user
10118 can modify any of its upper objects (i.e. conference or session).
10120 return self.getParent().canUserModify( av )
10122 def canUserSubmit( self, av ):
10123 return self.getOwner().canUserSubmit( av )
10125 def getAllowedToAccessList( self ):
10126 """Currently the SubContribution class has no access list.
10127 But instead of returning the owner Contribution's access list,
10128 I am returning an empty list. Methods such as getRecursiveAllowedToAccess()
10129 will call the owner Contribution anyway.
10131 return []
10133 def addMaterial( self, newMat ):
10134 newMat.setId( str(self.__materialGenerator.newCount()) )
10135 newMat.setOwner( self )
10136 self.materials[ newMat.getId() ] = newMat
10137 self.notifyModification()
10139 def removeMaterial( self, mat):
10140 if mat.getId() in self.materials.keys():
10141 self.materials[mat.getId()].setOwner(None)
10142 del self.materials[ mat.getId() ]
10143 mat.delete()
10144 self.notifyModification()
10145 elif mat.getId().lower() == 'paper':
10146 self.removePaper()
10147 self.notifyModification()
10148 elif mat.getId().lower() == 'slides':
10149 self.removeSlides()
10150 self.notifyModification()
10151 elif mat.getId().lower() == 'minutes':
10152 self.removeMinutes()
10153 self.notifyModification()
10154 elif mat.getId().lower() == 'video':
10155 self.removeVideo()
10156 self.notifyModification()
10157 elif mat.getId().lower() == 'poster':
10158 self.removePoster()
10159 self.notifyModification()
10161 def recoverMaterial(self, recMat):
10162 # Id must already be set in recMat.
10163 recMat.setOwner( self )
10164 self.materials[ recMat.getId() ] = recMat
10165 recMat.recover()
10166 self.notifyModification()
10168 def getMaterialRegistry(self):
10170 Return the correct material registry for this type
10172 from MaKaC.webinterface.materialFactories import SubContributionMFRegistry
10173 return SubContributionMFRegistry
10175 def getMaterialById( self, matId ):
10176 if matId.lower() == 'paper':
10177 return self.getPaper()
10178 elif matId.lower() == 'slides':
10179 return self.getSlides()
10180 elif matId.lower() == 'video':
10181 return self.getVideo()
10182 elif matId.lower() == 'poster':
10183 return self.getPoster()
10184 elif matId.lower() == 'minutes':
10185 return self.getMinutes()
10186 elif self.materials.has_key(matId):
10187 return self.materials[ matId ]
10188 return None
10190 def getMaterialList( self ):
10191 return self.materials.values()
10193 def getAllMaterialList( self ):
10194 l = self.getMaterialList()
10195 if self.getPaper():
10196 l.append( self.getPaper() )
10197 if self.getSlides():
10198 l.append( self.getSlides() )
10199 if self.getVideo():
10200 l.append( self.getVideo() )
10201 if self.getMinutes():
10202 l.append( self.getMinutes() )
10203 if self.getPoster():
10204 l.append( self.getPoster() )
10205 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
10206 return l
10208 def setPaper( self, newPaper ):
10209 if self.getPaper() != None:
10210 raise MaKaCError( _("The paper for this subcontribution has already been set"), _("Contribution"))
10211 self.paper=newPaper
10212 self.paper.setOwner( self )
10213 self.notifyModification()
10215 def removePaper( self ):
10216 if self.getPaper() is None:
10217 return
10218 self.paper.delete()
10219 self.paper.setOwner(None)
10220 self.paper = None
10221 self.notifyModification()
10223 def recoverPaper(self, p):
10224 self.setPaper(p)
10225 p.recover()
10227 def getPaper( self ):
10228 return self.paper
10230 def setSlides( self, newSlides ):
10231 if self.getSlides() != None:
10232 raise MaKaCError( _("The slides for this subcontribution have already been set"), _("Contribution"))
10233 self.slides=newSlides
10234 self.slides.setOwner( self )
10235 self.notifyModification()
10237 def removeSlides( self ):
10238 if self.getSlides() is None:
10239 return
10240 self.slides.delete()
10241 self.slides.setOwner( None )
10242 self.slides = None
10243 self.notifyModification()
10245 def recoverSlides(self, s):
10246 self.setSlides(s)
10247 s.recover()
10249 def getSlides( self ):
10250 return self.slides
10252 def setVideo( self, newVideo ):
10253 if self.getVideo() != None:
10254 raise MaKaCError( _("the video for this subcontribution has already been set"))
10255 self.video=newVideo
10256 self.video.setOwner( self )
10257 self.notifyModification()
10259 def removeVideo( self ):
10260 if self.getVideo() is None:
10261 return
10262 self.video.delete()
10263 self.video.setOwner(None)
10264 self.video = None
10265 self.notifyModification()
10267 def recoverVideo(self, v):
10268 self.setVideo(v)
10269 v.recover()
10271 def getVideo( self ):
10272 try:
10273 if self.video:
10274 pass
10275 except AttributeError:
10276 self.video = None
10277 return self.video
10279 def setPoster( self, newPoster ):
10280 if self.getPoster() != None:
10281 raise MaKaCError( _("the poster for this subcontribution has already been set"))
10282 self.poster=newPoster
10283 self.poster.setOwner( self )
10284 self.notifyModification()
10286 def removePoster( self ):
10287 if self.getPoster() is None:
10288 return
10289 self.poster.delete()
10290 self.poster.setOwner(None)
10291 self.poster = None
10292 self.notifyModification()
10294 def recoverPoster(self, p):
10295 self.setPoster(p)
10296 p.recover()
10298 def getPoster( self ):
10299 try:
10300 if self.poster:
10301 pass
10302 except AttributeError:
10303 self.poster = None
10304 return self.poster
10306 def setMinutes( self, newMinutes ):
10307 if self.getMinutes() != None:
10308 raise MaKaCError( _("the Minutes for this subcontribution has already been set"))
10309 self.minutes=newMinutes
10310 self.minutes.setOwner( self )
10311 self.notifyModification()
10313 def createMinutes( self ):
10314 if self.getMinutes() != None:
10315 raise MaKaCError( _("The minutes for this subcontribution have already been created"), _("Sub Contribution"))
10316 self.minutes = Minutes()
10317 self.minutes.setOwner( self )
10318 self.notifyModification()
10319 return self.minutes
10321 def removeMinutes( self ):
10322 if self.getMinutes() is None:
10323 return
10324 self.minutes.delete()
10325 self.minutes.setOwner( None )
10326 self.minutes = None
10327 self.notifyModification()
10329 def recoverMinutes(self, min):
10330 self.removeMinutes() # To ensure that the current minutes are put in
10331 # the trash can.
10332 self.minutes = min
10333 self.minutes.setOwner( self )
10334 min.recover()
10335 self.notifyModification()
10336 return self.minutes
10338 def getMinutes( self ):
10339 #To be removed
10340 try:
10341 if self.minutes:
10342 pass
10343 except AttributeError, e:
10344 self.minutes = None
10345 return self.minutes
10347 def getMasterSchedule( self ):
10348 return self.getOwner().getSchedule()
10350 def delete(self):
10352 self._notify('deleted', self.getOwner())
10354 while len(self.getSpeakerList()) > 0:
10355 self.removeSpeaker(self.getSpeakerList()[0])
10356 for mat in self.getMaterialList():
10357 self.removeMaterial(mat)
10358 self.removePaper()
10359 self.removeSlides()
10360 self.removeVideo()
10361 self.removePoster()
10362 self.removeMinutes()
10363 TrashCanManager().add(self)
10365 #self.unindex()
10367 def recover(self):
10368 TrashCanManager().remove(self)
10370 def getReportNumberHolder(self):
10371 try:
10372 if self._reportNumberHolder:
10373 pass
10374 except AttributeError, e:
10375 self._reportNumberHolder=ReportNumberHolder(self)
10376 return self._reportNumberHolder
10378 def setReportNumberHolder(self, rnh):
10379 self._reportNumberHolder=rnh
10381 class Material(CommonObjectBase):
10382 """This class represents a set of electronic documents (resources) which can
10383 be attached to a conference, a session or a contribution.
10384 A material can be of several types (achieved by specialising this class)
10385 and is like a container of files which have some relation among them.
10386 It contains the minimal set of attributes to store basic meta data and
10387 provides useful operations to access and manage it.
10388 Attributes:
10389 owner -- (Conference, Session or Contribution) Object to which the
10390 material is attached to
10391 id -- (string) Material unique identifier. Normally used to uniquely
10392 identify a material within a conference, session or contribution
10393 title -- (string) Material denomination
10394 description -- (string) Longer text describing in more detail material
10395 intentions
10396 type -- (string) String identifying the material classification
10397 resources -- (PMapping) Collection of resouces grouped within the
10398 material. Dictionary of references to Resource objects indexed
10399 by their unique relative id.
10402 fossilizes(IMaterialMinimalFossil, IMaterialFossil)
10404 def __init__( self, materialData=None ):
10405 self.id = "not assigned"
10406 self.__resources = {}
10407 self.__resourcesIdGen = Counter()
10408 self.title = ""
10409 self.description = ""
10410 self.type = ""
10411 self.owner = None
10412 self.__ac = AccessController(self)
10413 self._mainResource = None
10415 def isFullyPublic( self ):
10416 if hasattr(self, "_fullyPublic"):
10417 return self._fullyPublic
10418 else:
10419 self.setFullyPublic()
10420 return self._fullyPublic
10422 def setFullyPublic( self ):
10423 if self.isProtected():
10424 self._fullyPublic = False
10425 self._p_changed = 1
10426 return
10427 for res in self.getResourceList():
10428 if res.isProtected():
10429 self._fullyPublic = False
10430 self._p_changed = 1
10431 return
10432 self._fullyPublic = True
10433 self._p_changed = 1
10435 def updateFullyPublic( self ):
10436 self.setFullyPublic()
10437 self.getOwner().updateFullyPublic()
10439 def setValues( self, params ):
10440 """Sets all the values of the current material object from a diccionary
10441 containing the following key-value pairs:
10442 title-(str)
10443 description-(str)
10444 Please, note that this method sets ALL values which means that if
10445 the given dictionary doesn't contain any of the keys the value
10446 will set to a default value.
10448 self.setTitle( params.get( "title", _("NO TITLE ASSIGNED") ) )
10449 self.setDescription( params.get( "description", "" ) )
10450 self.notifyModification()
10452 def clone ( self, owner):
10453 mat = type(self)()
10454 mat.setTitle(self.getTitle())
10455 mat.setDescription(self.getDescription())
10456 mat.notifyModification()
10458 mat.setId(self.getId())
10459 mat.setOwner(owner)
10460 mat.setType(self.getType())
10462 mat.setProtection(self.getAccessController()._getAccessProtection())
10463 mat.setAccessKey(self.getAccessKey())
10464 rlist = self.getResourceList()
10465 for r in rlist:
10466 newres = r.clone(mat)
10467 mat.addResource(newres)
10469 mat.setMainResource(self.getMainResource())
10471 return mat
10473 def notifyModification( self ):
10474 parent = self.getOwner()
10475 if parent:
10476 parent.setModificationDate()
10477 self._p_changed = 1
10479 def getLocator( self ):
10480 if self.owner == None:
10481 return Locator()
10482 lconf = self.owner.getLocator()
10483 lconf["materialId"] = self.getId()
10484 return lconf
10486 def setId( self, newId ):
10487 self.id = str(newId).strip()
10489 def getId( self ):
10490 return self.id
10492 def getUniqueId( self ):
10493 """returns (string) the unique identifier of the item"""
10494 """used mainly in the web session access key table"""
10495 return "%sm%s" % (self.getOwner().getUniqueId(),self.id)
10497 def setOwner( self, newOwner ):
10498 self.owner = newOwner
10500 def getOwner( self ):
10501 return self.owner
10503 def getCategory( self ):
10504 if isinstance(self.getOwner(), Category):
10505 return self.getOwner()
10506 return None
10508 def getConference( self ):
10509 if type(self.getOwner()) is Conference:
10510 return self.getOwner()
10511 if type(self.getOwner()) is Category:
10512 return None
10513 return self.getOwner().getConference()
10515 def getSession( self ):
10516 if self.getContribution():
10517 return self.getContribution().getSession()
10518 if isinstance(self.getOwner(), Session):
10519 return self.getOwner()
10520 if isinstance(self.getOwner(), SubContribution):
10521 return self.getOwner().getSession()
10522 return None
10524 def getContribution( self ):
10525 if self.getSubContribution():
10526 return self.getSubContribution().getContribution()
10527 if isinstance(self.getOwner(), Contribution):
10528 return self.getOwner()
10529 return None
10531 def getSubContribution( self ):
10532 if isinstance(self.getOwner(), SubContribution):
10533 return self.getOwner()
10534 return None
10536 @Updates (['MaKaC.conference.Material',
10537 'MaKaC.conference.Minutes',
10538 'MaKaC.conference.Paper',
10539 'MaKaC.conference.Slides',
10540 'MaKaC.conference.Video',
10541 'MaKaC.conference.Poster',
10542 'MaKaC.conference.Reviewing'],'title')
10543 def setTitle( self, newTitle ):
10544 self.title = newTitle.strip()
10545 self.notifyModification()
10547 def getTitle( self ):
10548 return self.title
10550 @Updates (['MaKaC.conference.Material',
10551 'MaKaC.conference.Minutes',
10552 'MaKaC.conference.Paper',
10553 'MaKaC.conference.Slides',
10554 'MaKaC.conference.Video',
10555 'MaKaC.conference.Poster',
10556 'MaKaC.conference.Reviewing'], 'description')
10557 def setDescription( self, newDescription ):
10558 self.description = newDescription.strip()
10559 self.notifyModification()
10561 def getDescription( self ):
10562 return self.description
10564 def setType( self, newType ):
10565 self.type = newType.strip()
10566 self.notifyModification()
10568 def getType( self ):
10569 return self.type
10571 def getReviewingState(self):
10572 """ Returns the reviewing state of a material.
10573 The state is represented by an integer:
10574 0 : there's no reviewing state because the material does not belong to a contribution, or the conference
10575 has not reviewing module enabled, or the module is enabled but the mode is "no reviewing"
10576 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
10577 2 : the material is subject to reviewing, but has not been submitted yet by the author
10578 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
10579 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
10580 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
10582 if isinstance(self.owner, Contribution):
10583 conference = self.owner.getConference()
10584 if conference.getConfPaperReview().getChoice() == ConferencePaperReview.NO_REVIEWING: #conference has no reviewing process
10585 return 0
10586 else: #conference has reviewing
10587 #if self.id in reviewableMaterials: #material is reviewable
10588 if isinstance(self, Reviewing): #material is reviewable
10589 lastReview = self.owner.getReviewManager().getLastReview()
10590 if lastReview.isAuthorSubmitted(): #author has submitted
10591 refereeJudgement = lastReview.getRefereeJudgement()
10592 if refereeJudgement.isSubmitted(): #referee has submitted judgement
10593 if refereeJudgement.getJudgement() == "Accept":
10594 return 4
10595 elif refereeJudgement.getJudgement() == "Reject":
10596 return 5
10597 else:
10598 #we should never arrive here because referee judgements that are 'To be corrected'
10599 #or a custom state should imply a new review being created, so the state is back to 2
10600 raise MaKaCError("RefereeJudgement should be 'Accept' or 'Reject' in this method")
10601 else: #referee has not submitted judgement
10602 return 3
10603 else: #author has not submitted
10604 return 2
10605 else: #material is not reviewable
10606 return 1
10607 else: #material does not belong to a contribution
10608 return 0
10610 def _getRepository( self ):
10611 dbRoot = DBMgr.getInstance().getDBConnection().root()
10612 try:
10613 fr = dbRoot["local_repositories"]["main"]
10614 except KeyError, e:
10615 fr = fileRepository.MaterialLocalRepository()
10616 dbRoot["local_repositories"] = OOBTree()
10617 dbRoot["local_repositories"]["main"] = fr
10618 return fr
10620 def hasFile( self, name ):
10621 for f in self.getResourceList():
10622 if f.getName() == name:
10623 return True
10624 return False
10626 def addResource( self, newRes, forcedFileId = None ):
10627 newRes.setOwner( self )
10628 newRes.setId( str( self.__resourcesIdGen.newCount() ) )
10629 newRes.archive( self._getRepository(), forcedFileId = forcedFileId )
10630 self.__resources[newRes.getId()] = newRes
10631 self.notifyModification()
10632 Logger.get('storage').debug("Finished storing resource %s for material %s" % (newRes.getId(), self.getLocator()))
10634 def getResourceList( self ):
10635 list = self.__resources.values()
10636 list.sort(utils.sortFilesByName)
10637 return list
10639 def getNbResources(self ):
10640 return len(self.__resources)
10642 def getResourceById( self, id ):
10643 return self.__resources[id]
10645 def removeResource( self, res ):
10646 if res.getId() in self.__resources.keys():
10647 del self.__resources[ res.getId() ]
10648 res.delete()
10649 self.notifyModification()
10650 if self.getMainResource() is not None and \
10651 self._mainResource.getId() == res.getId():
10652 self._mainResource = None
10654 def recoverResource(self, recRes):
10655 recRes.setOwner(self)
10656 self.__resources[recRes.getId()] = recRes
10657 recRes.recover()
10658 self.notifyModification()
10660 def getMainResource(self):
10661 try:
10662 if self._mainResource:
10663 pass
10664 except AttributeError:
10665 self._mainResource = None
10666 return self._mainResource
10668 def setMainResource(self, mr):
10669 self._mainResource = mr
10671 def delete( self ):
10672 for res in self.getResourceList():
10673 self.removeResource( res )
10674 TrashCanManager().add(self)
10676 def recover(self):
10677 TrashCanManager().remove(self)
10679 def canIPAccess( self, ip ):
10680 if not self.__ac.canIPAccess( ip ):
10681 return False
10682 if self.getOwner() != None:
10683 return self.getOwner().canIPAccess(ip)
10684 return True
10686 def isProtected( self ):
10687 # tells if a material is protected or not
10688 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
10690 def getAccessProtectionLevel( self ):
10691 return self.__ac.getAccessProtectionLevel()
10693 def isItselfProtected( self ):
10694 return self.__ac.isItselfProtected()
10697 def hasProtectedOwner( self ):
10698 if self.getOwner() != None:
10699 return self.getOwner().isProtected()
10700 return False
10703 @Updates (['MaKaC.conference.Material',
10704 'MaKaC.conference.Minutes',
10705 'MaKaC.conference.Paper',
10706 'MaKaC.conference.Slides',
10707 'MaKaC.conference.Video',
10708 'MaKaC.conference.Poster',
10709 'MaKaC.conference.Reviewing'], 'protection', lambda(x): int(x))
10711 def setProtection( self, private ):
10712 self.__ac.setProtection( private )
10713 self.updateFullyPublic()
10714 self._p_changed = 1
10716 def isHidden( self ):
10717 return self.__ac.isHidden()
10719 @Updates (['MaKaC.conference.Material',
10720 'MaKaC.conference.Minutes',
10721 'MaKaC.conference.Paper',
10722 'MaKaC.conference.Slides',
10723 'MaKaC.conference.Video',
10724 'MaKaC.conference.Poster',
10725 'MaKaC.conference.Reviewing'], 'hidden')
10726 def setHidden( self, hidden ):
10727 self.__ac.setHidden( hidden )
10728 self._p_changed = 1
10731 @Updates (['MaKaC.conference.Material',
10732 'MaKaC.conference.Minutes',
10733 'MaKaC.conference.Paper',
10734 'MaKaC.conference.Slides',
10735 'MaKaC.conference.Video',
10736 'MaKaC.conference.Poster',
10737 'MaKaC.conference.Reviewing'], 'accessKey')
10739 def setAccessKey( self, pwd="" ):
10740 self.__ac.setAccessKey(pwd)
10741 self._p_changed = 1
10743 def getAccessKey( self ):
10744 return self.__ac.getAccessKey()
10746 def grantAccess( self, prin ):
10747 self.__ac.grantAccess( prin )
10748 if isinstance(prin, MaKaC.user.Avatar):
10749 prin.linkTo(self, "access")
10750 self._p_changed = 1
10752 def revokeAccess( self, prin ):
10753 self.__ac.revokeAccess( prin )
10754 if isinstance(prin, MaKaC.user.Avatar):
10755 prin.unlinkTo(self, "access")
10756 self._p_changed = 1
10758 def canView( self, aw ):
10759 """tells whether the specified user has access to the current object
10760 or any of its sub-objects
10762 if self.isHidden() and not self.canAccess( aw ):
10763 return False
10764 else:
10765 return True
10767 def isAllowedToAccess( self, user ):
10768 return (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or self.__ac.canUserAccess( user ) or self.canUserModify(user)
10770 def canAccess( self, aw ):
10772 # Allow harvesters (Invenio, offline cache) to access
10773 # protected pages
10774 if self.__ac.isHarvesterIP(aw.getIP()):
10775 return True
10776 #####################################################
10778 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
10779 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
10780 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
10781 return True
10783 canUserAccess = self.isAllowedToAccess( aw.getUser() )
10784 canIPAccess = self.canIPAccess( aw.getIP() )
10785 if not self.isProtected():
10786 return canUserAccess or canIPAccess
10787 else:
10788 canKeyAccess = self.canKeyAccess(aw)
10789 return canUserAccess or canKeyAccess
10791 def canKeyAccess( self, aw ):
10792 sess = aw.getSession()
10793 if not sess:
10794 return False
10795 keys = sess.getVar("accessKeys")
10796 if keys != None:
10797 key = keys.get(self.getUniqueId(),"")
10798 if self.getAccessKey() != "":
10799 return self.__ac.canKeyAccess(key)
10800 elif self.getConference() != None:
10801 return self.getConference().canKeyAccess(aw, key)
10802 return False
10804 def grantModification( self, prin ):
10805 self.__ac.grantModification( prin )
10806 if isinstance(prin, MaKaC.user.Avatar):
10807 prin.linkTo(self, "manager")
10808 self._p_changed = 1
10810 def revokeModification( self, prin ):
10811 self.__ac.revokeModification( prin )
10812 if isinstance(prin, MaKaC.user.Avatar):
10813 prin.unlinkTo(self, "manager")
10814 self._p_changed = 1
10816 def canModify( self, aw ):
10817 return self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw ))
10819 def canUserModify( self, user ):
10820 """Tells whether a user is allowed to modify the current contribution:
10821 only if the user is granted to modify the contribution or the user
10822 can modify any of its upper objects (i.e. conference or session).
10824 return self.getOwner().canUserModify( user )
10826 def getModifKey( self ):
10827 return self.getConference().getModifKey()
10829 def getManagerList( self ):
10830 return self.__ac.getModifierList()
10832 def getAllowedToAccessList( self ):
10833 return self.__ac.getAccessList()
10835 def requireDomain( self, dom ):
10836 self.__ac.requireDomain( dom )
10837 self._p_changed = 1
10839 def freeDomain( self, dom ):
10840 self.__ac.freeDomain( dom )
10841 self._p_changed = 1
10843 def getDomainList( self ):
10844 return self.__ac.getRequiredDomainList()
10846 def getAccessController(self):
10847 return self.__ac
10850 class Reviewing(Material):
10852 def __init__( self, materialData = None ):
10853 Material.__init__( self, materialData )
10854 self.id = "reviewing"
10856 def setId( self, newId ):
10857 return
10859 def getContribution(self):
10860 if isinstance(self.getOwner(), Review):
10861 return self.getOwner().getContribution()
10862 return Material.getContribution(self)
10864 class Paper(Material):
10866 def __init__( self, materialData = None ):
10867 Material.__init__( self, materialData )
10868 self.id = "paper"
10870 def setId( self, newId ):
10871 return
10875 class Slides(Material):
10877 def __init__( self, materialData = None ):
10878 Material.__init__( self, materialData )
10879 self.id = "slides"
10881 def setId( self, newId ):
10882 return
10886 class Video(Material):
10888 def __init__( self, materialData = None ):
10889 Material.__init__( self, materialData )
10890 self.id = "video"
10892 def setId( self, newId ):
10893 return
10895 class Poster(Material):
10897 def __init__( self, materialData = None ):
10898 Material.__init__( self, materialData )
10899 self.id = "poster"
10901 def setId( self, newId ):
10902 return
10904 class Minutes(Material):
10906 def __init__( self, materialData = None ):
10907 Material.__init__( self, materialData )
10908 self.id = "minutes"
10909 self.title = "Minutes"
10910 self.file = None
10912 def clone ( self, owner):
10913 mat = Minutes()
10914 mat.setTitle(self.getTitle())
10915 mat.setDescription(self.getDescription())
10916 mat.notifyModification()
10918 mat.setId(self.getId())
10919 mat.setOwner(owner)
10920 mat.setType(self.getType())
10922 mat.setProtection(self.getAccessController()._getAccessProtection())
10923 mat.setAccessKey(self.getAccessKey())
10924 lrep = self._getRepository()
10925 flist = lrep.getFiles()
10926 rlist = self.getResourceList()
10927 for r in rlist :
10928 if r.getId()=="minutes":
10929 mat.setText(self.getText())
10930 elif isinstance(r,Link):
10931 newlink = Link()
10932 newlink.setOwner(mat)
10933 newlink.setName(r.getName())
10934 newlink.setDescription(r.getDescription())
10935 newlink.setURL(r.getURL())
10936 mat.addResource(newlink)
10937 elif isinstance(r,LocalFile):
10938 newfile = LocalFile()
10939 newfile.setOwner(mat)
10940 newfile.setName(r.getName())
10941 newfile.setDescription(r.getDescription())
10942 newfile.setFilePath(r.getFilePath())
10943 newfile.setFileName(r.getFileName())
10944 mat.addResource(newfile)
10945 else :
10946 raise Exception( _("Unexpected object type in Resource List : ")+str(type(r)))
10948 mat.setMainResource(self.getMainResource())
10950 return mat
10952 def setId( self, newId ):
10953 return
10955 def setTitle( self, newTitle ):
10956 self.title = newTitle.strip()
10957 self.notifyModification()
10959 def _setFile( self, forcedFileId = None ):
10960 #XXX: unsafe; it must be changed by mkstemp when migrating to python 2.3
10961 tmpFileName = tempfile.mktemp()
10962 fh = open(tmpFileName, "w")
10963 fh.write(" ")
10964 fh.close()
10965 self.file = LocalFile()
10966 self.file.setId("minutes")
10967 self.file.setName("minutes")
10968 self.file.setFilePath(tmpFileName)
10969 self.file.setFileName("minutes.txt")
10970 self.file.setOwner(self)
10971 self.file.archive(self._getRepository(), forcedFileId = forcedFileId)
10973 def setText( self, text, forcedFileId = None ):
10974 if self.file:
10975 self.file.delete()
10976 self._setFile(forcedFileId = forcedFileId)
10977 self.file.replaceContent( text )
10978 self.getOwner().notifyModification()
10980 def getText( self ):
10981 if not self.file:
10982 return ""
10983 return self.file.readBin()
10985 def getResourceList( self ):
10986 res = Material.getResourceList( self )
10987 if self.file:
10988 res.insert(0, self.file)
10989 return res
10991 def getResourceById( self, id ):
10992 if id.strip() == "minutes":
10993 return self.file
10994 return Material.getResourceById( self, id )
10996 def removeResource(self, res):
10997 Material.removeResource(self, res)
10998 if self.file is not None and res.getId().strip() == "minutes":
10999 self.file = None
11000 res.delete()
11001 self.notifyModification()
11003 def recoverResource(self, recRes):
11004 if recRes.getId() == "minutes":
11005 recRes.setOwner(self)
11006 self.file = recRes
11007 recRes.recover()
11008 self.notifyModification()
11009 else:
11010 Material.recoverResource(self, recRes)
11013 class Resource(CommonObjectBase):
11014 """This is the base class for representing individual resources which can
11015 be included in material containers for lately being attached to
11016 conference objects (i.e. conferences, sessions or contributions). This
11017 class provides basic data and operations to handle this resources.
11018 Resources can be of serveral types (files, links, ...) which means
11019 different specialisations of this class.
11020 Attributes:
11021 id -- (string) Allows to assign the resource a unique identifier. It
11022 is normally used to uniquely identify the resource among other
11023 resources included in a certain material.
11024 name -- (string) Short description about the purpose or the contents
11025 of the resource.
11026 description - (string) detailed and varied information about the
11027 resource.
11028 __owner - (Material) reference to the material object in which the
11029 current resource is included.
11032 fossilizes(IResourceMinimalFossil, IResourceFossil)
11034 def __init__( self, resData = None ):
11035 self.id = "not assigned"
11036 self.name = ""
11037 self.description = ""
11038 self._owner = None
11039 self.__ac = AccessController(self)
11041 def clone( self, conf, protection=True ):
11042 res = self.__class__()
11043 res.setName(self.getName())
11044 res.setDescription(self.getDescription())
11045 res.setOwner(conf)
11046 res.notifyModification()
11047 res.setId(self.getId())
11049 if protection:
11050 res.setProtection(self.getAccessController()._getAccessProtection())
11051 #res.__ac = self.getAccessController()
11053 return res
11055 def notifyModification( self ):
11056 parent = self.getOwner()
11057 if parent:
11058 parent.setModificationDate()
11059 self._p_changed = 1
11061 def getLocator( self ):
11062 if self._owner == None:
11063 return Locator()
11064 lconf = self._owner.getLocator()
11065 lconf["resId"] = self.getId()
11066 return lconf
11068 def setId( self, newId ):
11069 self.id = newId.strip()
11071 def getId( self ):
11072 return self.id
11074 def getUniqueId( self ):
11075 """returns (string) the unique identifier of the item
11076 used mainly in the web session access key table
11077 for resources, it is the same as the father material since
11078 only the material can be protected with an access key"""
11079 return self.getOwner().getUniqueId()
11081 def setOwner( self, newOwner ):
11082 self._owner = newOwner
11084 def getOwner( self ):
11085 return self._owner
11087 def getCategory( self ):
11088 #raise "%s:%s:%s"%(self.getOwner(), Material, isinstance(self.getOwner, Material))
11090 if isinstance(self.getOwner(), Category):
11091 return self.getOwner()
11092 if isinstance(self.getOwner(), Material):
11093 return self.getOwner().getCategory()
11094 return None
11096 def getConference( self ):
11097 # this check owes itself to the fact that some
11098 # protection checking functions call getConference()
11099 # directly on resources, without caring whether they
11100 # are owned by Conferences or Categories
11101 if isinstance(self._owner, Category):
11102 return None
11103 else:
11104 return self._owner.getConference()
11106 def getSession( self ):
11107 return self._owner.getSession()
11109 def getContribution( self ):
11110 return self._owner.getContribution()
11112 def getSubContribution( self ):
11113 return self._owner.getSubContribution()
11115 @Updates (['MaKaC.conference.Link',
11116 'MaKaC.conference.LocalFile'], 'name')
11117 def setName( self, newName ):
11118 self.name = newName.strip()
11119 self.notifyModification()
11121 def getName( self ):
11122 return self.name
11124 @Updates (['MaKaC.conference.Link',
11125 'MaKaC.conference.LocalFile'], 'description')
11126 def setDescription( self, newDesc ):
11127 self.description = newDesc.strip()
11128 self.notifyModification()
11130 def getDescription( self ):
11131 return self.description
11133 def archive( self, repository = None, forcedFileId = None ):
11134 """performs necessary operations to ensure the archiving of the
11135 resource. By default is doing nothing as the persistence of the
11136 system already ensures the archiving of the basic resource data"""
11137 return
11139 def delete( self ):
11140 if self._owner != None:
11141 self._owner.removeResource( self )
11142 self._owner = None
11143 TrashCanManager().add(self)
11145 def recover(self):
11146 TrashCanManager().remove(self)
11148 def canIPAccess( self, ip ):
11149 if not self.__ac.canIPAccess( ip ):
11150 return False
11151 if self.getOwner() != None:
11152 return self.getOwner().canIPAccess(ip)
11153 return True
11155 def isProtected( self ):
11156 # tells if a resource is protected or not
11157 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
11159 def getAccessProtectionLevel( self ):
11160 return self.__ac.getAccessProtectionLevel()
11162 def isItselfProtected( self ):
11163 return self.__ac.isItselfProtected()
11165 def hasProtectedOwner( self ):
11166 if self.getOwner() != None:
11167 return self.getOwner().isProtected()
11168 return False
11170 @Updates (['MaKaC.conference.Link',
11171 'MaKaC.conference.LocalFile'],'protection', lambda(x): int(x))
11172 def setProtection( self, private ):
11173 self.__ac.setProtection( private )
11174 self.getOwner().updateFullyPublic()
11176 def grantAccess( self, prin ):
11177 self.__ac.grantAccess( prin )
11178 if isinstance(prin, MaKaC.user.Avatar):
11179 prin.linkTo(self, "access")
11181 def revokeAccess( self, prin ):
11182 self.__ac.revokeAccess( prin )
11183 if isinstance(prin, MaKaC.user.Avatar):
11184 prin.unlinkTo(self, "access")
11186 def canView( self, aw ):
11187 """tells whether the specified user has access to the current object
11188 or any of its sub-objects
11190 return self.canAccess( aw )
11192 def isAllowedToAccess( self, user ):
11193 return self.__ac.canUserAccess( user ) or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user ))
11195 def canAccess( self, aw ):
11196 # Allow harvesters (Invenio, offline cache) to access
11197 # protected pages
11198 if self.__ac.isHarvesterIP(aw.getIP()):
11199 return True
11200 #####################################################
11202 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
11203 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
11204 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
11205 return True
11207 if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ):
11208 return False
11209 if not self.isProtected():
11210 return True
11211 flag = self.isAllowedToAccess( aw.getUser() )
11212 return flag or self.canKeyAccess(aw) or self.getOwner().canKeyAccess(aw) or \
11213 (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == "") or \
11214 (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == self.getConference().getAccessKey())
11216 def grantModification( self, prin ):
11217 self.__ac.grantModification( prin )
11219 def revokeModification( self, prin ):
11220 self.__ac.revokeModification( prin )
11222 def canModify( self, aw ):
11223 return self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw ))
11225 def canUserModify( self, user ):
11226 """Tells whether a user is allowed to modify the current contribution:
11227 only if the user is granted to modify the contribution or the user
11228 can modify any of its upper objects (i.e. conference or session).
11230 return self.getOwner().canUserModify( user )
11232 def getModifKey( self ):
11233 return self.getConference().getModifKey()
11235 def getManagerList( self ):
11236 return self.__ac.getModifierList()
11238 def getAllowedToAccessList( self ):
11239 return self.__ac.getAccessList()
11241 def getURL( self ):
11242 return ""
11244 def requireDomain( self, dom ):
11245 self.__ac.requireDomain( dom )
11247 def freeDomain( self, dom ):
11248 self.__ac.freeDomain( dom )
11250 def getDomainList( self ):
11251 return self.__ac.getRequiredDomainList()
11253 def getAccessController(self):
11254 return self.__ac
11256 def getAccessKey(self):
11257 if self.getOwner() is not None:
11258 return self.getOwner().getAccessKey()
11259 return ""
11261 def canKeyAccess( self, aw ):
11262 sess = aw.getSession()
11263 if not sess:
11264 return False
11265 accessKey = self.getAccessKey()
11266 keys = sess.getVar("accessKeys")
11267 if keys != None:
11268 if keys.has_key(self.getUniqueId()):
11269 if (accessKey != "" and keys[self.getUniqueId()] == accessKey) or (accessKey == "" and self.getConference().getAccessKey() != "" and keys[self.getUniqueId()] == self.getConference().getAccessKey()):
11270 return True
11271 return False
11274 def getReviewingState(self):
11275 """ Returns the reviewing state of a resource, which is the reviewing state of the material to which it belongs.
11276 The state is represented by an integer:
11277 0 : there's no reviewing state because the resource doesn't belong to a material,
11278 the material does not belong to a contribution, or the conference does not have reviewing.
11279 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
11280 2 : the material is subject to reviewing, but has not been submitted yet by the author
11281 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
11282 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
11283 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
11285 if isinstance(self.getOwner(), Material):
11286 return self.getOwner().getReviewingState()
11287 else: #ressource does not belong to a material
11288 return 0
11291 class Link(Resource):
11292 """Specialises Resource class in order to represent web links. Objects of
11293 this class will contain necessary information to include in a conference
11294 object links to internet resources through a URL.
11295 Params:
11296 url -- (string) Contains the URL to the internet target resource.
11299 fossilizes(ILinkMinimalFossil, ILinkFossil)
11301 def __init__( self, resData = None ):
11302 Resource.__init__( self, resData )
11303 self.url = ""
11305 def clone( self, conf ):
11306 link = Resource.clone(self, conf)
11307 link.setURL(self.getURL())
11308 return link
11310 @Updates ('MaKaC.conference.Link', 'url')
11311 def setURL( self, newURL ):
11312 self.url = newURL.strip()
11313 self.notifyModification()
11315 def getURL( self ):
11316 return self.url
11319 class LocalFile(Resource):
11320 """Specialises Resource class in order to represent files which can be
11321 stored in the system. The user can choose to use the system as an
11322 archive of electronic files so he may want to attach a file which is
11323 in his computer to a conference so it remains there and must be kept
11324 in the system. This object contains the file basic metadata and provides
11325 the necessary operations to ensure the corresponding file is archived
11326 (it uses one of the file repositories of the system to do so) and keeps
11327 the reference for being able to access it afterwards.
11328 Params:
11329 fileName -- (string) Name of the file. Normally the original name of
11330 the user submitted file is kept.
11331 filePath -- (string) If it is set, it contains a local path to the
11332 file submitted by the user and uploaded in the system. This
11333 attribute is only temporary used so it keeps a pointer to a
11334 temporary uploaded file.
11335 __repository -- (FileRep) Once a file is archived, it is kept in a
11336 FileRepository for long term. This attribute contains a pointer
11337 to the file repository where the file is kept.
11338 __archivedId -- (string) It contains a unique identifier for the file
11339 inside the repository where it is archived.
11342 fossilizes(ILocalFileMinimalFossil, ILocalFileFossil, ILocalFileExtendedFossil, ILocalFileAbstractMaterialFossil)
11344 def __init__( self, resData = None ):
11345 Resource.__init__( self, resData )
11346 self.fileName= ""
11347 self.fileType = ""
11348 self.filePath = ""
11349 self.__repository = None
11350 self.__archivedId = ""
11352 def clone( self, conf, protection=True ):
11353 localfile = Resource.clone(self, conf, protection)
11354 localfile.setFilePath(self.getFilePath())
11355 localfile.setFileName(self.getFileName())
11356 return localfile
11358 def setFileName( self, newFileName, checkArchive=True ):
11359 """While the file is not archived sets the file name of the current
11360 object to the one specified (if a full path is specified the
11361 base name is extracted) replacing on it blanks by underscores.
11363 if checkArchive and self.isArchived():
11364 raise MaKaCError( _("The file name of an archived file cannot be changed"), _("File Archiving"))
11365 #Using os.path.basename is not enough as it only extract filenames
11366 # correclty depending on the server platform. So we need to convert
11367 # to the server platform and apply the basename extraction. As I
11368 # couldn't find a python function for this this is done manually
11369 # although it can contain errors
11370 #On windows basename function seems to work properly with unix file
11371 # paths
11372 if newFileName.count("/"):
11373 #unix filepath
11374 newFileName = newFileName.split("/")[-1]
11375 else:
11376 #windows file path: there "/" is not allowed on windows paths
11377 newFileName = newFileName.split("\\")[-1]
11378 self.fileName = newFileName.strip().replace(" ", "_")
11380 def getFileName( self ):
11381 return self.fileName
11383 def getFileType( self ):
11384 fileExtension = os.path.splitext( self.getFileName() )[1]
11385 if fileExtension != "":
11386 fileExtension = fileExtension[1:]
11387 cfg = Config.getInstance()
11388 if cfg.getFileType( fileExtension ) != "":
11389 return cfg.getFileType( fileExtension )
11390 else:
11391 return fileExtension
11393 def setFilePath( self, filePath ):
11394 if self.isArchived():
11395 raise MaKaCError( _("The path of an archived file cannot be changed"), _("File Archiving"))
11396 if not os.access( filePath.strip(), os.F_OK ):
11397 raise Exception( _("File does not exist : %s")%filePath.strip())
11398 self.filePath = filePath.strip()
11400 def getCreationDate( self):
11401 return self.__repository.getCreationDate(self.__archivedId)
11403 def getFilePath( self ):
11404 if not self.isArchived():
11405 return self.filePath
11406 return self.__repository.getFilePath(self.__archivedId)
11408 def getSize( self ):
11409 if not self.isArchived():
11410 return int(os.stat(self.getFilePath())[stat.ST_SIZE])
11411 return self.__repository.getFileSize( self.__archivedId )
11413 def setArchivedId( self, rep, id ):
11414 self.__repository = rep
11415 self.__archivedId = id
11417 def getRepositoryId( self ):
11418 return self.__archivedId
11420 def setRepositoryId(self, id):
11421 self.__archivedId = id
11423 def isArchived( self ):
11424 return self.__repository != None and self.__archivedId != ""
11426 def readBin( self ):
11427 if not self.isArchived():
11428 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11429 return self.__repository.readFile( self.__archivedId )
11431 def replaceContent( self, newContent ):
11432 if not self.isArchived():
11433 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11434 self.__repository.replaceContent( self.__archivedId, newContent )
11436 def archive( self, repository=None, forcedFileId = None ):
11437 if self.isArchived():
11438 raise Exception( _("File is already archived"))
11439 if not repository:
11440 raise Exception( _("Destination repository not set"))
11441 if self.filePath == "":
11442 return _("Nothing to archive")
11443 repository.storeFile( self, forcedFileId = forcedFileId)
11444 self.filePath = ""
11445 self.notifyModification()
11447 def unArchive(self):
11448 # Not used.
11449 self.__repository = None
11450 self.__archivedId = ""
11452 def recover(self):
11453 if not self.isArchived():
11454 raise Exception( _("File is not archived, so it cannot be recovered."))
11455 if not self.__repository:
11456 raise Exception( _("Destination repository not set."))
11457 self.__repository.recoverFile(self)
11458 Resource.recover(self)
11459 self.notifyModification()
11461 def delete( self ):
11462 if not self.isArchived():
11463 os.remove( self.getFilePath() )
11464 try:
11465 self.__repository.retireFile( self )
11466 except AttributeError, e:
11467 pass
11468 Resource.delete( self )
11470 def getRepository(self):
11471 return self.__repository
11473 #getURL is removed at the moment from the LocalFile and the file access
11474 # is completely delegated to the web interface; the web interface will
11475 # have to access the files locally (using the getFilePath) or the readBin
11476 # function.
11477 #However, for the future it could be required to have several file
11478 # repositories so the file access will have to be reviewed.
11479 #def getURL( self ):
11480 # #XXX: Very bad!! We should find a better solution
11481 # c = Config.getInstance()
11482 # return c.getArchivedFileURL( self )
11485 class TCIndex( Persistent ):
11486 """Index for conference track coordinators.
11488 This class allows to index conference track coordinators so the owner
11489 can answer optimally to the query if a user is coordinating
11490 any conference track.
11491 It is implemented by simply using a BTree where the Avatar id is used
11492 as key (because it is unique and non variable) and a list of
11493 coordinated tracks is kept as keys. It is the responsability of the
11494 index owner (conference) to keep it up-to-date i.e. notify track
11495 coordinator additions and removals.
11498 def __init__( self ):
11499 self._idx = OOBTree()
11502 def getTracks( self, av ):
11503 """Gives a list with the tracks a user is coordinating.
11505 if av == None:
11506 return []
11507 return self._idx.get( av.getId(), [] )
11509 def indexCoordinator( self, av, track ):
11510 """Registers in the index a coordinator of a track.
11512 if av == None or track == None:
11513 return
11514 if not self._idx.has_key( av.getId() ):
11515 l = []
11516 else:
11517 l = self._idx[av.getId()]
11518 if track not in l:
11519 l.append(track)
11520 # necessary, otherwise ZODB won't know it needs to update the BTree
11521 self._idx[av.getId()] = l
11522 self.notifyModification()
11524 def unindexCoordinator( self, av, track ):
11525 if av == None or track == None:
11526 return
11527 l = self._idx.get( av.getId(), [] )
11528 if track in l:
11529 l.remove( track )
11530 self._idx[av.getId()] = l
11531 self.notifyModification()
11533 def notifyModification(self):
11534 self._p_changed = 1
11537 class Track(CoreObject):
11539 def __init__( self ):
11540 self.conference = None
11541 self.id = "not assigned"
11542 self.title = ""
11543 self.description = ""
11544 self.subTracks = {}
11545 self.__SubTrackGenerator = Counter()
11546 self._abstracts = OOBTree()
11547 self._coordinators = []
11548 self._contributions = OOBTree()
11549 self._code=""
11551 def clone(self, conference):
11552 tr = Track()
11553 tr.setConference(conference)
11554 tr.setTitle(self.getTitle())
11555 tr.setCode(self.getCode())
11556 tr.setDescription(self.getDescription())
11558 for co in self.getCoordinatorList() :
11559 tr.addCoordinator(co)
11561 for subtr in self.getSubTrackList() :
11562 tr.addSubTrack(subtr.clone())
11564 return tr
11567 def delete( self ):
11568 """Deletes a track from the system. All the associated abstracts will
11569 also be notified so the track is no longer associated to them.
11571 #XXX: Should we allow to delete a track when there are some abstracts
11572 # or contributions submitted for it?!?!?!?!
11574 # we must notify each abstract in the track about the deletion of the
11575 # track
11576 while len(self._abstracts)>0:
11577 k = self._abstracts.keys()[0]
11578 abstract = self._abstracts[k]
11579 del self._abstracts[k]
11580 abstract.removeTrack( self )
11582 # we must notify each contribution in the track about the deletion of the
11583 # track
11584 while len(self._contributions)>0:
11585 k = self._contributions.keys()[0]
11586 contrib = self._contributions[k]
11587 del self._contributions[k]
11588 contrib.removeTrack( self )
11590 # we must delete and unindex all the possible track coordinators
11591 while len(self._coordinators)>0:
11592 self.removeCoordinator(self._coordinators[0])
11594 # we must notify the conference about the track deletion
11595 if self.conference:
11596 conf = self.conference
11597 self.conference = None
11598 conf.removeTrack( self )
11600 TrashCanManager().add(self)
11602 def recover(self):
11603 TrashCanManager().remove(self)
11605 def canModify( self, aw ):
11606 return self.conference.canModify( aw )
11608 def canUserModify( self, av ):
11609 return self.conference.canUserModify( av )
11611 def canView( self, aw ):
11612 return self.conference.canView( aw )
11614 def notifyModification( self ):
11615 parent = self.getConference()
11616 if parent:
11617 parent.setModificationDate()
11618 self._p_changed = 1
11620 def getLocator( self ):
11621 """Gives back a globaly unique identification encapsulated in a Locator
11622 object for the track instance
11624 if self.conference == None:
11625 return Locator()
11626 lconf = self.conference.getLocator()
11627 lconf["trackId"] = self.getId()
11628 return lconf
11630 def setConference(self, conference):
11631 self.conference = conference
11633 def getConference( self ):
11634 return self.conference
11636 def getOwner( self ):
11637 return self.getConference()
11639 def setId( self, newId ):
11640 self.id = str(newId)
11642 def getId( self ):
11643 return self.id
11645 def setTitle( self, newTitle ):
11646 self.title = newTitle
11647 self.notifyModification()
11649 def getTitle( self ):
11650 return self.title
11652 def setDescription(self, newDescription ):
11653 self.description = newDescription
11654 self.notifyModification()
11656 def getDescription(self):
11657 return self.description
11659 def getCode(self):
11660 try:
11661 if self._code:
11662 pass
11663 except AttributeError:
11664 self._code=self.id
11665 return self._code
11667 def setCode(self,newCode):
11668 self._code=str(newCode).strip()
11670 def __generateNewSubTrackId( self ):
11671 return str(self.__SubTrackGenerator.newCount())
11673 def addSubTrack( self, newSubTrack ):
11674 """Registers the contribution passed as parameter within the session
11675 assigning it a unique id.
11677 if newSubTrack in self.subTracks.values():
11678 return
11679 subTrackId = newSubTrack.getId()
11680 if subTrackId == "not assigned":
11681 subTrackId = self.__generateNewSubTrackId()
11682 self.subTracks[subTrackId] = newSubTrack
11683 newSubTrack.setTrack( self )
11684 newSubTrack.setId( subTrackId )
11685 self.notifyModification()
11687 def removeSubTrack( self, subTrack ):
11688 """Removes the indicated contribution from the session
11690 if subTrack in self.subTracks.values():
11691 del self.subTracks[ subTrack.getId() ]
11692 subTrack.setTrack( None )
11693 subTrack.delete()
11694 self.notifyModification()
11696 def recoverSubTrack(self, subTrack):
11697 self.addSubTrack(subTrack)
11698 subTrack.recover()
11700 def newSubTrack( self ):
11701 st = SubTrack()
11702 self.addSubTrack( st )
11703 return st
11705 def getSubTrackById( self, id ):
11706 if self.subTracks.has_key( id ):
11707 return self.subTracks[ id ]
11708 return None
11710 def getSubTrackList( self ):
11711 return self.subTracks.values()
11713 def getAbstractList( self ):
11716 try:
11717 if self._abstracts:
11718 pass
11719 except AttributeError:
11720 self._abstracts = OOBTree()
11721 return self._abstracts.values()
11723 def getAbstractById( self, id ):
11724 try:
11725 if self._abstracts:
11726 pass
11727 except AttributeError:
11728 self._abstracts = OOBTree()
11729 return self._abstracts[ str(id).strip() ]
11731 def hasAbstract( self, abstract ):
11734 try:
11735 if self._abstracts:
11736 pass
11737 except AttributeError:
11738 self._abstracts = OOBTree()
11739 return self._abstracts.has_key( abstract.getId() )
11741 def addAbstract( self, abstract ):
11742 """Adds an abstract to the track abstract list.
11744 Notice that this method doesn't notify the abstract about the track
11745 addition.
11747 if not self.hasAbstract( abstract ):
11748 self._abstracts[ abstract.getId() ] = abstract
11749 #abstract.addTrack( self )
11751 def removeAbstract( self, abstract ):
11752 """Removes an abstract from the track abstract list.
11754 Notice that this method doesn't notify the abstract about the track
11755 removal.
11757 if self.hasAbstract( abstract ):
11758 del self._abstracts[ abstract.getId() ]
11759 #abstract.removeTrack( self )
11761 def addCoordinator( self, av ):
11762 """Grants coordination privileges to user.
11764 Arguments:
11765 av -- (MaKaC.user.Avatar) the user to which
11766 coordination privileges must be granted.
11769 try:
11770 if self._coordinators:
11771 pass
11772 except AttributeError, e:
11773 self._coordinators = []
11774 self.notifyModification()
11776 if not (av in self._coordinators):
11777 self._coordinators.append( av )
11778 self.getConference().addTrackCoordinator( self, av )
11779 av.linkTo(self, "coordinator")
11780 self.notifyModification()
11782 def removeCoordinator( self, av ):
11783 """Revokes coordination privileges to user.
11785 Arguments:
11786 av -- (MaKaC.user.Avatar) user for which coordination privileges
11787 must be revoked
11789 try:
11790 if self._coordinators:
11791 pass
11792 except AttributeError, e:
11793 self._coordinators = []
11794 self.notifyModification()
11796 if av in self._coordinators:
11797 self._coordinators.remove( av )
11798 self.getConference().removeTrackCoordinator( self, av )
11799 av.linkTo(self, "coordinator")
11800 self.notifyModification()
11802 def isCoordinator( self, av ):
11803 """Tells whether the specified user is a coordinator of the track.
11805 Arguments:
11806 av -- (MaKaC.user.Avatar) user to be checke
11808 Return value: (boolean)
11810 try:
11811 if self._coordinators:
11812 pass
11813 except AttributeError, e:
11814 self._coordinators = []
11816 return av in self._coordinators
11818 def getCoordinatorList( self ):
11819 """Return all users which have privileges to coordinate the track.
11821 Return value: (list)
11823 try:
11824 if self._coordinators:
11825 pass
11826 except AttributeError, e:
11827 self._coordinators = []
11829 return self._coordinators
11831 def canCoordinate( self, aw ):
11832 """Tells if a user has coordination privileges.
11834 Only track coordinators have coordination privileges over a track.
11836 Params:
11837 aw -- (MaKaC.accessControl.AccessWrapper) User access
11838 information for which the coordination privileges must be
11839 checked.
11841 Return value: (boolean)
11843 return self.isCoordinator( aw.getUser() ) or self.canModify( aw )
11845 def addContribution( self, newContrib ):
11848 try:
11849 if self._contributions:
11850 pass
11851 except AttributeError:
11852 self._contributions = OOBTree()
11853 if self._contributions.has_key( newContrib.getId() ):
11854 return
11855 self._contributions[ newContrib.getId() ] = newContrib
11856 newContrib.setTrack( self )
11858 def getModifKey( self ):
11859 return self.getConference().getModifKey()
11861 def removeContribution( self, contrib ):
11864 try:
11865 if self._contributions:
11866 pass
11867 except AttributeError:
11868 self._contributions = OOBTree()
11869 if not self._contributions.has_key( contrib.getId() ):
11870 return
11871 del self._contributions[ contrib.getId() ]
11872 contrib.setTrack( None )
11874 def hasContribution( self, contrib ):
11875 try:
11876 if self._contributions:
11877 pass
11878 except AttributeError:
11879 self._contributions = OOBTree()
11880 return self._contributions.has_key( contrib.getId() )
11882 def getContributionList(self):
11883 try:
11884 if self._contributions:
11885 pass
11886 except AttributeError:
11887 self._contributions = OOBTree()
11888 return self._contributions.values()
11890 def canUserCoordinate( self, av ):
11891 return self.isCoordinator( av ) or self.canUserModify( av )
11894 class SubTrack(CoreObject):
11896 def __init__( self ):
11897 self.track = None
11898 self.id = "not assigned"
11899 self.title = ""
11900 self.description = ""
11902 def clone(self):
11903 sub = SubTrack()
11904 sub.setDescription(self.getDescription())
11905 sub.setTitle(self.getTitle())
11907 return sub
11910 def delete(self):
11911 TrashCanManager().add(self)
11913 def recover(self):
11914 TrashCanManager().remove(self)
11916 def canModify( self, aw ):
11917 return self.track.canModify( aw )
11919 def canView( self, aw ):
11920 return self.track.canView( aw )
11922 def notifyModification( self ):
11923 parent = self.getTrack()
11924 if parent:
11925 parent.setModificationDate()
11926 self._p_changed = 1
11928 def getLocator( self ):
11929 """Gives back a globaly unique identification encapsulated in a Locator
11930 object for the session instance
11932 if self.track == None:
11933 return Locator()
11934 lconf = self.track.getLocator()
11935 lconf["subTrackId"] = self.getId()
11936 return lconf
11938 def setTrack(self, track):
11939 self.track = track
11940 if track == None:
11941 return
11943 def getTrack( self ):
11944 return self.track
11946 def getOwner( self ):
11947 return self.getTrack()
11949 def setId( self, newId ):
11950 self.id = str(newId)
11952 def getId( self ):
11953 return self.id
11955 def setTitle( self, newTitle ):
11956 self.title = newTitle
11957 self.notifyModification()
11959 def getTitle( self ):
11960 return self.title
11962 def setDescription(self, newDescription ):
11963 self.description = newDescription
11964 self.notifyModification()
11966 def getDescription(self):
11967 return self.description
11970 class ContributionType(Persistent):
11972 def __init__(self, name, description, conference):
11973 self._id = ""
11974 self._name = name
11975 self._description = description
11976 self._conference = conference
11978 def getId(self):
11979 return self._id
11981 def setId(self, id):
11982 self._id = id
11984 def getName(self):
11985 return self._name
11987 def setName(self, name):
11988 self._name = name
11990 def getDescription(self):
11991 return self._description
11993 def setDescription(self, desc):
11994 self._description = desc
11996 def getConference(self):
11997 return self._conference
11999 def setConference(self, conf):
12000 self._conference = conf
12002 def getLocator( self ):
12003 if self._conference == None:
12004 return Locator()
12005 lconf = self._conference.getLocator()
12006 lconf["contribTypeId"] = self.getId()
12007 return lconf
12009 def canModify(self, aw):
12010 return self._conference.canModify(aw)
12012 def delete(self):
12013 self.setConference(None)
12014 TrashCanManager().add(self)
12016 def recover(self):
12017 TrashCanManager().remove(self)
12019 def clone(self, conference ):
12020 type = ContributionType(self.getName(), self.getDescription(),conference)
12021 return type
12024 class BOAConfig(Persistent):
12025 """Contains the configuration of the Book of Abstracts of a conference
12027 sortByTypes = {"number": L_("ID"),
12028 "name": L_("Title"),
12029 "sessionTitle": L_("Session title"),
12030 "speaker": L_("Presenter"),
12031 "schedule": L_("Schedule")}
12033 def __init__(self,conf):
12034 self._conf=conf
12035 self._text=""
12036 self._showIds= False
12037 self._sortBy = "number"
12039 def getText(self):
12040 return self._text
12042 def setText(self,newText):
12043 self._text=newText.strip()
12045 def getShowIds(self):
12046 if not hasattr(self, "_showIds"):
12047 self._showIds=False
12048 return self._showIds
12050 def setShowIds(self,showIds):
12051 self._showIds=showIds
12053 def getSortBy(self):
12054 if not hasattr(self, "_sortBy"):
12055 self._sortBy="number"
12056 return self._sortBy
12058 def setSortBy(self,sortBy):
12059 self._sortBy=sortBy
12061 @staticmethod
12062 def getSortByTypes():
12063 return BOAConfig.sortByTypes