1 # -*- coding: utf-8 -*-
4 ## This file is part of CDS Indico.
5 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
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.
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_
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
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
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.
119 self
._modificationDS
= date
121 def __conform__(self
, proto
):
123 if proto
== IIndexableByStartDateTime
:
124 return utc_timestamp(self
.getStartDate())
131 Inherited by objects that imply a physical location:
139 def getLocationParent(self
):
141 Returns the object the location info should be inherited from
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]
156 def getInheritedLocation(self
):
157 return self
.getLocationParent().getLocation()
159 def getOwnRoom(self
):
160 if len(self
.rooms
) > 0:
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:
177 elif len(self
.places
) > 0:
178 self
.places
[0] = newLocation
180 self
.places
.append( newLocation
)
181 self
.notifyModification()
183 def setRoom(self
, newRoom
):
184 oldRoom
= self
.getOwnRoom()
186 if len(self
.rooms
) > 0:
188 elif len(self
.rooms
) > 0:
189 self
.rooms
[0] = newRoom
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:
208 def getRecursiveManagerList(self
):
211 # Get the AccessProtectionLevel for this
212 apl
= self
.getAccessProtectionLevel()
217 for av
in self
.getManagerList():
219 for av
in self
.getOwner().getRecursiveManagerList():
222 for av
in self
.getManagerList():
226 for av
in self
.getOwner().getRecursiveManagerList():
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
241 # Get the AccessProtectionLevel for this
242 apl
= self
.getAccessProtectionLevel()
244 # If this object is "absolutely public", then return an empty set
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)
251 al
= self
.getAllowedToAccessList() + self
.getManagerList() + \
252 self
.getOwner().getRecursiveManagerList()
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()
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:
274 # return set containing whatever avatars/groups we may have collected
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())
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
)
306 root
= DBMgr
.getInstance().getDBConnection().root()
307 if not root
.has_key("rootCategory"):
309 r
.setName( _("Home"))
311 root
["rootCategory"] = r
312 return root
["rootCategory"]
314 def getDefaultConference( self
):
315 dconf
= HelperMaKaCInfo
.getMaKaCInfoInstance().getDefaultConference()
317 return HelperMaKaCInfo
.getMaKaCInfoInstance().setDefaultConference(DefaultConference())
323 class Category(CommonObjectBase
):
325 fossilizes(ICategoryFossil
)
327 def __init__( self
):
331 self
.description
= ""
332 self
.subcategories
= {}
334 self
.conferences
= OOTreeSet()
335 self
._numConferences
= 0
337 self
._defaultStyle
= { "simple_event":"","meeting":"" }
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,\
347 #self._materials = {}
349 self
._tasksAllowed
= False
351 self
._taskIdGenerator
= 0
352 self
._tasksPublic
= True
353 self
._tasksCommentPublic
= True
354 self
._tasksManagers
= []
355 self
._tasksCommentators
= []
356 self
._taskAccessList
= []
358 self
.__materialGenerator
= Counter()
359 self
._notifyCreationList
= ""
362 return "<Category %s@%s>" % (self
.getId(), hex(id(self
)))
364 def getAccessController(self
):
367 def updateFullyPublic( self
):
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"""
374 return self
._notifyCreationList
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"))
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})
401 def clearCache( self
):
402 """ delete cache file of this category. usually used for
404 cache
= CategoryCache({"categId":self
.getId()})
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():
413 def removePaper( self
):
414 if self
.paper
is None:
417 self
.paper
.setOwner(None)
419 self
.notifyModification()
421 def recoverPaper(self
, p
):
425 def getPaper( self
):
429 except AttributeError:
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:
444 self
.slides
.setOwner( None )
446 self
.notifyModification()
448 def recoverSlides(self
, s
):
452 def getSlides( self
):
456 except AttributeError:
460 def setVideo( self
, newVideo
):
461 if self
.getVideo() != None:
462 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
464 self
.video
.setOwner( self
)
465 self
.notifyModification()
467 def removeVideo( self
):
468 if self
.getVideo() is None:
471 self
.video
.setOwner(None)
473 self
.notifyModification()
475 def recoverVideo(self
, v
):
479 def getVideo( self
):
483 except AttributeError:
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:
498 self
.poster
.setOwner(None)
500 self
.notifyModification()
502 def recoverPoster(self
, p
):
506 def getPoster( self
):
510 except AttributeError:
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()
529 def removeMinutes( self
):
530 if self
.getMinutes() is None:
532 self
.minutes
.delete()
533 self
.minutes
.setOwner( None )
535 self
.notifyModification()
537 def recoverMinutes(self
, min):
538 self
.removeMinutes() # To ensure that the current minutes are put in
541 self
.minutes
.setOwner( self
)
543 self
.notifyModification()
546 def getMinutes( self
):
551 except AttributeError, e
:
555 def addMaterial( self
, newMat
):
557 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
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() ]
570 self
.notifyModification()
571 return "done: %s"%mat
.getId()
572 elif mat
.getId().lower() == 'minutes':
574 return "done: %s"%mat
.getId()
575 elif mat
.getId().lower() == 'paper':
577 return "done: %s"%mat
.getId()
578 elif mat
.getId().lower() == 'slides':
580 return "done: %s"%mat
.getId()
581 elif mat
.getId().lower() == 'video':
583 return "done: %s"%mat
.getId()
584 elif mat
.getId().lower() == 'poster':
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
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
]
618 def getMaterialList( self
):
620 return self
.materials
.values()
623 return self
.materials
.values()
625 def getAllMaterialList( self
):
626 l
= self
.getMaterialList()
628 l
.append( self
.getPaper() )
630 l
.append( self
.getSlides() )
632 l
.append( self
.getVideo() )
634 l
.append( self
.getPoster() )
635 if self
.getMinutes():
636 l
.append( self
.getMinutes() )
639 def getTaskList(self
):
641 return self
._tasks
.values()
644 return self
._tasks
.values()
656 def getTask(self
, taskId
):
657 return self
.getTasks().get(taskId
,None)
659 def _getTasksAllowed(self
):
661 return self
._tasksAllowed
663 self
._tasksAllowed
= False
664 return self
._tasksAllowed
666 def tasksAllowed(self
):
667 if self
.hasSubcategories():
669 return self
._getTasksAllowed
()
671 def setTasksAllowed(self
):
672 if self
.hasSubcategories() :
674 self
._getTasksAllowed
()
675 self
._tasksAllowed
= True
676 self
.notifyModification()
679 def setTasksForbidden(self
):
680 if len(self
.getTaskList()) > 0 :
682 self
._getTasksAllowed
()
683 self
._tasksAllowed
= False
684 self
.notifyModification()
687 def _getNewTaskId(self
):
689 if self
._taskIdGenerator
:
692 self
._taskIdGenerator
= 0
693 self
._taskIdGenerator
= self
._taskIdGenerator
+ 1
694 return self
._taskIdGenerator
696 def newTask(self
, user
):
699 newTask
= task
.Task(self
, self
._getNewTaskId
(), user
)
700 self
.getTasks()["%s"%newTask
.getId()] = newTask
701 self
.notifyModification()
704 def tasksPublic(self
):
706 return self
._tasksPublic
708 self
._tasksPublic
= True
709 return self
._tasksPublic
711 def setTasksPublic(self
):
713 self
._tasksPublic
= True
715 def setTasksPrivate(self
):
717 self
._tasksPublic
= False
719 def tasksCommentPublic(self
):
721 return self
._tasksCommentPublic
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
):
736 return self
._tasksManagers
738 self
._tasksManagers
= []
740 return self
._tasksManagers
742 def getTasksManager(self
, index
):
743 length
= len(self
.getTasksManagerList())
744 if index
< 0 or index
>= length
:
746 return self
._tasksManagers
[index
]
748 def addTasksManager(self
,user
):
751 self
.getTasksManagerList().append(user
)
755 def removeTasksManager(self
, index
):
756 length
= len(self
.getTasksManagerList())
757 if index
< 0 or index
>= length
:
759 del self
.getTasksManagerList()[index
]
763 def getTasksCommentatorList(self
):
765 return self
._tasksCommentators
767 self
._tasksCommentators
= []
769 return self
._tasksCommentators
771 def getTasksCommentator(self
, index
):
772 length
= len(self
.getTasksCommentatorList())
773 if index
< 0 or index
>= length
:
775 return self
._tasksCommentators
[index
]
777 def addTasksCommentator(self
,user
):
780 self
.getTasksCommentatorList().append(user
)
784 def removeTasksCommentator(self
, index
):
785 length
= len(self
.getTasksCommentatorList())
786 if index
< 0 or index
>= length
:
788 del self
._tasksCommentators
[index
]
793 def getTasksAccessList(self
):
795 return self
._tasksAccessList
797 self
._tasksAccessList
= []
799 return self
._tasksAccessList
801 def getTasksAccessPerson(self
, index
):
802 length
= len(self
.getTasksAccessList())
803 if index
< 0 or index
>= length
:
805 return self
._tasksAccessList
[index
]
807 def addTasksAccessPerson(self
,user
):
810 self
.getTasksAccessList().append(user
)
814 def removeTasksAccessPerson(self
, index
):
815 length
= len(self
.getTasksAccessList())
816 if index
< 0 or index
>= length
:
818 del self
.getTasksAccessList()[index
]
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)
829 return max(0,min(int(self
._visibility
), self
.getOwner().getVisibility()+1))
831 self
._visibility
= 999
834 def setVisibility( self
, visibility
=999 ):
835 self
._visibility
= int(visibility
)
838 def _reindex( self
):
839 catIdx
= indexes
.IndexesHolder().getIndex('category')
840 catIdx
.reindexCateg(self
)
841 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
842 catDateIdx
.reindexCateg(self
)
846 return self
.owner
== None
848 def getDefaultStyle( self
, type ):
850 return self
._defaultStyle
[type]
854 def setDefaultStyle( self
, type, style
, subcatsStyle
=False ):
856 self
._defaultStyle
[type] = style
858 self
._defaultStyle
= { "simple_event":"","meeting":"" }
859 self
._defaultStyle
[type] = style
860 self
.notifyModification()
861 #raise str(subcatsStyle)
864 categ
=self
.getSubCategoryList()
867 cat
.setDefaultStyle(type, style
, subcatsStyle
)
869 ##################################
870 # Fermi timezone awareness #
871 ##################################
872 def getTimezone(self
):
874 if self
._timezone
not in all_timezones
:
875 self
.setTimezone('UTC')
876 return self
._timezone
878 self
.setTimezone('UTC')
881 def setTimezone(self
,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
):
900 def setOrder( self
, order
):
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 """
913 d
["categId"] = self
.getId()
916 def getCategory(self
):
919 def getOwner( self
):
922 def setOwner( self
, newOwner
):
923 if self
.getOwner() != None and newOwner
!= None and self
.getOwner() != newOwner
:
924 self
.move( newOwner
)
926 self
.owner
= newOwner
928 def getCategoryPath(self
):
930 return [self
.getId()]
932 l
= self
.getOwner().getCategoryPath()
933 l
.append(self
.getId())
936 def getCategoryPathTitles(self
):
941 breadcrumbs
.insert(0, cat
.getTitle())
945 def delete( self
, deleteConferences
=0 ):
946 """removes completely a category (and all its sub-items) from the
949 oldOwner
= self
.getOwner()
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"))
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
)
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
)
978 catDateIdx
.indexCateg(self
)
980 self
._notify
('moved', oldOwner
, newOwner
)
985 def setName( self
, newName
):
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
)
998 def getDescription( self
):
999 return self
.description
1001 def setDescription( self
, newDesc
):
1002 self
.description
= newDesc
.strip()
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())
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
1037 if sc
in self
.getSubCategoryList():
1038 self
._decNumConfs
(sc
.getNumConferences())
1039 del self
.subcategories
[ sc
.getId() ]
1043 def newSubCategory(self
, protection
):
1044 cm
= CategoryManager()
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
)
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
)
1086 def getAccessKey(self
):
1089 def getModifKey(self
):
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
)
1099 def unindexConf( self
, conf
):
1100 catIdx
= indexes
.IndexesHolder().getIndex('category')
1101 catIdx
.unindexConf(conf
)
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
)
1113 def removeConference( self
, conf
, notify
=True, delete
= False ):
1114 if not (conf
in self
.conferences
):
1117 self
.unindexConf( conf
)
1119 self
.conferences
.remove(conf
)
1122 conf
.removeOwner( self
, notify
)
1123 self
._decNumConfs
(1)
1126 def getSubCategoryList( self
):
1127 subcategs
= self
.subcategories
.values()
1129 for categ
in subcategs
:
1130 cl
.append("%04s%s-%s" % (categ
.getOrder(),categ
.getName().replace("-",""),categ
.getId()))
1134 id = c
.split("-")[1]
1135 res
.append(self
.subcategories
[id])
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
)
1157 res
.sort(Conference
._cmpTitle
)
1159 res
.sort(Conference
._cmpTitle
)
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
:
1174 for subcateg
in self
.subcategories
.itervalues():
1175 for conf
in subcateg
.iterAllConferences():
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()
1184 for subcateg
in subcategs
:
1185 res
.extend(subcateg
.getAllConferenceList())
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()
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
1210 return prev
, nextEvt
, first
, last
1212 def _setNumConferences(self
):
1213 self
._numConferences
= 0
1214 if self
.conferences
:
1215 self
._incNumConfs
(len(self
.conferences
))
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.
1231 if self
._numConferences
:
1233 except AttributeError:
1234 self
._setNumConferences
()
1235 return self
._numConferences
1237 def _getRepository( self
):
1238 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
1240 fr
= dbRoot
["local_repositories"]["main"]
1242 fr
= fileRepository
.MaterialLocalRepository()
1243 dbRoot
["local_repositories"] = OOBTree()
1244 dbRoot
["local_repositories"]["main"] = fr
1247 def removeResource( self
, res
):
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:
1257 self
._icon
= iconFile
1258 self
.notifyModification()
1260 def getIcon( self
):
1264 except AttributeError, e
:
1268 def getIconURL( self
):
1269 if self
.getIcon() is None:
1271 return self
._icon
.getURL()
1273 def removeIcon(self
):
1274 if self
.getIcon() is None:
1278 self
.notifyModification()
1280 def recoverIcon(self
, icon
):
1282 if self
.getIcon() != None:
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")
1297 def revokeModification( self
, prin
):
1298 self
.__ac
.revokeModification( prin
)
1299 if isinstance(prin
, MaKaC
.user
.Avatar
):
1300 prin
.unlinkTo(self
, "manager")
1303 def canModify( self
, aw
):
1304 return self
.canUserModify( aw
.getUser() )
1306 def canUserModify( self
, av
):
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
1320 def canIPAccess( self
, ip
):
1321 if not self
.__ac
.canIPAccess( ip
):
1324 return self
.getOwner().canIPAccess(ip
)
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:
1339 if self
.getAccessProtectionLevel() == -1: #PUBLIC
1341 if self
.getOwner() is not None:
1342 return self
.getOwner().hasAnyProtection()
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
)
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
):
1365 if not self
.isItselfProtected() and self
.getOwner():
1366 return self
.getOwner().isAllowedToAccess( av
)
1368 def canView(self
,aw
):
1369 if self
.canAccess( aw
):
1371 for conf
in self
.getConferenceList():
1372 if conf
.canView( aw
):
1374 for subcateg
in self
.getSubCategoryList():
1375 if subcateg
.canView( aw
):
1379 def canAccess( self
, aw
):
1380 if not self
.hasAnyProtection():
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")
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")
1423 def getConferenceCreatorList( self
):
1424 return self
.__confCreators
1426 def isAllowedToCreateConference( self
, av
):
1428 if self
.canUserModify( av
):
1431 # Avatar is directly in the list
1432 if av
in self
.__confCreators
:
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
):
1444 def canCreateConference( self
, av
):
1445 if not self
.isConferenceCreationRestricted():
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
):
1462 if self
._statistics
:
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')
1476 class CustomLocation(Persistent
):
1478 def __init__(self
, **locationData
):
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
):
1490 d
["name"]=self
.getName()
1491 d
["address"]=self
.getAddress()
1492 d
["room"]=self
.getRoom()
1496 newCL
=CustomLocation()
1497 newCL
.setValues(self
.getValues())
1500 def setName(self
, newName
):
1506 def setAddress(self
, newAddress
):
1507 self
.address
= newAddress
1509 def getAddress(self
):
1512 def setRoom(self
, newRoom
):
1519 class CustomRoom(Persistent
):
1521 def __init__( self
):
1524 def setValues(self
, data
):
1525 self
.setName(data
.get("name",""))
1527 def getValues(self
):
1529 d
["name"]=self
.getName()
1537 newCR
.setValues(self
.getValues())
1540 def setName( self
, newName
):
1541 self
.name
= newName
.strip()
1543 def getName( self
):
1547 class ConferenceParticipation(Persistent
, Fossilizable
, Observable
):
1549 fossilizes(IConferenceParticipationFossil
, IConferenceParticipationMinimalFossil
)
1555 self
._affiliation
=""
1561 def _notifyModification( self
):
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
):
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()
1587 def setId(self
, newId
):
1593 def setDataFromAvatar(self
,av
):
1594 # av is an Avatar object.
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.
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
()
1622 TrashCanManager().add(self
)
1625 TrashCanManager().remove(self
)
1627 @Updates (['MaKaC.conference.ConferenceParticipation',
1628 'MaKaC.conference.SessionChair',
1629 'MaKaC.conference.SlotChair'], 'firstName')
1630 def setFirstName(self
,newName
):
1632 if tmp
==self
._firstName
:
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
):
1645 if tmp
==self
._surName
:
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
):
1658 if tmp
==self
._email
:
1660 self
._email
=newMail
.strip()
1661 self
._notifyModification
()
1663 def getEmail( self
):
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
()
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
()
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
()
1716 def getFullName( self
):
1717 res
= self
.getFamilyName()
1718 if self
.getFirstName() != "":
1719 if res
.strip() != "":
1720 res
= "%s, %s"%( res
, self
.getFirstName() )
1722 res
= self
.getFirstName()
1723 if self
.getTitle() != "":
1724 res
= "%s %s"%( self
.getTitle(), res
)
1727 def getFullNameNoTitle( self
):
1728 res
= self
.getFamilyName()
1729 if self
.getFirstName() != "":
1730 if res
.strip() != "":
1731 res
= "%s, %s"%( res
, self
.getFirstName() )
1733 res
= self
.getFirstName()
1736 def getDirectFullName( self
):
1737 res
= "%s %s"%( self
.getFirstName(), self
.getFamilyName() )
1739 if self
.getTitle() != "":
1740 res
= "%s %s"%( self
.getTitle(), res
)
1743 def getAbrName(self
):
1744 res
= self
.getFamilyName()
1745 if self
.getFirstName() != "":
1748 res
= "%s%s."%(res
, self
.getFirstName()[0].upper())
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
):
1765 ConferenceParticipation
.__init
__(self
)
1767 def _notifyModification( self
):
1768 if self
._conf
!= None:
1769 self
._conf
.notifyModification()
1772 newCC
=ConferenceChair()
1773 newCC
.setValues(self
.getValues())
1776 def getConference(self
):
1782 def includeInConference(self
,conf
,id):
1783 if self
.getConference()==conf
and self
.getId()==id.strip():
1790 ConferenceParticipation
.delete(self
)
1792 def getLocator(self
):
1793 if self
.getConference() is None:
1795 loc
=self
.getConference().getLocator()
1796 loc
["chairId"]=self
.getId()
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
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
1814 def __init__( self
):
1815 self
._idx
= OOBTree()
1816 self
._idxEmail
= OOBTree()
1818 def _getIdxEmail(self
):
1820 return self
._idxEmail
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
1831 ret
= self
._idx
.get(av
.getId(),[])
1833 self
._moveEmailtoId
(av
)
1834 ret
= self
._idx
.get(av
.getId(),[])
1837 def index(self
,av
,contrib
):
1838 """Registers in the index a submitter of a contribution.
1840 if av
==None or contrib
==None:
1842 if not self
._idx
.has_key(av
.getId()):
1844 self
._idx
[av
.getId()]=l
1846 l
=self
._idx
[av
.getId()]
1847 if contrib
not in l
:
1849 self
._idx
[av
.getId()]=l
1851 def indexEmail(self
, email
, contrib
):
1852 if not email
or not contrib
:
1854 if not self
._getIdxEmail
().has_key(email
):
1856 self
._getIdxEmail
()[email
] = l
1858 l
= self
._getIdxEmail
()[email
]
1859 if not contrib
in l
:
1861 self
._getIdxEmail
()[email
] = l
1864 def unindex(self
,av
,contrib
):
1865 if av
==None or contrib
==None:
1867 l
=self
._idx
.get(av
.getId(),[])
1870 self
._idx
[av
.getId()]=l
1872 def unindexEmail(self
, email
, contrib
):
1873 if not email
or not contrib
:
1875 if self
._getIdxEmail
().has_key(email
):
1876 l
= self
._getIdxEmail
()[email
]
1880 del self
._getIdxEmail
()[email
]
1882 self
._getIdxEmail
()[email
] = l
1884 def _moveEmailtoId(self
, av
):
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
):
1902 def addReportNumber(self
, system
, number
):
1903 if system
in self
.getReportNumberKeys() or system
in Config
.getInstance().getReportNumberSystems().keys():
1905 if not number
in self
._reports
[system
]:
1906 self
._reports
[system
].append(number
)
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):
1919 rn
= self
.listReportNumbers()[int(id)]
1920 self
.removeReportNumber(rn
[0], rn
[1])
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
]
1932 def getReportNumberKeys(self
):
1933 return self
._reports
.keys()
1935 def listReportNumbersOnKey(self
, key
):
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
])
1945 def listReportNumbers(self
):
1947 keys
= self
._reports
.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
])
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
)
1964 def notifyModification(self
):
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
1982 confData -- (Dict) Contains the data the conference object has to
1985 #IndexedObject.__init__(self)
1987 raise MaKaCError( _("A creator must be specified when creating a new Event"), _("Event"))
1988 self
.__creator
= creator
1989 self
.__creator
.linkTo(self
, "creator")
1992 self
.description
= ""
1995 ###################################
1996 # Fermi timezone awareness #
1997 ###################################
1998 self
.startDate
= nowutc()
1999 self
.endDate
= nowutc()
2001 ###################################
2002 # Fermi timezone awareness(end) #
2003 ###################################
2004 self
._screenStartDate
= None
2005 self
._screenEndDate
= None
2006 self
.contactInfo
=""
2007 self
.chairmanText
= ""
2009 self
._chairGen
=Counter()
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
= ""
2019 self
.__programGenerator
= Counter() # Provides track unique
2020 # identifiers for this conference
2021 self
.__ac
= AccessController(self
)
2023 self
.__materialGenerator
= Counter() # Provides material unique
2024 # identifiers for this conference
2030 self
.__schedule
=None
2033 self
._creationDS
= creationDate
2035 self
._creationDS
= nowutc() #creation timestamp
2036 if modificationDate
:
2037 self
._modificationDS
= modificationDate
2039 self
._modificationDS
= nowutc() #modification timestamp
2042 self
.__alarmCounter
= Counter()
2044 self
.abstractMgr
= review
.AbstractMgr(self
)
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
2062 self
._registrantGenerator
= Counter()
2065 self
._closed
= False
2066 self
._visibility
= 999
2067 self
._pendingQueuesMgr
=pendingQueues
.ConfPendingQueuesMgr(self
)
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
)
2078 self
._confPaperReview
= ConferencePaperReview(self
)
2079 self
._confAbstractReview
= ConferenceAbstractReview(self
)
2082 self
._sortUrlTag
= ""
2084 self
._observers
= []
2086 if PluginsHolder().hasPluginType("Collaboration"):
2087 from MaKaC
.plugins
.Collaboration
.base
import CSBookingManager
2088 self
._CSBookingManager
= CSBookingManager(self
)
2091 return "<Conference %s@%s>" % (self
.getId(), hex(id(self
)))
2094 def _cmpByDate(self
, toCmp
):
2095 res
= cmp(self
.getStartDate(), toCmp
.getStartDate())
2099 return cmp(self
, toCmp
)
2101 def __cmp__(self
, toCmp
):
2102 if isinstance(toCmp
, Conference
):
2103 return cmp(self
.getId(), toCmp
.getId())
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
):
2118 return self
._sortUrlTag
2120 self
._sortUrlTag
= ""
2121 return self
._sortUrlTag
2123 def setComments(self
,comm
=""):
2124 self
._comments
= comm
.strip()
2126 def getComments(self
):
2130 except AttributeError,e
:
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
):
2146 return self
._orgText
2151 def setOrgText( self
, org
="" ):
2154 def cleanCache( self
):
2155 minfo
= info
.HelperMaKaCInfo
.getMaKaCInfoInstance()
2156 if minfo
.isCacheActive():
2157 cache
= EventCache({"id":self
.getId(), "type": "normal"})
2159 cache
= EventCache({"id":self
.getId(), "type": "manager"})
2161 cache
= EventCache({"id":self
.getId(), "type": "static"})
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
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
2182 for mat
in self
.getAllMaterialList():
2183 if not mat
.isFullyPublic():
2184 self
._fullyPublic
= False
2187 for cont
in self
.getContributionList():
2188 if not cont
.isFullyPublic():
2189 self
._fullyPublic
= False
2192 for ses
in self
.getSessionList():
2193 if not ses
.isFullyPublic():
2194 self
._fullyPublic
= False
2197 self
._fullyPublic
= True
2200 def updateFullyPublic( self
):
2201 self
.setFullyPublic()
2203 # Room booking related
2204 #self.__roomBookingGuids = []
2207 def getKeywords(self
):
2209 return self
._keywords
2214 def setKeywords(self
, keywords
):
2215 self
._keywords
= keywords
2217 def _setCreator(self
, av
):
2220 # Room booking related ===================================================
2222 def getRoomBookingList( self
):
2224 Returns list of bookings for this conference.
2228 for resvGuid
in self
.getRoomBookingGuids():
2229 r
= resvGuid
.getReservation()
2231 self
.removeRoomBookingGuid( resvGuid
)
2236 def getBookedRooms( self
):
2238 Returns list of rooms booked for this conference.
2239 Returns [] if room booking module is off.
2243 for r
in self
.getRoomBookingList():
2244 if not r
.room
in rooms
:
2245 rooms
.append( r
.room
)
2248 def getRoomBookingGuids( self
):
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
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 ) )
2278 resvGuids
.append( ReservationGUID( Location
.getDefaultLocation(), resv
.id ) )
2280 self
.__roomBookingGuids
= resvGuids
2283 # ========================================================================
2285 def getParticipation(self
):
2287 if self
._participation
:
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
)
2303 def getVerboseType( self
):
2304 # Like getType, but returns "Lecture" instead of "simple_type"
2305 type = self
.getType()
2306 if type == "simple_event":
2308 return type.capitalize()
2311 def getLogHandler(self
):
2313 if self
._logHandler
:
2315 except AttributeError :
2316 self
._logHandler
= LogHandler()
2317 return self
._logHandler
2320 def getEnableSessionSlots(self
):
2322 # if self._enableSessionSlots :
2324 #except AttributeError :
2325 # self._enableSessionSlots = True
2326 #if self.getType() == "conference":
2328 #return self._enableSessionSlots
2331 def getEnableSessions(self
):
2333 if self
._enableSessions
:
2335 except AttributeError :
2336 self
._enableSessions
= True
2337 if self
.getType() == "conference":
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:
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)
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()
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() == "":
2392 room
= self
.getRoom()
2396 room
.setName(confData
["roomName"])
2397 self
.notifyModification()
2399 def getVisibility ( self
):
2401 return int(self
._visibility
)
2403 self
._visibility
= 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
):
2420 self
._closed
= 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
2449 return str(self
.___contribTypeGenerator
.newCount())
2451 self
.___contribTypeGenerator
= Counter()
2452 return str(self
.___contribTypeGenerator
.newCount())
2454 def addContribType(self
, ct
):
2456 if self
._contribTypes
:
2459 self
._contribTypes
= {}
2460 if ct
in self
._contribTypes
.values():
2464 id = self
.__generateNewContribTypeId
()
2466 self
._contribTypes
[id] = ct
2467 self
.notifyModification()
2469 def newContribType(self
, name
, description
):
2470 ct
= ContributionType(name
, description
, self
)
2471 self
.addContribType(ct
)
2474 def getContribTypeList(self
):
2476 return self
._contribTypes
.values()
2478 self
._contribTypes
= {}
2479 self
.notifyModification()
2480 return self
._contribTypes
.values()
2482 def getContribTypeById(self
, id):
2484 if self
._contribTypes
:
2487 self
._contribTypes
= {}
2488 self
.notifyModification()
2489 if id in self
._contribTypes
.keys():
2490 return self
._contribTypes
[id]
2493 def removeContribType(self
, ct
):
2495 if self
._contribTypes
:
2498 self
._contribTypes
= {}
2499 if not ct
in self
._contribTypes
.values():
2501 del self
._contribTypes
[ct
.getId()]
2502 for cont
in self
.getContributionList():
2503 if cont
.getType() == ct
:
2506 self
.notifyModification()
2508 def recoverContribType(self
, ct
):
2509 ct
.setConference(self
)
2510 self
.addContribType(ct
)
2513 def _getRepository( self
):
2514 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
2516 fr
= dbRoot
["local_repositories"]["main"]
2518 fr
= fileRepository
.MaterialLocalRepository()
2519 dbRoot
["local_repositories"] = OOBTree()
2520 dbRoot
["local_repositories"]["main"] = fr
2523 def removeResource( self
, res
):
2526 def setLogo( self
, logoFile
):
2527 logoFile
.setOwner( self
)
2528 logoFile
.setId( "logo" )
2529 logoFile
.archive( self
._getRepository
() )
2530 if self
._logo
!= None:
2532 self
._logo
= logoFile
2533 self
.notifyModification()
2535 def getLogo( self
):
2538 def getLogoURL( self
):
2540 if self
._logo
== None:
2542 return self
._logo
.getURL()
2543 except AttributeError:
2547 def removeLogo(self
):
2548 if self
._logo
is None:
2552 self
.notifyModification()
2554 def recoverLogo(self
, logo
):
2556 if self
._logo
!= None:
2560 self
.notifyModification()
2562 def getSession(self
):
2565 def getContribution(self
):
2568 def getSubContribution(self
):
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()
2580 self
._notify
('infoChanged')
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
):
2606 self
.__creator
.unlinkTo(self
, "creator")
2607 creator
.linkTo(self
, "creator")
2608 self
.__creator
= creator
2611 """returns (string) the unique identifier of the conference"""
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 """
2628 d
["confId"] = self
.getId()
2631 def getOwner( self
):
2632 if self
.getOwnerList() == []:
2634 return self
.getOwnerList()[0]
2636 def getOwnerList( self
):
2637 return self
.__owners
2639 def getOwnerPath( self
):
2641 owner
= self
.getOwnerList()[0]
2642 while owner
!= None and owner
.getId() != "0":
2644 owner
= owner
.getOwner()
2647 def getOwnerById( self
, key
):
2648 """Returns one specific category which contains the conference.
2650 - key: The "id" of the category.
2652 for owner
in self
.__owners
:
2653 if key
== owner
.getId():
2657 def addOwner( self
, newOwner
):
2658 if newOwner
== None:
2660 self
.__owners
.append( newOwner
)
2661 self
.notifyModification()
2663 def removeOwner( self
, owner
, notify
=True ):
2664 if not (owner
in self
.__owners
):
2666 self
.__owners
.remove( owner
)
2667 owner
.removeConference( self
)
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
)
2684 """deletes the conference from the system.
2686 #we notify the observers that the conference has been deleted
2688 self
._notify
('deleted', self
.getOwner())
2689 except Exception, e
:
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()
2721 TrashCanManager().add(self
)
2723 def getConference( 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
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)
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
:
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
:
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."),
2769 _("You should try using a larger timespan."))
2771 # so, we really need to try changing something
2776 self
.setStartDate(sDate
, check
=0, moveEntries
= moveEntries
, index
=False, notifyObservers
= False)
2777 self
.setEndDate(eDate
, check
=0, index
=False, notifyObservers
= False)
2780 self
._checkInnerSchedule
()
2782 # reindex the conference
2785 # clear the category cache
2786 self
.cleanCategoryCache()
2790 self
._notify
('dateChanged', {'oldStartDate': oldStartDate
, 'newStartDate': self
.getStartDate(), 'oldEndDate': oldEndDate
, 'newEndDate': self
.getEndDate()})
2791 except Exception, e
:
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():
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 ###################################
2820 self
.verifyStartDate(sDate
)
2821 oldSdate
= self
.getStartDate()
2822 diff
= sDate
- oldSdate
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()[:]
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()
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
2849 self
._notify
('startDateChanged', {'newDate': sDate
, 'oldDate': oldSdate
})
2850 except Exception, e
:
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
):
2860 # are there any alarms? if so, update the relative ones
2861 for alarm
in self
.getAlarmList():
2862 tbef
= alarm
.getTimeBefore()
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
2884 self
._notify
('startTimeChanged', sdate
)
2885 #for observer in self.getObservers():
2886 #observer.notifyEventDateChanges(sdate, self.startDate, None, None)
2887 except Exception, e
:
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):
2904 tz
= self
.getTimezone()
2905 if tz
not in all_timezones
:
2907 return self
.getStartDate().astimezone(timezone(tz
))
2909 ###################################
2910 # Fermi timezone awareness(end) #
2911 ###################################
2913 def setScreenStartDate(self
, date
):
2914 if date
== self
.getStartDate():
2916 self
._screenStartDate
= date
2917 self
.notifyModification()
2919 def getScreenStartDate(self
):
2921 date
= self
._screenStartDate
2923 date
= self
._screenStartDate
= None
2927 return self
.getStartDate()
2929 def getAdjustedScreenStartDate(self
, tz
=None):
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():
2954 if eDate
.year
< 1900:
2955 eDate
= datetime(1900,eDate
.month
,eDate
.day
,eDate
.hour
,eDate
.minute
)
2957 self
.verifyEndDate(eDate
)
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()
2969 #if everything went well, we notify the observers that the start date has changed
2972 self
._notify
('endDateChanged', {'newDate': eDate
, 'oldDate': oldEdate
})
2973 except Exception, e
:
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
2992 self
._notify
('endTimeChanged', edate
)
2993 #for observer in self.getObservers():
2994 except Exception, e
:
2995 #observer.notifyEventDateChanges(None, None, edate, self.endDate)
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"""
3006 ##################################
3007 # Fermi timezone awareness #
3008 ##################################
3010 def getAdjustedEndDate(self
,tz
=None):
3012 tz
= self
.getTimezone()
3013 if tz
not in all_timezones
:
3015 return self
.getEndDate().astimezone(timezone(tz
))
3017 ##################################
3018 # Fermi timezone awareness(end) #
3019 ##################################
3021 def setScreenEndDate(self
, date
):
3022 if date
== self
.getEndDate():
3024 self
._screenEndDate
= date
3025 self
.notifyModification()
3027 def getScreenEndDate(self
):
3029 date
= self
._screenEndDate
3031 date
= self
._screenEndDate
= None
3035 return self
.getEndDate()
3037 def getAdjustedScreenEndDate(self
, tz
=None):
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
):
3053 oldTimezone
= self
.timezone
3054 except AttributeError:
3057 #for observer in self.getObservers():
3059 #observer.notifyTimezoneChange(oldTimezone, tz)
3060 self
._notify
('timezoneChanged', oldTimezone
)
3061 except Exception, e
:
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
):
3070 return self
.timezone
3074 def moveToTimezone(self
, tz
):
3075 if self
.getTimezone() == tz
:
3077 sd
=self
.getAdjustedStartDate()
3078 ed
=self
.getAdjustedEndDate()
3079 self
.setTimezone(tz
)
3081 sDate
= timezone(tz
).localize(datetime(sd
.year
, \
3086 eDate
= timezone(tz
).localize(datetime(ed
.year
, \
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')),
3099 ####################################
3100 # Fermi timezone awareness(end) #
3101 ####################################
3104 """returns (String) the title of the conference"""
3107 def setTitle(self
, title
):
3108 """changes the current title of the conference to the one specified"""
3109 oldTitle
= self
.title
3112 self
.cleanCategoryCache()
3113 self
.notifyModification()
3115 #we notify the observers that the conference's title has changed
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
3140 if self
._supportEmail
:
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)
3149 supportCaption
= self
.getDisplayMgr().getSupportEmailCaption()
3151 if caption
and supportCaption
:
3152 return '"%s" <%s>' % (supportCaption
, self
._supportEmail
)
3154 return self
._supportEmail
3156 def setSupportEmail( self
, newSupportEmail
):
3157 self
._supportEmail
= newSupportEmail
.strip()
3159 def hasSupportEmail( self
):
3161 if self
._supportEmail
:
3163 except AttributeError, e
:
3164 self
._supportEmail
= ""
3165 return self
._supportEmail
!= "" and self
._supportEmail
!= None
3167 def getChairmanText( self
):
3169 if self
.chairmanText
:
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()
3183 def _resetChairs(self
):
3187 except AttributeError:
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)
3200 def _addChair(self
,newChair
):
3201 if newChair
in self
._chairs
:
3206 except AttributeError:
3207 self
._chairGen
=Counter()
3208 id = newChair
.getId()
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
3222 self
._addChair
(newChair
)
3224 def removeChair(self
,chair
):
3225 """removes the specified user from the list of conference
3228 if chair
not in self
._chairs
:
3230 self
._chairs
.remove(chair
)
3231 if isinstance(chair
, MaKaC
.user
.Avatar
):
3232 chair
.unlinkTo(self
, "chair")
3234 self
.notifyModification()
3236 def recoverChair(self
, ch
):
3240 def getChairById(self
,id):
3242 for chair
in self
._chairs
:
3243 if chair
.getId()==id:
3247 def getAllSessionsConvenerList(self
) :
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
)
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
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
3289 def getFavoriteRooms(self
):
3291 roomList
.extend(self
.getRoomList())
3292 #roomList.extend(map(lambda x: x._getName(), self.getBookedRooms()))
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
):
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
):
3319 return self
._modifKey
3320 except AttributeError:
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
3335 1: check and raise error in case of problem
3336 2: check and adapt the owner dates"""
3338 if self
.hasSession(newSession
):
3340 if self
.getSchedule().isOutside(newSession
):
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")
3344 if self
.getSchedule().getStartDate() > newSession
.getStartDate():
3345 self
.setStartDate(newSession
.getStartDate())
3346 if self
.getSchedule().getEndDate() < newSession
.getEndDate():
3347 self
.setEndDate(newSession
.getEndDate())
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()):
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():
3374 del self
.sessions
[session
.getId()]
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
):
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
)
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
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
:
3415 def getNumberOfSessions( self
):
3416 return len(self
.sessions
)
3418 def _generateNewContributionId( self
):
3419 """Returns a new unique identifier for the current conference
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
):
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
()
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() ):
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() ]
3479 self
.notifyModification()
3481 def recoverContribution(self
, contrib
):
3482 self
.addContribution(contrib
, contrib
.getId())
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)
3492 self
.addContribution( c
, id )
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 ]
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
):
3533 return self
.programDescription
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
:
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
:
3564 if track
in self
.program
:
3565 self
.program
.remove( track
)
3566 self
.notifyModification()
3568 def recoverTrack(self
, track
):
3569 self
.addTrack(track
)
3572 def newTrack( self
):
3579 def getTrackById( self
, id ):
3582 for track
in self
.program
:
3583 if track
.getId() == id.strip():
3587 def getTrackList( self
):
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
):
3619 newPos
=self
.getTrackPos(track
)-1
3620 self
.moveTrack(track
,newPos
)
3622 def moveDownTrack(self
,track
):
3625 if self
.isLastTrack(track
):
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.
3646 res
.sort( self
._cmpTracks
)
3649 def canIPAccess( self
, ip
):
3650 if not self
.__ac
.canIPAccess( ip
):
3652 for owner
in self
.getOwnerList():
3653 if not owner
.canIPAccess(ip
):
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():
3685 if self
.getDomainList():
3688 if self
.getAccessProtectionLevel() == -1:
3691 for owner
in self
.getOwnerList():
3692 if owner
.hasAnyProtection():
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
:
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
):
3730 for session
in self
.getSessionList():
3731 if session
.canView( aw
):
3733 for contrib
in self
.getContributionList():
3734 if contrib
.canView( aw
):
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)
3744 if (av
in self
.getChairList()) or (self
.__ac
.canUserAccess( av
)) or (self
.canUserModify( av
)):
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
):
3754 # track coordinators are also allowed to access the conference
3755 for track
in self
.getTrackList():
3756 if track
.isCoordinator( av
):
3759 # paper reviewing team should be also allowed to access
3760 if self
.getConfPaperReview().isInReviewingTeam(av
):
3763 # video services managers are also allowed to access the conference
3764 if PluginsHolder().hasPluginType("Collaboration"):
3765 if self
.getCSBookingManager().isPluginManagerOfAnyPlugin(av
):
3767 from MaKaC
.webinterface
.rh
.collaboration
import RCCollaborationAdmin
, RCCollaborationPluginAdmin
3768 if RCCollaborationAdmin
.hasRights(user
=av
) or \
3769 RCCollaborationPluginAdmin
.hasRights(user
=av
, plugins
='any'):
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
3780 # Allow harvesters (Invenio, offline cache) to access
3782 if self
.__ac
.isHarvesterIP(aw
.getIP()):
3785 if self
.isProtected():
3786 if self
.canUserModify(aw
.getUser()) or self
.isAllowedToAccess( aw
.getUser() ):
3789 return self
.canKeyAccess(aw
)
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
:
3799 keys
= sess
.getVar("accessKeys")
3801 if keys
.has_key(self
.getUniqueId()):
3802 if keys
[self
.getUniqueId()] == accessKey
:
3806 def canKeyModify( self
, aw
):
3807 sess
= aw
.getSession()
3808 modifKey
= self
.getModifKey()
3809 if modifKey
!= "" and sess
:
3810 keys
= sess
.getVar("modifKeys")
3812 if keys
.has_key(self
.id):
3813 if keys
[self
.id] == modifKey
:
3817 def grantModification( self
, prin
, sendEmail
=True ):
3819 if isinstance(prin
, ConferenceChair
):
3820 email
= prin
.getEmail()
3821 elif isinstance(prin
, str):
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")
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
):
3851 if ( av
== self
.getCreator()) or self
.getAccessController().canModify( av
):
3853 for owner
in self
.getOwnerList():
3854 if owner
.canUserModify( av
):
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
):
3884 return av
in self
.getRegistrarList()
3885 except AttributeError:
3888 def getRegistrarList(self
):
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():
3910 self
.materials
[mat
.getId()].setOwner(None)
3911 del self
.materials
[ mat
.getId() ]
3912 self
.notifyModification()
3913 elif mat
.getId().lower() == 'paper':
3915 self
.notifyModification()
3916 elif mat
.getId().lower() == 'slides':
3918 self
.notifyModification()
3919 elif mat
.getId().lower() == 'minutes':
3920 self
.removeMinutes()
3921 self
.notifyModification()
3922 elif mat
.getId().lower() == 'video':
3924 self
.notifyModification()
3925 elif mat
.getId().lower() == 'poster':
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
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
]
3958 def getMaterialList( self
):
3959 return self
.materials
.values()
3961 def getAllMaterialList( self
):
3962 l
= self
.getMaterialList()
3964 l
.append( self
.getPaper() )
3965 if self
.getSlides():
3966 l
.append( self
.getSlides() )
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()))
3976 def setPaper( self
, newPaper
):
3977 if self
.getPaper() != None:
3978 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
3980 self
.paper
.setOwner( self
)
3981 self
.notifyModification()
3983 def removePaper( self
):
3984 if self
.paper
is None:
3987 self
.paper
.setOwner(None)
3989 self
.notifyModification()
3991 def recoverPaper(self
, p
):
3995 def getPaper( self
):
3999 except AttributeError:
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:
4013 self
.slides
.delete()
4014 self
.slides
.setOwner( None )
4016 self
.notifyModification()
4018 def recoverSlides(self
, s
):
4022 def getSlides( self
):
4026 except AttributeError:
4030 def setVideo( self
, newVideo
):
4031 if self
.getVideo() != None:
4032 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
4034 self
.video
.setOwner( self
)
4035 self
.notifyModification()
4037 def removeVideo( self
):
4038 if self
.getVideo() is None:
4041 self
.video
.setOwner(None)
4043 self
.notifyModification()
4045 def recoverVideo(self
, v
):
4049 def getVideo( self
):
4053 except AttributeError:
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:
4067 self
.poster
.delete()
4068 self
.poster
.setOwner(None)
4070 self
.notifyModification()
4072 def recoverPoster(self
, p
):
4076 def getPoster( self
):
4080 except AttributeError:
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()
4099 def removeMinutes( self
):
4100 if self
.getMinutes() is None:
4102 self
.minutes
.delete()
4103 self
.minutes
.setOwner( None )
4105 self
.notifyModification()
4107 def recoverMinutes(self
, min):
4108 self
.removeMinutes() # To ensure that the current minutes are put in
4111 self
.minutes
.setOwner( self
)
4113 self
.notifyModification()
4116 def getMinutes( self
):
4121 except AttributeError, e
:
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
):
4133 if not self
.__schedule
:
4135 except AttributeError, e
:
4137 return self
.__schedule
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:
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():
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())
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"]
4209 confRegistry
= OOBTree
.OOBTree()
4210 db_root
["webfactoryregistry"] = confRegistry
4212 # if the event is a meeting or a lecture
4213 if confRegistry
.get(str(self
.getId()), None) is not None :
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
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 :
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
})
4296 def newAlarm(self
, when
, enqueue
=True):
4298 if type(when
) == timedelta
:
4305 confRelId
= self
._getNextAlarmId
()
4306 al
= tasks
.AlarmTask(self
, confRelId
,
4307 startDateTime
=dtStart
,
4310 self
.addAlarm(al
, enqueue
)
4313 def removeAlarm(self
, alarm
):
4314 confRelId
= alarm
.getConfRelativeId()
4316 if confRelId
in self
.alarmList
:
4317 del self
.alarmList
[confRelId
]
4323 raise Exception("alarm not in list!")
4325 def _getNextAlarmId(self
):
4326 return self
.__alarmCounter
.newCount()
4328 def addAlarm(self
, alarm
, enqueue
= True):
4333 self
.alarmList
[alarm
.getConfRelativeId()] = alarm
4336 def recoverAlarm(self
, alarm
):
4337 self
.addAlarm(alarm
)
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.
4352 if self
._trackCoordinators
:
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.
4363 if self
._trackCoordinators
:
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.
4377 if self
._trackCoordinators
:
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
):
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
):
4429 if self
._speakerIdx
:
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
):
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
):
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
)
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.
4476 id -- id of the wanted evaluation
4478 for evaluation
in self
.getEvaluations():
4479 if str(evaluation
.getId()) == str(id) :
4481 if HelperMaKaCInfo
.getMaKaCInfoInstance().isDebugActive():
4482 raise Exception(_("Error with id: expected '%s', found '%s'.")%(id, self
.getEvaluations()[0].getId()))
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
):
4520 except AttributeError, e
:
4522 self
.notifyModification()
4523 return self
._bookings
4525 def getBookingsList(self
, sort
= False):
4526 bl
= self
.getBookings().values()
4531 def _getBookingGenerator(self
):
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()
4559 def getBookingByType(self
, type):
4560 if self
.getBookings().has_key(type):
4561 return self
.getBookings()[type]
4564 def getBookingById(self
, id):
4565 if self
.getBookings().has_key(id):
4566 return self
.getBookings()[id]
4569 ## End of Videoconference bookings related
4571 def getModPay(self
):
4573 if self
._modPay
is None:
4574 self
._modPay
= epayment
.EPayment(self
)
4575 except AttributeError,e
:
4576 self
._modPay
= epayment
.EPayment(self
)
4579 def getRegistrants(self
):
4581 if self
._registrants
:
4583 except AttributeError, e
:
4584 self
._registrants
= {}
4585 self
.notifyModification()
4586 return self
._registrants
4588 def getRegistrantsByEmail(self
):
4590 if self
._registrantsByEmail
:
4592 except AttributeError, e
:
4593 self
._registrantsByEmail
= self
._createRegistrantsByEmail
()
4594 self
.notifyModification()
4595 return self
._registrantsByEmail
4597 def _createRegistrantsByEmail(self
):
4599 for r
in self
.getRegistrantsList():
4600 dicByEmail
[r
.getEmail()] = r
4603 def getRegistrantsList(self
, sort
= False):
4604 rl
= self
.getRegistrants().values()
4606 rl
.sort(registration
.Registrant
._cmpFamilyName
)
4609 def _getRegistrantGenerator(self
):
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()) )
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]
4653 def _getPrimAuthIndex(self
):
4655 if self
._primAuthIdx
:
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.
4671 if self
._sessionCoordinators
:
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
)
4684 def getManagedSession( self
, av
):
4686 for session
in self
.getSessionList():
4689 for email
in av
.getEmails():
4690 if email
in session
.getAccessController().getModificationEmail():
4693 if av
in session
.getManagerList() or pending
:
4697 def addSessionCoordinator(self
,session
,av
):
4698 """Makes a user become coordinator for a session.
4701 if self
._sessionCoordinators
:
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.
4713 if self
._sessionCoordinators
:
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
):
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
):
4741 except AttributeError:
4742 self
._boa
=BOAConfig(self
)
4745 def getSessionCoordinatorRights(self
):
4747 if self
._sessionCoordinatorRights
:
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
):
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
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
):
4797 if self
._pendingQueuesMgr
:
4799 except AttributeError, e
:
4800 self
._pendingQueuesMgr
=pendingQueues
.ConfPendingQueuesMgr(self
)
4801 return self
._pendingQueuesMgr
4803 def getAccessController(self
):
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
):
4814 if self
._reportNumberHolder
:
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
):
4825 if self
.__badgeTemplateManager
:
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
):
4836 if self
.__posterTemplateManager
:
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
4857 class DefaultConference(Conference
):
4858 """ 'default' conference, which stores the
4859 default templates for posters and badges
4862 def indexConf(self
):
4866 """ Default constructor
4869 Conference
.__init
__(self
, AdminList
.getInstance().getList()[0], "default")
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"
4884 id = ObjectHolder
._newId
( self
)
4887 def getByStartDate( self
, sday
, eday
= None ):
4888 # XXX This function seems strange?
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
:
4897 def getById( self
, id, quiet
=False ):
4898 """returns an object from the index which id corresponds to the one
4902 if (id == "default"):
4903 return CategoryManager().getDefaultConference()
4907 if self
._getIdx
().has_key(str(id)):
4908 return self
._getIdx
()[str(id)]
4912 raise NoReportError( _("The specified event with id \"%s\" does not exist or has been deleted.") % str(id) )
4914 class ConfSectionsMgr
:
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)
4937 def getSections(self
):
4938 return self
._sections
4940 def getSectionList(self
, sort
=False):
4941 l
=self
._sections
.values()
4946 def getSectionKeys(self
, sort
=False):
4947 l
=self
._sections
.keys()
4952 def getSection(self
, id):
4953 if self
._sections
.has_key(id):
4954 return self
._sections
[id]
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
__
4982 conf
= self
.getOwner()
4983 name
= name
+ " of event " + conf
.getId() + "'"
4984 except AttributeError:
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
):
5061 ConferenceParticipation
.__init
__(self
)
5063 def _notifyModification( self
):
5064 if self
._session
!= None:
5065 self
._session
.notifyModification()
5068 chair
= SessionChair()
5069 chair
.setValues(self
.getValues())
5072 def getSession(self
):
5073 return self
._session
5075 def getConference(self
):
5079 return s
.getConference()
5081 def includeInSession(self
,session
,id):
5082 if self
.getSession()==session
and self
.getId()==id.strip():
5084 self
._session
=session
5089 ConferenceParticipation
.delete(self
)
5091 def getLocator(self
):
5092 if self
.getSession() is None:
5094 loc
=self
.getSession().getLocator()
5095 loc
["convId"]=self
.getId()
5099 class SlotChair(ConferenceParticipation
):
5104 ConferenceParticipation
.__init
__(self
)
5106 def _notifyModification( self
):
5107 if self
._slot
!= None:
5108 self
._slot
.notifyModification()
5112 chair
.setValues(self
.getValues())
5118 def getSession(self
):
5122 return s
.getSession()
5124 def getConference(self
):
5128 return s
.getConference()
5130 def includeInSlot(self
,slot
,id):
5131 if self
.getSlot()==slot
and self
.getId()==id.strip():
5138 ConferenceParticipation
.delete(self
)
5140 def getLocator(self
):
5141 if self
.getSlot() is None:
5143 loc
=self
.getSlot().getLocator()
5144 loc
["convId"]=self
.getId()
5147 class SessionCoordinatorRights
:
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
):
5160 def getRightList(self
, sort
=False):
5161 l
=self
._rights
.values()
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]
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
):
5191 def getSessions(self
,av
):
5192 """Gives a list with the sessions a user is coordinating.
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:
5203 if not self
._idx
.has_key(av
.getId()):
5205 self
._idx
[av
.getId()]=l
5207 l
=self
._idx
[av
.getId()]
5208 if session
not in l
:
5210 self
.notifyModification()
5212 def unindex(self
,av
,session
):
5213 if av
==None or session
==None:
5215 l
=self
._idx
.get(av
.getId(),[])
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
5240 sessionData -- (Dict) Contains the data the session object has to
5243 self
.conference
=None
5244 self
.id="not assigned"
5247 #################################
5248 # Fermi timezone awareness #
5249 #################################
5250 self
.startDate
= nowutc()
5251 #################################
5252 # Fermi timezone awareness(end) #
5253 #################################
5255 self
.duration
=timedelta(minutes
=1)
5258 self
.conveners
=[] # This attribute must not be used and should disappear someday
5260 self
._convenerGen
=Counter()
5261 self
.convenerText
=""
5262 self
.contributions
={}
5263 self
._contributionDuration
=timedelta(minutes
=20)
5264 self
.__ac
=AccessController(self
)
5266 self
.__materialGenerator
=Counter()
5270 self
.__slotGenerator
=Counter()
5272 self
._coordinators
=OOBTree()
5273 self
._coordinatorsEmail
= []
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()
5285 def getTimezone( self
):
5286 return self
.getConference().getTimezone()
5288 def isFullyPublic( self
):
5289 if hasattr(self
, "_fullyPublic"):
5290 return self
._fullyPublic
5292 self
.setFullyPublic()
5293 return self
._fullyPublic
5295 def setFullyPublic( self
):
5296 if self
.isProtected():
5297 self
._fullyPublic
= False
5300 for res
in self
.getAllMaterialList():
5301 if not res
.isFullyPublic():
5302 self
._fullyPublic
= False
5305 for res
in self
.getContributionList():
5306 if not res
.isFullyPublic():
5307 self
._fullyPublic
= False
5310 self
._fullyPublic
= True
5313 def updateFullyPublic( self
):
5314 self
.setFullyPublic()
5315 self
.getOwner().updateFullyPublic()
5317 def getKeywords(self
):
5319 return self
._keywords
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()
5334 parent
.setModificationDate(date
)
5337 def getModificationDate( self
):
5338 """Returns the date in which the session was last modified"""
5340 return self
._modificationDS
5342 self
._modificationDS
= nowutc()
5343 return self
._modificationDS
5345 def getCreationDate( self
):
5346 """Returns the date in which the session was created"""
5348 return self
._creationDS
5350 self
._creationDS
= nowutc()
5351 return self
._creationDS
5353 def getLogInfo(self
):
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()
5377 def getEnableSessionSlots(self
):
5379 return self
.getConference().getEnableSessionSlots()
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
):
5392 if self
._registrationSession
:
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():
5407 self
._closed
= False
5410 def setClosed( self
, closed
=True ):
5411 self
._closed
= closed
5412 self
.notifyModification()
5414 def includeInConference(self
,conf
,newId
):
5415 self
.conference
=conf
5417 for slot
in self
.getSlotList():
5418 conf
.getSchedule().addEntry(slot
.getConfSchEntry(),2)
5419 self
.getConference().addSession(self
)
5420 self
.notifyModification()
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():
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:
5457 lconf
= self
.conference
.getLocator()
5458 lconf
["sessionId"] = self
.getId()
5461 def getConference( self
):
5462 return self
.conference
5464 def getSession( self
):
5467 def getOwner( self
):
5468 return self
.getConference()
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
):
5486 return self
._contributionDuration
5488 self
._contributionDuration
= timedelta(minutes
=20)
5489 return self
._contributionDuration
5491 def setContribDuration(self
, hour
=0, min=20, dur
=None):
5493 self
._contributionDuration
=dur
5495 self
._contributionDuration
= timedelta(hours
=hour
,minutes
=min)
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
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())
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
)
5527 self
.notifyModification()
5529 def recoverSlot(self
, slot
):
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
)
5544 def getMinSlotStartTime(self
):
5546 for slot
in self
.getSlotList():
5547 if slot
.isMoreThanDay():
5549 shour
= slot
.getStartDate().hour
5550 smin
= slot
.getStartDate().minute
5551 if (shour
, smin
) < min:
5555 def getMaxSlotEndTime(self
):
5557 for slot
in self
.getSlotList():
5558 if slot
.isMoreThanDay():
5560 endDate
= slot
.getEndDate()
5561 if (endDate
.hour
, endDate
.minute
) > max:
5562 newEndDate
= endDate
- timedelta(0, 0, 0)
5563 max = (newEndDate
.hour
, newEndDate
.minute
)
5566 def getMinSlotStartDate(self
):
5567 slotList
= self
.getSlotList()
5568 if len(slotList
)==0:
5569 return self
.getStartDate()
5571 sDate
= self
.getEndDate()
5572 for slot
in slotList
:
5573 if slot
.getStartDate() < sDate
:
5574 sDate
= slot
.getStartDate()
5577 def getMaxSlotEndDate(self
):
5578 slotList
= self
.getSlotList()
5579 if len(slotList
)==0:
5580 return self
.getEndDate()
5582 eDate
= self
.getStartDate()
5583 for slot
in slotList
:
5584 if slot
.getEndDate() > eDate
:
5585 eDate
= slot
.getEndDate()
5588 def _getCorrectColor(self
, color
):
5589 if not color
.startswith("#"):
5591 m
= re
.match("^#[0-9A-Fa-f]{6}$", color
)
5596 def _getCorrectBgColor(self
, color
):
5597 color
=self
._getCorrectColor
(color
)
5602 def _getCorrectTextColor(self
, color
):
5603 color
=self
._getCorrectColor
(color
)
5605 return self
._textColor
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:
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
5624 durMin - (int) => hours of duration for each entry in the session
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")
5643 self
.setCode(self
.getId())
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()))
5654 self
.setTextColor(self
._getCorrectTextColor
(textcolor
))
5655 self
.setTextColorToLinks(sessionData
.has_key("textcolortolinks"))
5657 if "locationName" in sessionData
:
5658 loc
= self
.getOwnLocation()
5660 loc
= CustomLocation()
5661 self
.setLocation( loc
)
5662 loc
.setName( sessionData
["locationName"] )
5663 loc
.setAddress( sessionData
.get("locationAddress", "") )
5665 self
.setLocation(None)
5667 #same as for the location
5668 if "roomName" in sessionData
:
5669 room
= self
.getOwnRoom()
5672 self
.setRoom( room
)
5673 room
.setName( sessionData
["roomName"] )
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")
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
):
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()
5759 def setTitle( self
, newTitle
):
5760 self
.title
= newTitle
5761 self
.notifyModification()
5763 def getTitle( self
):
5766 def setDescription(self
, newDescription
):
5767 self
.description
= newDescription
5768 self
.notifyModification()
5770 def getDescription(self
):
5771 return self
.description
5777 except AttributeError:
5781 def setCode(self
,newCode
):
5782 self
._code
=str(newCode
).strip()
5788 except AttributeError:
5789 self
._color
="#e3f2d3"
5793 def setColor(self
,newColor
):
5794 self
._color
=str(newColor
).strip()
5797 def getTextColor(self
):
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
):
5810 if self
._textColorToLink
:
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):
5824 tz
= self
.getConference().getTimezone()
5825 if tz
not in all_timezones
:
5827 return self
.startDate
.astimezone(timezone(tz
))
5829 def verifyStartDate(self
, sdate
, check
=2):
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():
5840 raise ParentTimingError( _("The session starting date cannot be prior to the event starting date"), _("Session"))
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
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")
5857 self
.verifyStartDate(newDate
,check
)
5858 oldSdate
= self
.getStartDate()
5860 tz
= str(self
.getStartDate().tzinfo
)
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()[:]
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
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):
5904 1: check and raise error in case of problem
5905 2: check and adapt the owner dates
5908 tz
= timezone(self
.getConference().getTimezone())
5910 tz
= timezone('UTC')
5911 # compare end date with start date
5912 if edate
<=self
.getStartDate():
5914 raise MaKaCError( _("End date cannot be prior to the Start date"), _("Session"))
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
):
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')),\
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")
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):
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):
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"))
5971 self
.verifyEndDate(self
.getEndDate())
5972 self
.notifyModification()
5974 def getStartOnDay(self
, day
, tz
=None):
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() :
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()
5991 def getEndOnDay(self
, day
, tz
=None):
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() :
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()
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
6022 def addLocation(self
, newPlace
):
6023 self
.places
.append( newPlace
)
6024 self
.notifyModification()
6026 def _resetConveners(self
):
6030 except AttributeError:
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
:
6045 if self
._convenerGen
:
6047 except AttributeError:
6048 self
._convenerGen
=Counter()
6049 id = newConv
.getId()
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
:
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")
6076 self
.notifyModification()
6078 def recoverConvener(self
, con
):
6079 self
.addConvener(con
)
6082 def getConvenerById(self
,id):
6084 for conv
in self
._conveners
:
6085 if conv
.getId()==id:
6089 def getConvenerText( self
):
6092 if self
.convenerText
:
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
):
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
):
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 ):
6137 self
.addContribution( c
, id )
6140 def getContributionById(self
,id):
6142 if self
.contributions
.has_key( id ):
6143 return self
.contributions
[ id ]
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
):
6155 if self
.getOwner() != None:
6156 return self
.getOwner().canIPAccess(ip
)
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():
6175 if self
.getDomainList():
6177 if self
.getAccessProtectionLevel() == -1:
6180 return self
.getOwner().hasAnyProtection()
6182 def hasProtectedOwner( self
):
6183 if self
.getOwner() != None:
6184 return self
.getOwner().isProtected()
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
):
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"):
6212 ################################################################################################
6213 for contrib
in self
.getContributionList():
6214 if contrib
.canView( aw
):
6218 def isAllowedToAccess( self
, user
):
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
)):
6226 def canAccess( self
, aw
):
6227 # Allow harvesters (Invenio, offline cache) to access
6229 if self
.__ac
.isHarvesterIP(aw
.getIP()):
6231 #####################################################
6233 if not self
.canIPAccess(aw
.getIP()) and not self
.canUserModify(aw
.getUser()) and not self
.isAllowedToAccess( aw
.getUser() ):
6235 if not self
.isProtected():
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
):
6243 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
6246 if sb
.getEmail().lower().strip() in [j
.lower().strip() for j
in i
.getEmails()]:
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() )
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() ]
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
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
]
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()))
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
):
6340 if self
.__schedule
is None or not isinstance(self
.__schedule
,SessionSchedule
):
6342 except AttributeError, e
:
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
):
6365 except AttributeError,e
:
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()
6377 def removeMinutes( self
):
6378 if self
.minutes
is None:
6380 self
.minutes
.delete()
6381 self
.minutes
.setOwner( None )
6383 self
.notifyModification()
6385 def recoverMinutes(self
, min):
6386 self
.removeMinutes() # To ensure that the current minutes are put in
6389 self
.minutes
.setOwner( self
)
6391 self
.notifyModification()
6394 def getMinutes( self
):
6399 except AttributeError, e
:
6404 def _addCoordinator(self
, av
):
6405 if av
is None or self
._coordinators
.has_key(av
.getId()):
6407 self
._coordinators
[av
.getId()]=av
6408 if self
.getConference() is not None:
6409 self
.getConference().addSessionCoordinator(self
,av
)
6411 def getCoordinatorEmailList(self
):
6413 return self
._coordinatorsEmail
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
)
6428 def addCoordinator( self
, sb
, sendEmail
=True ):
6429 """Grants coordination privileges to user.
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.
6440 if self
._coordinators
:
6442 except AttributeError, e
:
6443 self
._coordinators
=OOBTree()
6445 if isinstance(sb
, SessionChair
):
6447 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
6451 if sb
.getEmail().lower().strip() in [j
.lower().strip() for j
in i
.getEmails()]:
6455 if r
is not None and r
.isActivated():
6457 self
._addCoordinator
(r
)
6458 r
.linkTo(self
, "coordinator")
6460 self
.getConference().getPendingQueuesMgr().addPendingCoordinator(sb
)
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.
6470 av -- (MaKaC.user.Avatar) user for which coordination privileges
6474 if self
._coordinators
:
6476 except AttributeError, e
:
6477 self
._coordinators
=OOBTree()
6479 if av
is None or not self
._coordinators
.has_key(av
.getId()):
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.
6491 av -- (MaKaC.user.Avatar) user to be checked
6493 Return value: (boolean)
6496 if self
._coordinators
:
6498 except AttributeError, e
:
6499 self
._coordinators
=OOBTree()
6500 if (av
is not None) and self
._coordinators
.has_key(av
.getId()):
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
)
6512 def getCoordinatorList( self
):
6513 """Return all users which have privileges to coordinate the session.
6515 Return value: (list)
6518 if self
._coordinators
:
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
6532 aw -- (MaKaC.accessControl.AccessWrapper) User access
6533 information for which the coordination privileges must be
6536 Return value: (boolean)
6539 return self
.isCoordinator(aw
.getUser()) and self
.getConference().hasSessionCoordinatorRight(right
)
6540 return self
.isCoordinator(aw
.getUser())
6543 def getScheduleType(self
):
6547 except AttributeError:
6548 self
._ttType
=SlotSchTypeFactory
.getDefaultId()
6551 def setScheduleType(self
,t
):
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
:
6561 for slot
in self
.getSlotList():
6562 slot
.setScheduleType(t
)
6564 def getAccessController(self
):
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"
6583 self
.duration
= timedelta(minutes
=1)
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
):
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
6604 for p
in self
.places
:
6605 data
["place %s"%i] = p
.getName()
6608 for r
in self
.rooms
:
6609 data
["room %s"%i] = r
.getName()
6611 for c
in self
._conveners
:
6612 data
["convener %s"%c.getId()] = c
.getFullName()
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)
6625 if self
.getOwnLocation() is not None:
6626 slot
.setLocation(self
.getOwnLocation().clone())
6628 if self
.getOwnRoom() is not None:
6629 slot
.setRoom(self
.getOwnRoom().clone())
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()
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
):
6671 if i
+1 == len(entries
):
6672 dur
=self
.getEndDate()-entry
.getStartDate()
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
)
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
6689 #if not isinstance(entry, BreakTimeSchEntry):
6690 # st=entry.getEndDate()+diff
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):
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()
6719 loc
= CustomLocation()
6720 self
.setLocation( loc
)
6721 loc
.setName( data
["locationName"] )
6722 loc
.setAddress( data
.get("locationAddress", "") )
6724 self
.setLocation( None )
6726 if "roomName" in data
:
6727 room
= self
.getOwnRoom()
6730 self
.setRoom( room
)
6731 room
.setName( data
["roomName"] )
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
)
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"))
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
:
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
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.
6801 if self
._contributionDuration
:
6803 except AttributeError, e
:
6804 self
._contributionDuration
= None
6805 return self
._contributionDuration
6807 def notifyModification( self
):
6808 self
.getSession().notifyModification()
6811 def getLocator( self
):
6812 l
=self
.getSession().getLocator()
6813 l
["slotId"]=self
.getId()
6816 def getConference( self
):
6817 return self
.getSession().getConference()
6819 def getSession(self
):
6822 def getOwner( self
):
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
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
):
6845 if self
._confSchEntry
:
6847 except AttributeError:
6848 self
._confSchEntry
=LinkedTimeSchEntry(self
)
6849 return self
._confSchEntry
6851 def getSessionSchEntry( self
):
6853 if self
._sessionSchEntry
:
6855 except AttributeError:
6856 self
._sessionSchEntry
=self
._schEntry
6857 return self
._sessionSchEntry
6859 def setId( self
, newId
):
6861 self
.notifyModification()
6866 def setTitle( self
, newTitle
):
6868 self
.notifyModification()
6870 def getTitle( self
):
6874 except AttributeError,e
:
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):
6887 1: check and raise error in case of problem
6888 2: check and adapt the owner dates"""
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()
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
6908 se
= slotEntry
.getOwner()
6909 se
.startDate
= se
.getStartDate() + diff
6910 self
.getSchedule().reSchedule()
6912 def verifyStartDate(self
, sDate
,check
=2):
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():
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')),\
6927 self
.getSession().setStartDate(sDate
, check
, 0)
6929 def setStartDate(self
,sDate
,check
=2,moveEntries
=0,checkDuration
=True):
6932 1: check and raise error in case of problem
6933 2: check and adapt the owner dates"""
6936 if not sDate
.tzname():
6937 raise MaKaCError("date should be timezone aware")
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
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")
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):
6983 tz
= self
.getConference().getTimezone()
6984 if tz
not in all_timezones
:
6986 return self
.startDate
.astimezone(timezone(tz
))
6988 def getEndDate( self
):
6989 if self
.startDate
is None:
6991 return self
.startDate
+self
.duration
6993 def getAdjustedEndDate( self
, tz
=None ):
6995 tz
= self
.getConference().getTimezone()
6996 if tz
not in all_timezones
:
6998 if self
.getEndDate():
6999 return self
.getEndDate().astimezone(timezone(tz
))
7002 def getDuration( self
):
7003 return self
.duration
7005 def isMoreThanDay(self
):
7006 if self
.getDuration() >= timedelta(days
=1):
7010 def verifyDuration(self
, dur
, check
=1):
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"))
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
:
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')),\
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()
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')),\
7048 def setDuration(self
, days
=0,hours
=0,minutes
=0,dur
=0,check
=1):
7051 1: check and raise error in case of problem
7052 2: check and adapt the owner dates"""
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",
7059 dur
= timedelta(minutes
=1)
7060 if dur
> timedelta(days
=1) and check
==2:
7061 pass#dur = timedelta(days=1)
7063 self
.verifyDuration(dur
, check
)
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
7078 self
.getSchedule().clear()
7079 if self
.getSession() is not None:
7080 self
.getSession().removeSlot(self
)
7082 TrashCanManager().add(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
:
7098 self
._setSchedule
(SlotSchTypeFactory
.getScheduleKlass(id))
7100 def getConvenerList(self
):
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
:
7114 if self
._convenerGen
:
7116 except AttributeError:
7117 self
._convenerGen
=Counter()
7118 id = newConv
.getId()
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
:
7128 self
._conveners
.remove(conv
)
7130 self
.notifyModification()
7132 def recoverConvener(self
, con
):
7133 self
.addConvener(con
)
7136 def getConvenerById(self
,id):
7138 for conv
in self
._conveners
:
7139 if conv
.getId()==id:
7143 def getOwnConvenerList(self
):
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()
7158 if self
.getSession() is not None:
7159 res
=self
.getSession().getColor()
7162 def getTextColor(self
):
7164 if self
.getSession() is not None:
7165 res
=self
.getSession().getTextColor()
7169 class ContributionParticipation(Persistent
, Fossilizable
):
7171 fossilizes(IContributionParticipationFossil
, IContributionParticipationMinimalFossil
,\
7172 IContributionParticipationTTDisplayFossil
,\
7173 IContributionParticipationTTMgmtFossil
)
7175 def __init__( self
):
7176 self
._contrib
= None
7178 self
._firstName
= ""
7181 self
._affiliation
= ""
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
):
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()
7215 part
= ContributionParticipation()
7216 part
.setValues(self
.getValues())
7219 def setDataFromAvatar(self
,av
):
7220 # av is an Avatar object.
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.
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():
7250 self
._contrib
= contrib
7254 self
._contrib
= None
7255 TrashCanManager().add(self
)
7258 TrashCanManager().remove(self
)
7260 def setId(self
, newId
):
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:
7275 loc
=self
.getContribution().getLocator()
7276 loc
["authId"]=self
.getId()
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
)
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
):
7298 if tmp
==self
._firstName
:
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
):
7315 if tmp
==self
._surName
:
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
):
7332 if tmp
==self
._email
:
7335 self
._email
=newMail
.strip()
7337 self
._notifyModification
()
7339 def getEmail( self
):
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":
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
):
7368 @Updates ('MaKaC.conference.ContributionParticipation', 'title')
7369 def setTitle( self
, newTitle
):
7370 self
._title
= newTitle
.strip()
7371 self
._notifyModification
()
7373 def getTitle( self
):
7376 @Updates ('MaKaC.conference.ContributionParticipation', 'fax')
7377 def setFax( self
, newFax
):
7378 self
._fax
= newFax
.strip()
7379 self
._notifyModification
()
7385 except AttributeError:
7389 def getDirectFullName( self
):
7390 res
= "%s %s"%( self
.getFirstName(), self
.getFamilyName().upper() )
7392 if self
.getTitle() != "":
7393 res
= "%s %s"%( self
.getTitle(), res
)
7396 def getFullName( self
):
7397 res
= self
.getFullNameNoTitle()
7398 if self
.getTitle() != "":
7399 res
= "%s %s"%( self
.getTitle(), 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() )
7408 res
= self
.getFirstName()
7411 def getAbrName(self
):
7412 res
= self
.getFamilyName()
7413 if self
.getFirstName() != "":
7416 res
= "%s%s."%(res
, self
.getFirstName()[0].upper())
7420 def isPendingSubmitter(self
):
7421 if self
.getContribution() is None:
7423 if self
.getContribution().getConference() is None:
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
):
7441 def _getKey(self
,author
):
7442 k
= "%s %s %s"%(author
.getFamilyName().lower(),author
.getFirstName().lower(),author
.getEmail().lower())
7445 def index(self
,author
):
7446 key
=self
._getKey
(author
)
7447 if not self
._idx
.has_key(key
):
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
]:
7461 if len(self
._idx
[key
])<=0:
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
7481 def match(self
, criteria
, exact
=0):
7482 self
._options
= ['organisation', 'surName', 'name', 'email']
7484 for item
in self
.getParticipations():
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()):
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()):
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()):
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()):
7508 if len(ok
) > 0 and not False in ok
:
7512 class _AuthIdx(Persistent
):
7514 def __init__(self
,conf
):
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
):
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:
7549 def match(self
,query
):
7550 query
=query
.lower().strip()
7552 for k
in self
._idx
.keys():
7553 if k
.find(query
)!=-1:
7554 res
=union(res
,self
._idx
[k
])
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():
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
):
7583 self
.description
= ""
7585 self
.duration
= timedelta(0)
7587 self
.speakerText
= ""
7590 self
._boardNumber
=""
7591 self
._resetSchEntry
()
7592 self
.__ac
= AccessController(self
)
7594 self
.__materialGenerator
= Counter()
7596 self
.__subContGenerator
= Counter()
7602 self
.reviewing
= None
7603 self
._authorGen
= Counter()
7604 self
._authors
= OOBTree()
7605 self
._primaryAuthors
= []
7606 self
._coAuthors
= []
7610 self
._status
=ContribStatusNotSch(self
)
7611 #List of allowed users to submit material
7613 self
._submittersEmail
=[]
7614 self
._modificationDS
= nowutc()
7616 self
._reviewManager
= ReviewManager(self
)
7620 parentId
= self
.parent
.getId()
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
7637 self
.setFullyPublic()
7638 return self
._fullyPublic
7640 def setFullyPublic( self
):
7641 if self
.isProtected():
7642 self
._fullyPublic
= False
7645 for res
in self
.getAllMaterialList():
7646 if not res
.isFullyPublic():
7647 self
._fullyPublic
= False
7650 for res
in self
.getSubContributionList():
7651 if not res
.isFullyPublic():
7652 self
._fullyPublic
= False
7655 self
._fullyPublic
= True
7658 def updateFullyPublic( self
):
7659 self
.setFullyPublic()
7660 self
.getOwner().updateFullyPublic()
7662 def getKeywords(self
):
7664 return self
._keywords
7669 def setKeywords(self
, keywords
):
7670 if type(keywords
) is list:
7671 self
._keywords
= keywords
[0]
7673 self
._keywords
= keywords
7674 self
.notifyModification()
7676 def getFields( self
):
7682 if self
.summary
!= "":
7683 self
._fields
["summary"] = self
.summary
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
):
7696 self
.getFields()[field
] = value
7697 self
.notifyModification()
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
)
7713 def getLogInfo(self
):
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():
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()
7751 data
["submitter"] = s
.getName()
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:
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
7768 durationHours, durationMinutes - (str)
7772 1: check and raise error in case of problem
7773 2: check and adapt the owner dates
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():
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()
7808 loc
=CustomLocation()
7809 self
.setLocation(loc
)
7810 loc
.setName(data
["locationName"])
7811 loc
.setAddress(data
.get("locationAddress", ""))
7813 self
.setLocation(None)
7815 #same as for the location
7816 if "roomName" in data
:
7817 room
=self
.getOwnRoom()
7821 room
.setName(data
["roomName"])
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')),
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
)
7851 h
=data
.get("durHours","").strip()
7852 m
=data
.get("durMins","").strip()
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() )
7874 deltaTime
= parent
.getStartDate() - self
.getOwner().getStartDate()
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() :
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() :
7907 if options
.get("access", False) :
7908 cont
.setProtection(self
.getAccessController()._getAccessProtection
())
7909 for u
in self
.getAllowedToAccessList() :
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
))
7948 def notifyModification( self
, date
= None, raiseEvent
= True):
7950 self
.setModificationDate(date
)
7953 self
._notify
('infoChanged')
7955 parent
= self
.getParent()
7957 parent
.setModificationDate()
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:
7975 lconf
= self
.getConference().getLocator()
7976 if self
.getSession() is not None:
7977 lconf
["sessionId"] = self
.getSession().getId()
7978 lconf
["contribId"] = self
.getId()
7981 def _setConference( self
, conf
):
7984 def _setId( self
, 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")
7994 self
._setConference
( conf
)
7998 """deletes a contribution and all of its subitems
8001 oldParent
= self
.getConference()
8003 if oldParent
!= None:
8004 self
._notify
('deleted', oldParent
)
8007 self
.setSession(None)
8008 for mat
in self
.getMaterialList():
8009 self
.removeMaterial(mat
)
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
)
8038 TrashCanManager().remove(self
)
8040 def setId( self
, newId
):
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()
8056 self
._notify
('contributionTitleChanged', oldTitle
, newTitle
)
8057 self
.notifyModification()
8059 def getTitle( self
):
8060 if self
.title
.strip() == "":
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
):
8079 self
.notifyModification()
8080 if self
.parent
==None:
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
):
8097 def getSession( self
):
8101 except AttributeError:
8103 return self
._session
8105 def setSession(self
,session
):
8106 if self
.getSession()==session
:
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
):
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
):
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
):
8160 def setRoom( self
, 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
):
8171 if self
._boardNumber
:
8173 except AttributeError:
8174 self
._boardNumber
=""
8175 return self
._boardNumber
8177 def verifyStartDate(self
, sDate
, check
=2):
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()
8187 owner
= self
.getOwner()
8188 if sDate
< owner
.getStartDate():
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')),\
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():
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')),\
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():
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')),\
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):
8222 1: check and raise error in case of problem
8223 2: check and adapt the owner dates"""
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:
8244 tz
= self
.getConference().getTimezone()
8245 if tz
not in all_timezones
:
8247 return self
.getStartDate().astimezone(timezone(tz
))
8249 def getEndDate( self
):
8250 if self
.getStartDate() is None:
8252 return self
.getStartDate()+self
.getDuration()
8254 def getAdjustedEndDate(self
,tz
=None):
8256 tz
= self
.getConference().getTimezone()
8257 if tz
not in all_timezones
:
8259 if self
.getEndDate():
8260 return self
.getEndDate().astimezone(timezone(tz
))
8263 def getDuration( self
):
8264 return self
.duration
8266 def verifyDuration(self
, check
=2):
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():
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')),\
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):
8293 1: check and raise error in case of problem
8294 2: check and adapt the owner dates"""
8299 self
.duration
=timedelta(hours
=int(hours
),minutes
=int(minutes
))
8301 self
.verifyDuration(check
)
8302 self
.getSchEntry().synchro()
8303 self
.notifyModification()
8305 def _addAuthor( self
, part
):
8311 except AttributeError:
8312 self
._authors
= OOBTree()
8316 except AttributeError:
8317 self
._authorGen
=Counter()
8318 newId
= part
.getId()
8320 newId
= str( self
._authorGen
.newCount() )
8321 self
._authors
[newId
] = part
8322 part
.includeInContribution( self
, newId
)
8324 def _removeAuthor( self
, part
):
8330 except AttributeError:
8331 self
._authors
= OOBTree()
8332 if not self
._authors
.has_key( part
.getId() ):
8334 del self
._authors
[ part
.getId() ]
8337 def addPrimaryAuthor( self
, part
):
8341 if self
._primaryAuthors
:
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):
8355 if self
._primaryAuthors
:
8357 except AttributeError:
8358 self
._primaryAuthors
= []
8359 if part
not in self
._primaryAuthors
:
8361 if self
.getConference() is not None:
8362 self
.getConference().unindexAuthor(part
)
8363 self
._primaryAuthors
.remove( part
)
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
)
8376 if isPendingSubmitter
:
8377 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(pa
, False)
8379 def isPrimaryAuthor( self
, part
):
8383 if self
._primaryAuthors
:
8385 except AttributeError:
8386 self
._primaryAuthors
= []
8387 return part
in self
._primaryAuthors
8389 def upPrimaryAuthor(self
,part
):
8393 if self
._primaryAuthors
:
8395 except AttributeError:
8396 self
._primaryAuthors
=[]
8398 idx
=self
._primaryAuthors
.index(part
)
8403 self
._primaryAuthors
.remove(part
)
8404 self
._primaryAuthors
.insert(idx
-1,part
)
8405 self
.notifyModification()
8407 def downPrimaryAuthor(self
,part
):
8411 if self
._primaryAuthors
:
8413 except AttributeError:
8414 self
._primaryAuthors
=[]
8416 idx
=self
._primaryAuthors
.index(part
)
8419 if idx
>len(self
._primaryAuthors
):
8421 self
._primaryAuthors
.remove(part
)
8422 self
._primaryAuthors
.insert(idx
+1,part
)
8423 self
.notifyModification()
8425 def upCoAuthor(self
,part
):
8431 except AttributeError:
8434 idx
=self
._coAuthors
.index(part
)
8439 self
._coAuthors
.remove(part
)
8440 self
._coAuthors
.insert(idx
-1,part
)
8441 self
.notifyModification()
8443 def downCoAuthor(self
,part
):
8449 except AttributeError:
8452 idx
=self
._coAuthors
.index(part
)
8455 if idx
>len(self
._coAuthors
):
8457 self
._coAuthors
.remove(part
)
8458 self
._coAuthors
.insert(idx
+1,part
)
8459 self
.notifyModification()
8461 def getPrimaryAuthorList( self
):
8465 if self
._primaryAuthors
:
8467 except AttributeError:
8468 self
._primaryAuthors
= []
8469 return self
._primaryAuthors
8471 getPrimaryAuthorsList
= getPrimaryAuthorList
8473 def getAuthorList( self
):
8479 except AttributeError:
8480 self
._authors
= OOBTree()
8481 return self
._authors
.values()
8483 def addCoAuthor( self
, part
):
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):
8503 except AttributeError:
8504 self
._coAuthors
= []
8505 if part
not in self
._coAuthors
:
8507 if self
.getConference() is not None:
8508 self
.getConference().unindexAuthor(part
)
8509 self
._coAuthors
.remove( part
)
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
)
8522 if isPendingSubmitter
:
8523 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(ca
, False)
8525 def isCoAuthor( self
, part
):
8529 if self
._primaryAuthors
:
8531 except AttributeError:
8532 self
._primaryAuthors
= []
8533 return part
in self
._coAuthors
8535 def getCoAuthorList( self
):
8541 except AttributeError:
8542 self
._coAuthors
= []
8543 return self
._coAuthors
8545 def getAuthorById( self
, id ):
8551 except AttributeError:
8552 self
._authors
= OOBTree()
8553 return self
._authors
.get( id.strip(), None )
8555 def isAuthor( self
, part
):
8561 except AttributeError:
8562 self
._authors
= OOBTree()
8563 return self
._authors
.has_key( part
.getId() )
8565 def getSpeakerById( self
, id ):
8571 except AttributeError:
8573 for spk
in self
._speakers
:
8574 if spk
.getId() == id:
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
8586 except AttributeError:
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
8603 except AttributeError:
8608 except AttributeError:
8609 self
._authorGen
=Counter()
8610 self
._speakers
.append( part
)
8611 newId
= part
.getId()
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
):
8625 except AttributeError:
8627 if part
not in self
._speakers
:
8629 self
._speakers
.remove( part
)
8630 if self
.getConference() is not None:
8631 self
.getConference().unindexSpeaker(part
)
8632 if part
not in self
.getAuthorList():
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
)
8642 if isPendingSubmitter
:
8643 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(spk
, False)
8645 def isSpeaker( self
, part
):
8651 except AttributeError:
8653 return part
in self
._speakers
8655 def getSpeakerList ( self
):
8661 except AttributeError:
8663 return self
._speakers
8665 def getSpeakerText( self
):
8668 if self
.speakerText
:
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
):
8683 if self
.getOwner() != None:
8684 return self
.getOwner().canIPAccess(ip
)
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():
8703 if self
.getDomainList():
8705 if self
.getAccessProtectionLevel() == -1:
8708 return self
.getOwner().hasAnyProtection()
8712 def hasProtectedOwner( self
):
8713 if self
.getOwner() != None:
8714 return self
.getOwner().isProtected()
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
:
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
):
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'):
8749 ################################################################################################
8750 for sc
in self
.getSubContributionList():
8751 if sc
.canView( aw
):
8755 def isAllowedToAccess( self
, user
):
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
8766 if self
.__ac
.isHarvesterIP(aw
.getIP()):
8768 #####################################################
8770 if self
.canModify(aw
):
8773 if not self
.canIPAccess(aw
.getIP()) and not self
.isAllowedToAccess( aw
.getUser() ):
8775 if not self
.isProtected():
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() ]
8817 self
.notifyModification()
8818 elif mat
.getId().lower() == 'paper':
8820 self
.notifyModification()
8821 elif mat
.getId().lower() == 'slides':
8823 self
.notifyModification()
8824 elif mat
.getId().lower() == 'minutes':
8825 self
.removeMinutes()
8826 self
.notifyModification()
8827 elif mat
.getId().lower() == 'video':
8829 self
.notifyModification()
8830 elif mat
.getId().lower() == 'poster':
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
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
]
8863 def getMaterialList( self
):
8864 return self
.materials
.values()
8866 def getAllMaterialList( self
):
8867 l
= self
.getMaterialList()
8869 l
.append( self
.getPaper() )
8870 if self
.getSlides():
8871 l
.append( self
.getSlides() )
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()))
8881 def newSubContribution(self
):
8882 newSub
= SubContribution()
8883 self
.addSubContribution(newSub
)
8884 newSub
._notify
('created', self
)
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
:
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
:
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"))
8941 self
.paper
.setOwner( self
)
8942 self
.notifyModification()
8944 def removePaper( self
):
8945 if self
.paper
is None:
8948 self
.paper
.setOwner(None)
8950 self
.notifyModification()
8952 def recoverPaper(self
, p
):
8956 def getPaper( self
):
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:
8969 self
.slides
.delete()
8970 self
.slides
.setOwner( None )
8972 self
.notifyModification()
8974 def recoverSlides(self
, s
):
8978 def getSlides( self
):
8981 def setVideo( self
, newVideo
):
8982 if self
.getVideo() != None:
8983 raise MaKaCError( _("the video for this contribution has already been set"))
8985 self
.video
.setOwner( self
)
8986 self
.notifyModification()
8988 def removeVideo( self
):
8989 if self
.getVideo() is None:
8992 self
.video
.setOwner(None)
8994 self
.notifyModification()
8996 def recoverVideo(self
, v
):
9000 def getVideo( self
):
9004 except AttributeError:
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:
9018 self
.poster
.delete()
9019 self
.poster
.setOwner(None)
9021 self
.notifyModification()
9023 def recoverPoster(self
, p
):
9027 def getPoster( self
):
9031 except AttributeError:
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()
9050 def removeMinutes( self
):
9051 if self
.getMinutes() is None:
9053 self
.minutes
.delete()
9054 self
.minutes
.setOwner( None )
9056 self
.notifyModification()
9058 def recoverMinutes(self
, min):
9059 self
.removeMinutes() # To ensure that the current minutes are put in
9062 self
.minutes
.setOwner( self
)
9064 self
.notifyModification()
9067 def getMinutes( self
):
9072 except AttributeError, e
:
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:
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
)
9095 def getReviewing( self
):
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
):
9121 except AttributeError:
9125 def setTrack( self
, newTrack
):
9126 currentTrack
= self
.getTrack()
9127 if newTrack
== currentTrack
:
9130 currentTrack
.removeContribution( self
)
9131 self
._track
= newTrack
9133 self
._track
.addContribution( self
)
9135 def removeTrack(self
, track
):
9136 if track
== self
._track
:
9139 def setType( self
, newType
):
9140 self
._type
= newType
9142 def getType( self
):
9146 except AttributeError:
9150 def getModificationDate( self
):
9151 """Returns the date in which the contribution was last modified"""
9153 return self
._modificationDS
9155 if self
.getConference():
9156 self
._modificationDS
= self
.getConference().getModificationDate()
9158 self
._modificationDS
= nowutc()
9159 return self
._modificationDS
9161 def getCurrentStatus(self
):
9165 except AttributeError:
9166 self
._status
=ContribStatusNotSch(self
)
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
)
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
9208 if self
._submitters
:
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
)
9232 def revokeSubmissionEmail(self
, email
):
9233 if email
in self
.getSubmitterEmailList():
9234 self
.getSubmitterEmailList().remove(email
)
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
):
9244 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
9247 if i
.hasEmail(sb
.getEmail()):
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
)
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
):
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
):
9290 return self
._submittersEmail
9292 self
._submittersEmail
= []
9293 return self
._submittersEmail
9295 def canUserSubmit(self
,av
):
9296 """Tells whether a user can submit material for the current contribution
9300 self
._initSubmissionPrivileges
()
9301 for principal
in self
._submitters
:
9302 if principal
!= None and principal
.containsUser( av
):
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
)
9314 def getAccessController(self
):
9317 def getReportNumberHolder(self
):
9319 if self
._reportNumberHolder
:
9321 except AttributeError, e
:
9322 self
._reportNumberHolder
=ReportNumberHolder(self
)
9323 return self
._reportNumberHolder
9325 def setReportNumberHolder(self
, rnh
):
9326 self
._reportNumberHolder
=rnh
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()
9336 return maxDatetime()
9340 if self
.getSession() is not None:
9341 res
=self
.getSession().getColor()
9344 def getTextColor(self
):
9346 if self
.getSession() is not None:
9347 res
=self
.getSession().getTextColor()
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
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
)
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
9406 if self
._submitters
:
9408 except AttributeError:
9409 self
._submitters
=[]#create the attribute
9410 self
._grantSubmission
(self
.getAbstract().getSubmitter().getUser())
9413 """deletes a contribution and all of their subitems
9415 abs = self
.getAbstract()
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
)
9437 def clone(self
, contribution
, responsible
):
9438 cs
= ContribStatus(contribution
, responsible
)
9439 cs
.setDate(self
.getDate())
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
9457 def setDate(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())
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())
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())
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())
9520 class SubContribParticipation(Persistent
, Fossilizable
):
9522 fossilizes(ISubContribParticipationFossil
)
9524 def __init__( self
):
9525 self
._subContrib
= None
9527 self
._firstName
= ""
9530 self
._affiliation
= ""
9536 def getConference(self
):
9537 if self
._subContrib
is not None:
9538 return self
._subContrib
.getConference()
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
):
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()
9569 part
= SubContribParticipation()
9570 part
.setValues(self
.getValues())
9573 def setDataFromAvatar(self
,av
):
9574 # av is an Avatar object.
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.
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.
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():
9618 self
._subContrib
= subcontrib
9622 self
._subContrib
= None
9623 TrashCanManager().add(self
)
9626 TrashCanManager().remove(self
)
9628 @Updates ('MaKaC.conference.SubContribParticipation', 'id')
9629 def setId(self
, newId
):
9635 def getSubContrib( self
):
9636 return self
._subContrib
9638 def getContribution( self
):
9639 if self
._subContrib
is not None:
9640 return self
._subContrib
.getContribution()
9643 # def getLocator(self):
9644 # if self.getSubContrib() is None:
9646 # loc=self.getSubContrib().getLocator()
9647 # loc["authId"]=self.getId()
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
)
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
):
9669 if tmp
==self
._firstName
:
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
):
9685 if tmp
==self
._surName
:
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
):
9701 if tmp
==self
._email
:
9704 self
._email
=newMail
.strip()
9706 self
._notifyModification
()
9708 def getEmail( self
):
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
):
9735 @Updates ('MaKaC.conference.SubContribParticipation', 'title')
9736 def setTitle( self
, newTitle
):
9737 self
._title
= newTitle
.strip()
9738 self
._notifyModification
()
9740 def getTitle( self
):
9743 def setFax( self
, newFax
):
9744 self
._fax
= newFax
.strip()
9745 self
._notifyModification
()
9751 except AttributeError:
9755 def getFullName( self
):
9756 res
= self
.getFullNameNoTitle()
9757 if self
.getTitle() != "":
9758 res
= "%s %s"%( self
.getTitle(), 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() )
9767 res
= self
.getFirstName()
9770 def getAbrName(self
):
9771 res
= self
.getFamilyName()
9772 if self
.getFirstName() != "":
9775 res
= "%s%s."%(res
, self
.getFirstName()[0].upper())
9778 class SubContribution(CommonObjectBase
, Locatable
):
9782 fossilizes(ISubContributionFossil
, ISubContributionWithSpeakersFossil
)
9784 def __init__( self
, **subContData
):
9788 self
.description
= ""
9789 self
.__schEntry
= None
9790 self
.duration
= timedelta( minutes
=15 )
9792 self
.speakerText
= ""
9795 self
.__materialGenerator
= Counter() # Provides material unique
9796 # identifiers whithin the current
9797 self
.poster
= None # contribution
9803 self
._authorGen
= Counter()
9808 parentId
= self
.parent
.getId()
9809 if self
.getConference():
9810 grandpaId
= self
.getConference().getId()
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
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
9831 self
._fullyPublic
= True
9834 def updateFullyPublic( self
):
9835 self
.setFullyPublic()
9836 self
.getOwner().updateFullyPublic()
9838 def getAccessController(self
):
9839 return self
.getOwner().getAccessController()
9841 def getKeywords(self
):
9843 return self
._keywords
9848 def setKeywords(self
, keywords
):
9849 self
._keywords
= keywords
9851 def getLogInfo(self
):
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()
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()
9905 def notifyModification( self
):
9906 parent
= self
.getParent()
9908 parent
.setModificationDate()
9909 self
._notify
('infoChanged')
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()
9925 def setId( self
, newId
):
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() == "":
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:
9957 def getParent( self
):
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
):
9975 def getDuration( self
):
9976 return self
.duration
9978 def setDuration( self
, hours
, minutes
=0, dur
=0 ):
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:
10001 def newSpeaker( self
, spk
):
10004 self
.speakers
.append( spk
)
10006 if self
._authorGen
:
10008 except AttributeError:
10009 self
._authorGen
=Counter()
10010 newId
= spk
.getId()
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
:
10023 self
.speakers
.remove( spk
)
10024 if self
.getConference() is not None:
10025 self
.getConference().unindexSpeaker(spk
)
10027 self
.notifyModification()
10029 def recoverSpeaker(self
, spk
):
10030 self
.newSpeaker(spk
)
10033 def isSpeaker( self
, spk
):
10036 return spk
in self
._speakers
10038 def getSpeakerList ( self
):
10041 return self
.speakers
10043 def getSpeakerText( self
):
10046 if self
.speakerText
:
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()) )
10059 # There is no _order attribute in this class -
10060 # the methods below are either obsolate or the feature has not been implemented
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()
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
):
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.
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() ]
10144 self
.notifyModification()
10145 elif mat
.getId().lower() == 'paper':
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':
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
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
]
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()))
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:
10218 self
.paper
.delete()
10219 self
.paper
.setOwner(None)
10221 self
.notifyModification()
10223 def recoverPaper(self
, p
):
10227 def getPaper( self
):
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:
10240 self
.slides
.delete()
10241 self
.slides
.setOwner( None )
10243 self
.notifyModification()
10245 def recoverSlides(self
, s
):
10249 def getSlides( self
):
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:
10262 self
.video
.delete()
10263 self
.video
.setOwner(None)
10265 self
.notifyModification()
10267 def recoverVideo(self
, v
):
10271 def getVideo( self
):
10275 except AttributeError:
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:
10289 self
.poster
.delete()
10290 self
.poster
.setOwner(None)
10292 self
.notifyModification()
10294 def recoverPoster(self
, p
):
10298 def getPoster( self
):
10302 except AttributeError:
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:
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
10333 self
.minutes
.setOwner( self
)
10335 self
.notifyModification()
10336 return self
.minutes
10338 def getMinutes( self
):
10343 except AttributeError, e
:
10344 self
.minutes
= None
10345 return self
.minutes
10347 def getMasterSchedule( self
):
10348 return self
.getOwner().getSchedule()
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
)
10359 self
.removeSlides()
10361 self
.removePoster()
10362 self
.removeMinutes()
10363 TrashCanManager().add(self
)
10368 TrashCanManager().remove(self
)
10370 def getReportNumberHolder(self
):
10372 if self
._reportNumberHolder
:
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.
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
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()
10409 self
.description
= ""
10412 self
.__ac
= AccessController(self
)
10413 self
._mainResource
= None
10415 def isFullyPublic( self
):
10416 if hasattr(self
, "_fullyPublic"):
10417 return self
._fullyPublic
10419 self
.setFullyPublic()
10420 return self
._fullyPublic
10422 def setFullyPublic( self
):
10423 if self
.isProtected():
10424 self
._fullyPublic
= False
10425 self
._p
_changed
= 1
10427 for res
in self
.getResourceList():
10428 if res
.isProtected():
10429 self
._fullyPublic
= False
10430 self
._p
_changed
= 1
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:
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
):
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()
10466 newres
= r
.clone(mat
)
10467 mat
.addResource(newres
)
10469 mat
.setMainResource(self
.getMainResource())
10473 def notifyModification( self
):
10474 parent
= self
.getOwner()
10476 parent
.setModificationDate()
10477 self
._p
_changed
= 1
10479 def getLocator( self
):
10480 if self
.owner
== None:
10482 lconf
= self
.owner
.getLocator()
10483 lconf
["materialId"] = self
.getId()
10486 def setId( self
, newId
):
10487 self
.id = str(newId
).strip()
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
):
10503 def getCategory( self
):
10504 if isinstance(self
.getOwner(), Category
):
10505 return self
.getOwner()
10508 def getConference( self
):
10509 if type(self
.getOwner()) is Conference
:
10510 return self
.getOwner()
10511 if type(self
.getOwner()) is Category
:
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()
10524 def getContribution( self
):
10525 if self
.getSubContribution():
10526 return self
.getSubContribution().getContribution()
10527 if isinstance(self
.getOwner(), Contribution
):
10528 return self
.getOwner()
10531 def getSubContribution( self
):
10532 if isinstance(self
.getOwner(), SubContribution
):
10533 return self
.getOwner()
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
):
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
):
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
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":
10595 elif refereeJudgement
.getJudgement() == "Reject":
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
10603 else: #author has not submitted
10605 else: #material is not reviewable
10607 else: #material does not belong to a contribution
10610 def _getRepository( self
):
10611 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
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
10620 def hasFile( self
, name
):
10621 for f
in self
.getResourceList():
10622 if f
.getName() == name
:
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
)
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() ]
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
10658 self
.notifyModification()
10660 def getMainResource(self
):
10662 if self
._mainResource
:
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
)
10677 TrashCanManager().remove(self
)
10679 def canIPAccess( self
, ip
):
10680 if not self
.__ac
.canIPAccess( ip
):
10682 if self
.getOwner() != None:
10683 return self
.getOwner().canIPAccess(ip
)
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()
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
):
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
10774 if self
.__ac
.isHarvesterIP(aw
.getIP()):
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'):
10783 canUserAccess
= self
.isAllowedToAccess( aw
.getUser() )
10784 canIPAccess
= self
.canIPAccess( aw
.getIP() )
10785 if not self
.isProtected():
10786 return canUserAccess
or canIPAccess
10788 canKeyAccess
= self
.canKeyAccess(aw
)
10789 return canUserAccess
or canKeyAccess
10791 def canKeyAccess( self
, aw
):
10792 sess
= aw
.getSession()
10795 keys
= sess
.getVar("accessKeys")
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
)
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
):
10850 class Reviewing(Material
):
10852 def __init__( self
, materialData
= None ):
10853 Material
.__init
__( self
, materialData
)
10854 self
.id = "reviewing"
10856 def setId( self
, newId
):
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
)
10870 def setId( self
, newId
):
10875 class Slides(Material
):
10877 def __init__( self
, materialData
= None ):
10878 Material
.__init
__( self
, materialData
)
10881 def setId( self
, newId
):
10886 class Video(Material
):
10888 def __init__( self
, materialData
= None ):
10889 Material
.__init
__( self
, materialData
)
10892 def setId( self
, newId
):
10895 class Poster(Material
):
10897 def __init__( self
, materialData
= None ):
10898 Material
.__init
__( self
, materialData
)
10901 def setId( self
, newId
):
10904 class Minutes(Material
):
10906 def __init__( self
, materialData
= None ):
10907 Material
.__init
__( self
, materialData
)
10908 self
.id = "minutes"
10909 self
.title
= "Minutes"
10912 def clone ( self
, owner
):
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()
10928 if r
.getId()=="minutes":
10929 mat
.setText(self
.getText())
10930 elif isinstance(r
,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
)
10946 raise Exception( _("Unexpected object type in Resource List : ")+str(type(r
)))
10948 mat
.setMainResource(self
.getMainResource())
10952 def setId( self
, newId
):
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")
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 ):
10976 self
._setFile
(forcedFileId
= forcedFileId
)
10977 self
.file.replaceContent( text
)
10978 self
.getOwner().notifyModification()
10980 def getText( self
):
10983 return self
.file.readBin()
10985 def getResourceList( self
):
10986 res
= Material
.getResourceList( self
)
10988 res
.insert(0, self
.file)
10991 def getResourceById( self
, id ):
10992 if id.strip() == "minutes":
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":
11001 self
.notifyModification()
11003 def recoverResource(self
, recRes
):
11004 if recRes
.getId() == "minutes":
11005 recRes
.setOwner(self
)
11008 self
.notifyModification()
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.
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
11026 description - (string) detailed and varied information about the
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"
11037 self
.description
= ""
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())
11046 res
.notifyModification()
11047 res
.setId(self
.getId())
11050 res
.setProtection(self
.getAccessController()._getAccessProtection
())
11051 #res.__ac = self.getAccessController()
11055 def notifyModification( self
):
11056 parent
= self
.getOwner()
11058 parent
.setModificationDate()
11059 self
._p
_changed
= 1
11061 def getLocator( self
):
11062 if self
._owner
== None:
11064 lconf
= self
._owner
.getLocator()
11065 lconf
["resId"] = self
.getId()
11068 def setId( self
, newId
):
11069 self
.id = newId
.strip()
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
):
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()
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
):
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
):
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"""
11139 def delete( self
):
11140 if self
._owner
!= None:
11141 self
._owner
.removeResource( self
)
11143 TrashCanManager().add(self
)
11146 TrashCanManager().remove(self
)
11148 def canIPAccess( self
, ip
):
11149 if not self
.__ac
.canIPAccess( ip
):
11151 if self
.getOwner() != None:
11152 return self
.getOwner().canIPAccess(ip
)
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()
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
11198 if self
.__ac
.isHarvesterIP(aw
.getIP()):
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'):
11207 if not self
.canIPAccess(aw
.getIP()) and not self
.canUserModify(aw
.getUser()) and not self
.isAllowedToAccess( aw
.getUser() ):
11209 if not self
.isProtected():
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
):
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
):
11256 def getAccessKey(self
):
11257 if self
.getOwner() is not None:
11258 return self
.getOwner().getAccessKey()
11261 def canKeyAccess( self
, aw
):
11262 sess
= aw
.getSession()
11265 accessKey
= self
.getAccessKey()
11266 keys
= sess
.getVar("accessKeys")
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()):
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
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.
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
)
11305 def clone( self
, conf
):
11306 link
= Resource
.clone(self
, conf
)
11307 link
.setURL(self
.getURL())
11310 @Updates ('MaKaC.conference.Link', 'url')
11311 def setURL( self
, newURL
):
11312 self
.url
= newURL
.strip()
11313 self
.notifyModification()
11315 def getURL( self
):
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.
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
)
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())
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
11372 if newFileName
.count("/"):
11374 newFileName
= newFileName
.split("/")[-1]
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
)
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"))
11440 raise Exception( _("Destination repository not set"))
11441 if self
.filePath
== "":
11442 return _("Nothing to archive")
11443 repository
.storeFile( self
, forcedFileId
= forcedFileId
)
11445 self
.notifyModification()
11447 def unArchive(self
):
11449 self
.__repository
= None
11450 self
.__archivedId
= ""
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() )
11465 self
.__repository
.retireFile( self
)
11466 except AttributeError, e
:
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
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.
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:
11514 if not self
._idx
.has_key( av
.getId() ):
11517 l
= self
._idx
[av
.getId()]
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:
11527 l
= self
._idx
.get( av
.getId(), [] )
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"
11543 self
.description
= ""
11544 self
.subTracks
= {}
11545 self
.__SubTrackGenerator
= Counter()
11546 self
._abstracts
= OOBTree()
11547 self
._coordinators
= []
11548 self
._contributions
= OOBTree()
11551 def clone(self
, conference
):
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())
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
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
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
)
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()
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:
11626 lconf
= self
.conference
.getLocator()
11627 lconf
["trackId"] = self
.getId()
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
)
11645 def setTitle( self
, newTitle
):
11646 self
.title
= newTitle
11647 self
.notifyModification()
11649 def getTitle( self
):
11652 def setDescription(self
, newDescription
):
11653 self
.description
= newDescription
11654 self
.notifyModification()
11656 def getDescription(self
):
11657 return self
.description
11663 except AttributeError:
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():
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 )
11694 self
.notifyModification()
11696 def recoverSubTrack(self
, subTrack
):
11697 self
.addSubTrack(subTrack
)
11700 def newSubTrack( self
):
11702 self
.addSubTrack( st
)
11705 def getSubTrackById( self
, id ):
11706 if self
.subTracks
.has_key( id ):
11707 return self
.subTracks
[ id ]
11710 def getSubTrackList( self
):
11711 return self
.subTracks
.values()
11713 def getAbstractList( self
):
11717 if self
._abstracts
:
11719 except AttributeError:
11720 self
._abstracts
= OOBTree()
11721 return self
._abstracts
.values()
11723 def getAbstractById( self
, id ):
11725 if self
._abstracts
:
11727 except AttributeError:
11728 self
._abstracts
= OOBTree()
11729 return self
._abstracts
[ str(id).strip() ]
11731 def hasAbstract( self
, abstract
):
11735 if self
._abstracts
:
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
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
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.
11765 av -- (MaKaC.user.Avatar) the user to which
11766 coordination privileges must be granted.
11770 if self
._coordinators
:
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.
11786 av -- (MaKaC.user.Avatar) user for which coordination privileges
11790 if self
._coordinators
:
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.
11806 av -- (MaKaC.user.Avatar) user to be checke
11808 Return value: (boolean)
11811 if self
._coordinators
:
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)
11824 if self
._coordinators
:
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.
11837 aw -- (MaKaC.accessControl.AccessWrapper) User access
11838 information for which the coordination privileges must be
11841 Return value: (boolean)
11843 return self
.isCoordinator( aw
.getUser() ) or self
.canModify( aw
)
11845 def addContribution( self
, newContrib
):
11849 if self
._contributions
:
11851 except AttributeError:
11852 self
._contributions
= OOBTree()
11853 if self
._contributions
.has_key( newContrib
.getId() ):
11855 self
._contributions
[ newContrib
.getId() ] = newContrib
11856 newContrib
.setTrack( self
)
11858 def getModifKey( self
):
11859 return self
.getConference().getModifKey()
11861 def removeContribution( self
, contrib
):
11865 if self
._contributions
:
11867 except AttributeError:
11868 self
._contributions
= OOBTree()
11869 if not self
._contributions
.has_key( contrib
.getId() ):
11871 del self
._contributions
[ contrib
.getId() ]
11872 contrib
.setTrack( None )
11874 def hasContribution( self
, contrib
):
11876 if self
._contributions
:
11878 except AttributeError:
11879 self
._contributions
= OOBTree()
11880 return self
._contributions
.has_key( contrib
.getId() )
11882 def getContributionList(self
):
11884 if self
._contributions
:
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
):
11898 self
.id = "not assigned"
11900 self
.description
= ""
11904 sub
.setDescription(self
.getDescription())
11905 sub
.setTitle(self
.getTitle())
11911 TrashCanManager().add(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()
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:
11934 lconf
= self
.track
.getLocator()
11935 lconf
["subTrackId"] = self
.getId()
11938 def setTrack(self
, track
):
11943 def getTrack( self
):
11946 def getOwner( self
):
11947 return self
.getTrack()
11949 def setId( self
, newId
):
11950 self
.id = str(newId
)
11955 def setTitle( self
, newTitle
):
11956 self
.title
= newTitle
11957 self
.notifyModification()
11959 def getTitle( self
):
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
):
11975 self
._description
= description
11976 self
._conference
= conference
11981 def setId(self
, id):
11987 def setName(self
, 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:
12005 lconf
= self
._conference
.getLocator()
12006 lconf
["contribTypeId"] = self
.getId()
12009 def canModify(self
, aw
):
12010 return self
._conference
.canModify(aw
)
12013 self
.setConference(None)
12014 TrashCanManager().add(self
)
12017 TrashCanManager().remove(self
)
12019 def clone(self
, conference
):
12020 type = ContributionType(self
.getName(), self
.getDescription(),conference
)
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
):
12036 self
._showIds
= False
12037 self
._sortBy
= "number"
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
12062 def getSortByTypes():
12063 return BOAConfig
.sortByTypes