1 # -*- coding: utf-8 -*-
4 ## This file is part of Indico.
5 ## Copyright (C) 2002 - 2013 European Organization for Nuclear Research (CERN).
7 ## 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 3 of the
10 ## License, or (at your option) any later version.
12 ## 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 Indico;if not, see <http://www.gnu.org/licenses/>.
21 from MaKaC
.common
.timezoneUtils
import datetimeToUnixTimeInt
22 from MaKaC
.plugins
import PluginsHolder
, Observable
23 from MaKaC
.common
.utils
import formatDateTime
24 from MaKaC
.fossils
.subcontribution
import ISubContribParticipationFossil
,\
25 ISubContribParticipationFullFossil
, 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 MaKaC
.rb_location
import CrossLocationQueries
, CrossLocationDB
43 from indico
.util
.i18n
import L_
50 from datetime
import datetime
, timedelta
, time
52 from MaKaC
.contributionReviewing
import ReviewManager
53 from MaKaC
.paperReviewing
import ConferencePaperReview
as ConferencePaperReview
54 from MaKaC
.abstractReviewing
import ConferenceAbstractReview
as ConferenceAbstractReview
56 from pytz
import timezone
57 from pytz
import all_timezones
59 from persistent
import Persistent
60 from BTrees
.OOBTree
import OOBTree
, OOTreeSet
, OOSet
61 from BTrees
.OIBTree
import OIBTree
,OISet
,union
63 import MaKaC
.common
.indexes
as indexes
64 from MaKaC
.common
.timezoneUtils
import nowutc
, maxDatetime
65 import MaKaC
.fileRepository
as fileRepository
66 from MaKaC
.schedule
import ConferenceSchedule
, SessionSchedule
,SlotSchedule
,\
67 PosterSlotSchedule
, SlotSchTypeFactory
, ContribSchEntry
, \
68 LinkedTimeSchEntry
, BreakTimeSchEntry
69 import MaKaC
.review
as review
70 from MaKaC
.common
import Config
, DBMgr
, utils
71 from MaKaC
.common
.Counter
import Counter
72 from MaKaC
.common
.ObjectHolders
import ObjectHolder
73 from MaKaC
.common
.Locators
import Locator
74 from MaKaC
.accessControl
import AccessController
, AdminList
75 from MaKaC
.errors
import MaKaCError
, TimingError
, ParentTimingError
, EntryTimingError
, NoReportError
76 from MaKaC
import registration
,epayment
77 from MaKaC
.evaluation
import Evaluation
78 from MaKaC
.trashCan
import TrashCanManager
79 from MaKaC
.user
import AvatarHolder
80 from MaKaC
.common
import pendingQueues
81 from MaKaC
.common
.info
import HelperMaKaCInfo
82 from MaKaC
.participant
import Participation
83 from MaKaC
.common
.log
import LogHandler
84 import MaKaC
.common
.info
as info
85 from MaKaC
.badge
import BadgeTemplateManager
86 from MaKaC
.poster
import PosterTemplateManager
87 from MaKaC
.common
.cache
import CategoryCache
, EventCache
88 from MaKaC
.common
import mail
89 from MaKaC
.common
.utils
import getHierarchicalId
90 from MaKaC
.i18n
import _
91 from MaKaC
.common
.PickleJar
import Updates
92 from MaKaC
.common
.PickleJar
import if_else
94 from MaKaC
.webinterface
import urlHandlers
96 from MaKaC
.common
.logger
import Logger
97 from MaKaC
.common
.contextManager
import ContextManager
98 from MaKaC
.webinterface
.common
.tools
import escape_html
101 from indico
.modules
.scheduler
import Client
, tasks
102 from indico
.util
.date_time
import utc_timestamp
103 from indico
.core
.index
import IIndexableByStartDateTime
, IUniqueIdProvider
, Catalog
104 from indico
.core
.db
.event
import SupportInfo
105 from MaKaC
.schedule
import ScheduleToJson
107 from indico
.util
.redis
import write_client
as redis_write_client
108 import indico
.util
.redis
.avatar_links
as avatar_links
110 class CoreObject(Persistent
):
112 CoreObjects are Persistent objects that are employed by Indico's core
115 zope
.interface
.implements(IUniqueIdProvider
,
116 IIndexableByStartDateTime
)
118 def setModificationDate(self
, date
= None):
120 Method called to notify the current object has been modified.
124 self
._modificationDS
= date
126 def __conform__(self
, proto
):
128 if proto
== IIndexableByStartDateTime
:
129 return utc_timestamp(self
.getStartDate())
136 Inherited by objects that imply a physical location:
144 def getLocationParent(self
):
146 Returns the object the location info should be inherited from
149 raise Exception("Unimplemented method")
151 def getLocation(self
):
152 if self
.getOwnLocation():
153 return self
.getOwnLocation()
154 return self
.getInheritedLocation()
156 def getOwnLocation(self
):
157 if len(self
.places
) > 0:
158 return self
.places
[0]
161 def getInheritedLocation(self
):
162 return self
.getLocationParent().getLocation()
164 def getOwnRoom(self
):
165 if len(self
.rooms
) > 0:
170 if self
.getOwnRoom():
171 return self
.getOwnRoom()
172 return self
.getInheritedRoom()
174 def getInheritedRoom(self
):
175 return self
.getLocationParent().getRoom()
177 def setLocation(self
, newLocation
):
178 oldLocation
= self
.getOwnLocation()
179 if newLocation
== None:
180 if len(self
.places
) > 0:
182 elif len(self
.places
) > 0:
183 self
.places
[0] = newLocation
185 self
.places
.append( newLocation
)
186 self
.notifyModification()
188 def setRoom(self
, newRoom
):
189 oldRoom
= self
.getOwnRoom()
191 if len(self
.rooms
) > 0:
193 elif len(self
.rooms
) > 0:
194 self
.rooms
[0] = newRoom
196 self
.rooms
.append( newRoom
)
197 self
.notifyModification()
200 class CommonObjectBase(CoreObject
, Observable
, Fossilizable
):
202 This class is for holding commonly used methods that are used by several classes.
203 It is inherited by the following classes:
213 def getRecursiveManagerList(self
):
216 # Get the AccessProtectionLevel for this
217 apl
= self
.getAccessProtectionLevel()
222 for av
in self
.getManagerList():
224 for av
in self
.getOwner().getRecursiveManagerList():
227 for av
in self
.getManagerList():
231 for av
in self
.getOwner().getRecursiveManagerList():
236 def getRecursiveAllowedToAccessList(self
, onlyManagers
=False):
237 """Returns a set of Avatar resp. CERNGroup objects for those people resp.
238 e-groups allowed to access this object as well as all parent objects.
241 # Initialize set of avatars/groups: this will hold those
242 # people/groups explicitly
243 # allowed to access this object
246 # Get the AccessProtectionLevel for this
247 apl
= self
.getAccessProtectionLevel()
249 # If this object is "absolutely public", then return an empty set
253 # If this object is protected "all by itself", then get the list of
254 # people/groups allowed to access it, plus managers of owner(s)
256 al
= self
.getAllowedToAccessList() + self
.getManagerList() + \
257 self
.getOwner().getRecursiveManagerList()
262 # If access settings are inherited (and PRIVATE) from its owners, look at those.
263 elif apl
== 0 and self
.isProtected():
264 # If event is protected, then get list of people/groups allowed
265 # to access, and add that to the set of avatars.
266 al
= self
.getAllowedToAccessList() + self
.getManagerList()
271 # Add list of avatars/groups allowed to access parents objects.
272 owner
= self
.getOwner()
273 if owner
is not None:
274 owner_al
= owner
.getRecursiveAllowedToAccessList(onlyManagers
=True)
275 if owner_al
is not None:
279 # return set containing whatever avatars/groups we may have collected
283 class CategoryManager( ObjectHolder
):
284 idxName
= "categories"
285 counterName
= "CATEGORY"
287 def add(self
, category
):
288 ObjectHolder
.add(self
, category
)
289 # Add category to the name index
290 nameIdx
= indexes
.IndexesHolder().getIndex('categoryName')
291 nameIdx
.index(category
.getId(), category
.getTitle().decode('utf-8'))
293 def remove(self
, category
):
294 ObjectHolder
.remove(self
, category
)
295 # remove category from the name index
296 nameIdx
= indexes
.IndexesHolder().getIndex('categoryName')
297 nameIdx
.unindex(category
.getId())
298 Catalog
.getIdx('categ_conf_sd').remove_category(category
.getId())
302 returns a new id for the category
303 the id must not already exist in the collection
305 id = ObjectHolder
._newId
( self
)
306 while self
.hasKey(id):
307 id = ObjectHolder
._newId
( self
)
311 root
= DBMgr
.getInstance().getDBConnection().root()
312 if not root
.has_key("rootCategory"):
316 root
["rootCategory"] = r
317 return root
["rootCategory"]
319 def getDefaultConference( self
):
320 dconf
= HelperMaKaCInfo
.getMaKaCInfoInstance().getDefaultConference()
322 return HelperMaKaCInfo
.getMaKaCInfoInstance().setDefaultConference(DefaultConference())
328 class Category(CommonObjectBase
):
330 fossilizes(ICategoryFossil
)
332 def __init__( self
):
336 self
.description
= ""
337 self
.subcategories
= {}
339 self
.conferences
= OOTreeSet()
340 self
._numConferences
= 0
342 self
._defaultStyle
= { "simple_event":"","meeting":"" }
344 self
.__ac
= AccessController(self
)
345 self
.__confCreationRestricted
= 1
346 self
.__confCreators
= []
347 self
._visibility
= 999
348 self
._statistics
= {"events":None,"contributions":None,"resources":None,\
352 #self._materials = {}
354 self
._tasksAllowed
= False
356 self
._taskIdGenerator
= 0
357 self
._tasksPublic
= True
358 self
._tasksCommentPublic
= True
359 self
._tasksManagers
= []
360 self
._tasksCommentators
= []
361 self
._taskAccessList
= []
363 self
.__materialGenerator
= Counter()
364 self
._notifyCreationList
= ""
366 def __cmp__(self
, other
):
367 if type(self
) is not type(other
):
368 # This is actually dangerous and the ZODB manual says not to do this
369 # because it relies on memory order. However, this branch should never
370 # be taken anyway since we do not store different types in the same set
371 # or use them as keys.
372 return cmp(hash(self
), hash(other
))
373 return cmp(self
.getId(), other
.getId())
376 return "<Category %s@%s>" % (self
.getId(), hex(id(self
)))
378 def getAccessController(self
):
381 def updateNonInheritingChildren(self
, elem
, delete
=False):
384 def getNotifyCreationList( self
):
385 """ self._notifyCreationList is a string containing the list of
386 email addresses to send an email to when a new event is created"""
388 return self
._notifyCreationList
390 self
._notifyCreationList
= ""
391 return self
._notifyCreationList
393 def setNotifyCreationList( self
, value
):
394 self
._notifyCreationList
= value
396 def getUniqueId( self
):
397 return "cat%s" % self
.getId()
399 def setPaper( self
, newPaper
):
400 if self
.getPaper() != None:
401 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
403 self
.paper
.setOwner( self
)
404 self
.notifyModification()
406 def cleanCache( self
):
407 """ delete cache files of this category and its fathers
408 usually used when an object in the category has changed """
409 minfo
= info
.HelperMaKaCInfo
.getMaKaCInfoInstance()
410 if minfo
.isCacheActive():
411 for id in self
.getCategoryPath():
412 cache
= CategoryCache({"categId":id})
415 def clearCache( self
):
416 """ delete cache file of this category. usually used for
418 cache
= CategoryCache({"categId":self
.getId()})
421 def clearConferenceCaches( self
):
422 """ delete cache files of all conferences in the category
423 usually used for admin purposes """
424 for conf
in self
.getConferenceList():
427 def removePaper( self
):
428 if self
.paper
is None:
431 self
.paper
.setOwner(None)
433 self
.notifyModification()
435 def recoverPaper(self
, p
):
439 def getPaper( self
):
443 except AttributeError:
447 def setSlides( self
, newSlides
):
448 if self
.getSlides() != None:
449 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
450 self
.slides
=newSlides
451 self
.slides
.setOwner( self
)
452 self
.notifyModification()
454 def removeSlides( self
):
455 if self
.slides
is None:
458 self
.slides
.setOwner( None )
460 self
.notifyModification()
462 def recoverSlides(self
, s
):
466 def getSlides( self
):
470 except AttributeError:
474 def setVideo( self
, newVideo
):
475 if self
.getVideo() != None:
476 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
478 self
.video
.setOwner( self
)
479 self
.notifyModification()
481 def removeVideo( self
):
482 if self
.getVideo() is None:
485 self
.video
.setOwner(None)
487 self
.notifyModification()
489 def recoverVideo(self
, v
):
493 def getVideo( self
):
497 except AttributeError:
501 def setPoster( self
, newPoster
):
502 if self
.getPoster() != None:
503 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
504 self
.poster
=newPoster
505 self
.poster
.setOwner( self
)
506 self
.notifyModification()
508 def removePoster( self
):
509 if self
.getPoster() is None:
512 self
.poster
.setOwner(None)
514 self
.notifyModification()
516 def recoverPoster(self
, p
):
520 def getPoster( self
):
524 except AttributeError:
528 def setMinutes( self
, newMinutes
):
529 if self
.getMinutes() != None:
530 raise MaKaCError( _("The Minutes for this conference has already been set"))
531 self
.minutes
=newMinutes
532 self
.minutes
.setOwner( self
)
533 self
.notifyModification()
535 def createMinutes( self
):
536 if self
.getMinutes() != None:
537 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
538 self
.minutes
= Minutes()
539 self
.minutes
.setOwner( self
)
540 self
.notifyModification()
543 def removeMinutes( self
):
544 if self
.getMinutes() is None:
546 self
.minutes
.delete()
547 self
.minutes
.setOwner( None )
549 self
.notifyModification()
551 def recoverMinutes(self
, min):
552 self
.removeMinutes() # To ensure that the current minutes are put in
555 self
.minutes
.setOwner( self
)
557 self
.notifyModification()
560 def getMinutes( self
):
565 except AttributeError, e
:
569 def addMaterial( self
, newMat
):
571 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
573 self
.__materialGenerator
= Counter()
574 newMat
.setId(self
.__materialGenerator
.newCount() )
575 newMat
.setOwner( self
)
576 self
.materials
[ newMat
.getId() ] = newMat
577 self
.notifyModification()
579 def removeMaterial( self
, mat
):
580 if mat
.getId() in self
.materials
.keys():
582 self
.materials
[mat
.getId()].setOwner(None)
583 del self
.materials
[ mat
.getId() ]
584 self
.notifyModification()
585 return "done: %s"%mat
.getId()
586 elif mat
.getId().lower() == 'minutes':
588 return "done: %s"%mat
.getId()
589 elif mat
.getId().lower() == 'paper':
591 return "done: %s"%mat
.getId()
592 elif mat
.getId().lower() == 'slides':
594 return "done: %s"%mat
.getId()
595 elif mat
.getId().lower() == 'video':
597 return "done: %s"%mat
.getId()
598 elif mat
.getId().lower() == 'poster':
600 return "done: %s"%mat
.getId()
601 return "not done: %s"%mat
.getId()
603 def recoverMaterial(self
, recMat
):
604 # Id must already be set in recMat.
605 recMat
.setOwner( self
)
606 self
.materials
[ recMat
.getId() ] = recMat
608 self
.notifyModification()
610 def getMaterialRegistry(self
):
612 Return the correct material registry for this type
614 from MaKaC
.webinterface
.materialFactories
import CategoryMFRegistry
615 return CategoryMFRegistry
617 def getMaterialById( self
, matId
):
618 if matId
.lower() == 'paper':
619 return self
.getPaper()
620 elif matId
.lower() == 'slides':
621 return self
.getSlides()
622 elif matId
.lower() == 'video':
623 return self
.getVideo()
624 elif matId
.lower() == 'poster':
625 return self
.getPoster()
626 elif matId
.lower() == 'minutes':
627 return self
.getMinutes()
628 elif self
.materials
.has_key(matId
):
629 return self
.materials
[ matId
]
632 def getMaterialList( self
):
634 return self
.materials
.values()
637 return self
.materials
.values()
639 def getAllMaterialList(self
):
640 l
= self
.getMaterialList()
642 l
.append( self
.getPaper() )
644 l
.append( self
.getSlides() )
646 l
.append( self
.getVideo() )
648 l
.append( self
.getPoster() )
649 if self
.getMinutes():
650 l
.append( self
.getMinutes() )
653 def getTaskList(self
):
655 return self
._tasks
.values()
658 return self
._tasks
.values()
670 def getTask(self
, taskId
):
671 return self
.getTasks().get(taskId
,None)
673 def _getTasksAllowed(self
):
675 return self
._tasksAllowed
677 self
._tasksAllowed
= False
678 return self
._tasksAllowed
680 def tasksAllowed(self
):
681 if self
.hasSubcategories():
683 return self
._getTasksAllowed
()
685 def setTasksAllowed(self
):
686 if self
.hasSubcategories() :
688 self
._getTasksAllowed
()
689 self
._tasksAllowed
= True
690 self
.notifyModification()
693 def setTasksForbidden(self
):
694 if len(self
.getTaskList()) > 0 :
696 self
._getTasksAllowed
()
697 self
._tasksAllowed
= False
698 self
.notifyModification()
701 def _getNewTaskId(self
):
703 if self
._taskIdGenerator
:
706 self
._taskIdGenerator
= 0
707 self
._taskIdGenerator
= self
._taskIdGenerator
+ 1
708 return self
._taskIdGenerator
710 def newTask(self
, user
):
713 newTask
= task
.Task(self
, self
._getNewTaskId
(), user
)
714 self
.getTasks()["%s"%newTask
.getId()] = newTask
715 self
.notifyModification()
718 def tasksPublic(self
):
720 return self
._tasksPublic
722 self
._tasksPublic
= True
723 return self
._tasksPublic
725 def setTasksPublic(self
):
727 self
._tasksPublic
= True
729 def setTasksPrivate(self
):
731 self
._tasksPublic
= False
733 def tasksCommentPublic(self
):
735 return self
._tasksCommentPublic
737 self
._tasksCommentPublic
= True
738 return self
._tasksCommentPublic
740 def setTasksCommentPublic(self
):
741 self
.tasksCommentPublic()
742 self
._tasksCommentPublic
= True
744 def setTasksCommentPrivate(self
):
745 self
.tasksCommentPublic()
746 self
._tasksCommentPublic
= False
748 def getTasksManagerList(self
):
750 return self
._tasksManagers
752 self
._tasksManagers
= []
754 return self
._tasksManagers
756 def getTasksManager(self
, index
):
757 length
= len(self
.getTasksManagerList())
758 if index
< 0 or index
>= length
:
760 return self
._tasksManagers
[index
]
762 def addTasksManager(self
,user
):
765 self
.getTasksManagerList().append(user
)
769 def removeTasksManager(self
, index
):
770 length
= len(self
.getTasksManagerList())
771 if index
< 0 or index
>= length
:
773 del self
.getTasksManagerList()[index
]
777 def getTasksCommentatorList(self
):
779 return self
._tasksCommentators
781 self
._tasksCommentators
= []
783 return self
._tasksCommentators
785 def getTasksCommentator(self
, index
):
786 length
= len(self
.getTasksCommentatorList())
787 if index
< 0 or index
>= length
:
789 return self
._tasksCommentators
[index
]
791 def addTasksCommentator(self
,user
):
794 self
.getTasksCommentatorList().append(user
)
798 def removeTasksCommentator(self
, index
):
799 length
= len(self
.getTasksCommentatorList())
800 if index
< 0 or index
>= length
:
802 del self
._tasksCommentators
[index
]
807 def getTasksAccessList(self
):
809 return self
._tasksAccessList
811 self
._tasksAccessList
= []
813 return self
._tasksAccessList
815 def getTasksAccessPerson(self
, index
):
816 length
= len(self
.getTasksAccessList())
817 if index
< 0 or index
>= length
:
819 return self
._tasksAccessList
[index
]
821 def addTasksAccessPerson(self
,user
):
824 self
.getTasksAccessList().append(user
)
828 def removeTasksAccessPerson(self
, index
):
829 length
= len(self
.getTasksAccessList())
830 if index
< 0 or index
>= length
:
832 del self
.getTasksAccessList()[index
]
836 def hasSubcategories(self
):
837 return len(self
.subcategories
.values()) > 0
839 def getVisibility ( self
):
841 Returns category visibility, considering that it can be
842 restricted by parent categories
844 owner
= self
.getOwner()
845 visibility
= int(self
._visibility
)
847 # visibility can be restricted by parent categories
849 return max(0, min(visibility
, owner
.getVisibility() + 1))
853 def setVisibility( self
, visibility
=999 ):
854 self
._visibility
= int(visibility
)
857 def _reindex( self
):
858 catIdx
= indexes
.IndexesHolder().getIndex('category')
859 catIdx
.reindexCateg(self
)
860 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
861 catDateIdx
.reindexCateg(self
)
862 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
863 catDateAllIdx
.reindexCateg(self
)
867 return self
.owner
== None
869 def getDefaultStyle( self
, type ):
871 return self
._defaultStyle
[type]
875 def setDefaultStyle( self
, type, style
, subcatsStyle
=False ):
877 self
._defaultStyle
[type] = style
879 self
._defaultStyle
= { "simple_event":"","meeting":"" }
880 self
._defaultStyle
[type] = style
881 self
.notifyModification()
882 #raise str(subcatsStyle)
885 categ
=self
.getSubCategoryList()
888 cat
.setDefaultStyle(type, style
, subcatsStyle
)
890 ##################################
891 # Fermi timezone awareness #
892 ##################################
893 def getTimezone(self
):
895 if self
._timezone
not in all_timezones
:
896 self
.setTimezone('UTC')
897 return self
._timezone
899 self
.setTimezone('UTC')
902 def setTimezone(self
,tz
):
906 def changeConfTimezones(self
, tz
):
907 for conference
in self
.getConferenceList():
908 conference
.moveToTimezone(tz
)
910 ##################################
911 # Fermi timezone awareness(end) #
912 ##################################
914 def getOrder( self
):
921 def setOrder( self
, order
):
927 def setId( self
, newId
):
928 self
.id = str( newId
.strip() )
930 def getLocator( self
):
931 """Gives back (Locator) a globaly unique identification encapsulated
932 in a Locator object for the category instance """
934 d
["categId"] = self
.getId()
937 def getCategory(self
):
940 def getOwner( self
):
943 def setOwner( self
, newOwner
):
944 if self
.getOwner() != None and newOwner
!= None and self
.getOwner() != newOwner
:
945 self
.move( newOwner
)
947 self
.owner
= newOwner
949 def getCategoryPath(self
):
951 return [self
.getId()]
953 l
= self
.getOwner().getCategoryPath()
954 l
.append(self
.getId())
957 def getCategoryPathTitles(self
):
962 breadcrumbs
.insert(0, cat
.getTitle())
966 def delete( self
, deleteConferences
=0 ):
967 """removes completely a category (and all its sub-items) from the
970 oldOwner
= self
.getOwner()
973 raise MaKaCError( _("Root category cannot be deleted"), _("Category"))
974 if not deleteConferences
:
975 if self
.getNumConferences()>0:
976 raise MaKaCError( _("This category still contains some conferences, please remove them first"), _("Category"))
978 for subcateg
in self
.getSubCategoryList():
979 subcateg
.delete( deleteConferences
)
980 for conference
in self
.getConferenceList():
981 self
.removeConference( conference
, delete
= True )
982 self
.getOwner()._removeSubCategory
( self
)
983 CategoryManager().remove(self
)
984 for prin
in self
.__ac
.getAccessList():
985 if isinstance(prin
, MaKaC
.user
.Avatar
):
986 prin
.unlinkTo(self
, "access")
987 for prin
in self
.__ac
.getModifierList():
988 if isinstance(prin
, MaKaC
.user
.Avatar
):
989 prin
.unlinkTo(self
, "manager")
990 TrashCanManager().add(self
)
992 self
._notify
('deleted', oldOwner
)
996 def move( self
, newOwner
):
997 oldOwner
= self
.getOwner()
998 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
999 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
1001 catDateIdx
.unindexCateg(self
)
1002 catDateAllIdx
.unindexCateg(self
)
1004 self
.getOwner()._removeSubCategory
( self
)
1005 newOwner
._addSubCategory
( self
)
1007 catDateIdx
.indexCateg(self
)
1008 catDateAllIdx
.indexCateg(self
)
1010 self
._notify
('moved', oldOwner
, newOwner
)
1012 def getName( self
):
1015 def setName( self
, newName
):
1017 self
.name
= newName
.strip()
1019 # Reindex when name changes
1020 nameIdx
= indexes
.IndexesHolder().getIndex('categoryName')
1021 nameIdx
.unindex(self
.getId())
1022 nameIdx
.index(self
.getId(), self
.getTitle().decode('utf-8'))
1024 self
._notify
('categoryTitleChanged', oldName
, newName
)
1028 def getDescription( self
):
1029 return self
.description
1031 def setDescription( self
, newDesc
):
1032 self
.description
= newDesc
.strip()
1035 def moveConference(self
, conf
, toCateg
):
1037 Moves a conference from this category to another one
1039 self
.removeConference( conf
)
1040 toCateg
._addConference
( conf
)
1041 conf
._notify
('moved', self
, toCateg
)
1043 def _addSubCategory( self
, newSc
):
1044 #categories can only contain either conferences either other categories
1045 # but can never contain both. For the moment an exception is raised
1046 # but this could be replaced by the following policy: if a
1047 # sub-category is to be added to a category already containing
1048 # conferences then the conferes are moved into the new sub-category
1049 # and it is added to target category.
1050 #first, check that the category is registered if not raise an exception
1051 if len(self
.conferences
)>0:
1052 for conf
in self
.getConferenceList():
1053 self
.moveConference(conf
, newSc
)
1055 if len(self
.conferences
)>0:
1056 raise MaKaCError( _("Cannot add subcategory: the current category already contains events"), _("Category"))
1057 newSc
.setOwner( self
)
1058 self
.subcategories
[ newSc
.getId() ] = newSc
1059 self
._incNumConfs
(newSc
.getNumConferences())
1062 def _removeSubCategory( self
, sc
):
1063 """if the given subcategory belongs to the current category it removes
1064 it from the subcategories list (don't use this method, use delete
1067 if sc
in self
.getSubCategoryList():
1068 self
._decNumConfs
(sc
.getNumConferences())
1069 del self
.subcategories
[ sc
.getId() ]
1073 def newSubCategory(self
, protection
):
1074 cm
= CategoryManager()
1078 # set the protection
1079 sc
.setProtection(protection
)
1081 Catalog
.getIdx('categ_conf_sd').add_category(sc
.getId())
1082 sc
._notify
('created', self
)
1084 self
._addSubCategory
( sc
)
1089 def _incNumConfs(self
, num
=1):
1090 """Increases the number of conferences for the current category in a given number.
1091 WARNING: Only Categories must use this method!!!"""
1092 self
._numConferences
= self
.getNumConferences()
1093 self
._numConferences
+=num
1094 if self
.getOwner() is not None:
1095 self
.getOwner()._incNumConfs
(num
)
1097 def _decNumConfs(self
, num
=1):
1098 """Decreases the number of conferences for the current category in a given number.
1099 WARNING: Only Categories must use this method!!!"""
1100 self
._numConferences
= self
.getNumConferences()
1101 self
._numConferences
-=num
1102 if self
.getOwner() is not None:
1103 self
.getOwner()._decNumConfs
(num
)
1105 def _addConference( self
, newConf
):
1106 if len(self
.subcategories
)>0:
1107 raise MaKaCError( _("Cannot add event: the current category already contains some sub-categories"), _("Category"))
1108 if newConf
.getId() == "":
1109 raise MaKaCError( _("Cannot add to a category an event which is not registered"), _("Category"))
1110 self
.conferences
.insert(newConf
)
1111 newConf
.addOwner(self
)
1112 self
._incNumConfs
(1)
1113 self
.indexConf(newConf
)
1116 def getAccessKey(self
):
1119 def getModifKey(self
):
1122 def indexConf( self
, conf
):
1123 # Specific for category changes, calls Conference.indexConf()
1124 # (date-related indexes)
1125 catIdx
= indexes
.IndexesHolder().getIndex('category')
1126 catIdx
.indexConf(conf
)
1129 def unindexConf( self
, conf
):
1130 catIdx
= indexes
.IndexesHolder().getIndex('category')
1131 catIdx
.unindexConf(conf
)
1134 def newConference( self
, creator
, id="", creationDate
=None, modificationDate
=None ):
1135 conf
= Conference( creator
, id, creationDate
, modificationDate
)
1136 ConferenceHolder().add( conf
)
1137 self
._addConference
( conf
)
1140 conf
._notify
('created', self
)
1144 def removeConference( self
, conf
, notify
=True, delete
= False ):
1145 if not (conf
in self
.conferences
):
1148 self
.unindexConf( conf
)
1150 self
.conferences
.remove(conf
)
1153 conf
.removeOwner( self
, notify
)
1154 self
._decNumConfs
(1)
1157 def getSubCategoryList( self
):
1158 subcategs
= self
.subcategories
.values()
1160 for categ
in subcategs
:
1161 cl
.append("%04s%s-%s" % (categ
.getOrder(),categ
.getName().replace("-",""),categ
.getId()))
1165 id = c
.split("-")[1]
1166 res
.append(self
.subcategories
[id])
1169 def iteritems(self
, *args
):
1170 return self
.conferences
.iteritems(*args
)
1172 def itervalues(self
, *args
):
1173 return self
.conferences
.itervalues(*args
)
1175 def getConferenceList( self
, sortType
=1 ):
1176 """returns the list of conferences included in the current category.
1177 Thanks to the used structure the list is sorted by date.
1178 We can choose other sorting types:
1180 sortType=1--> By date
1181 sortType=2--> Alphabetically
1182 sortType=3--> Alphabetically - Reversed
1185 res
= sorted(self
.conferences
, cmp=Conference
._cmpByDate
)
1188 res
.sort(Conference
._cmpTitle
)
1190 res
.sort(Conference
._cmpTitle
)
1194 def iterConferences( self
):
1195 """returns the iterator for conferences.
1197 return self
.conferences
1199 def iterAllConferences( self
):
1200 """returns the iterator for conferences in all subcategories.
1202 for conf
in self
.conferences
:
1205 for subcateg
in self
.subcategories
.itervalues():
1206 for conf
in subcateg
.iterAllConferences():
1209 def getAllConferenceList( self
):
1210 """returns the list of all conferences included in the current category
1211 and in all its subcategories"""
1212 res
= self
.getConferenceList()
1213 subcategs
= self
.getSubCategoryList()
1215 for subcateg
in subcategs
:
1216 res
.extend(subcateg
.getAllConferenceList())
1219 def getRelativeEvent(self
, which
, conf
=None):
1220 index
= Catalog
.getIdx('categ_conf_sd').getCategory(self
.getId())
1221 if which
== 'first':
1222 return list(index
[index
.minKey()])[0]
1223 elif which
== 'last':
1224 return list(index
[index
.maxKey()])[-1]
1225 elif which
in ('next', 'prev'):
1226 categIter
= index
.itervalues()
1233 nextEvt
= next(categIter
, None)
1239 raise AttributeError("'conf' parameter missing")
1241 raise AttributeError("Unknown argument value: '%s'" % which
)
1243 def _setNumConferences(self
):
1244 self
._numConferences
= 0
1245 if self
.conferences
:
1246 self
._incNumConfs
(len(self
.conferences
))
1248 for sc
in self
.getSubCategoryList():
1249 self
._incNumConfs
(sc
.getNumConferences())
1251 def getNumConferences( self
):
1252 """returns the total number of conferences contained in the current
1253 category and all its sub-categories (if any)"""
1254 #this new approach will speed up considerably the counting of category
1255 # conferences. However, it will give non accurate results for
1256 # conferences within many categories (a conference will be counted
1257 # twice in parent categories).
1258 # Besides this approach will generate much more conflict errors. This
1259 # can be reduced by simply isolating the counter in a separate object.
1261 if self
._numConferences
:
1263 except AttributeError:
1264 self
._setNumConferences
()
1265 return self
._numConferences
1267 def _getRepository( self
):
1268 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
1270 fr
= dbRoot
["local_repositories"]["main"]
1272 fr
= fileRepository
.MaterialLocalRepository()
1273 dbRoot
["local_repositories"] = OOBTree()
1274 dbRoot
["local_repositories"]["main"] = fr
1277 def removeResource( self
, res
):
1280 def setIcon( self
, iconFile
):
1281 iconFile
.setOwner( self
)
1282 iconFile
.setId( "icon" )
1283 iconFile
.archive( self
._getRepository
() )
1284 iconFile
.setProtection( -1 )
1285 if self
.getIcon() != None:
1287 self
._icon
= iconFile
1288 self
.notifyModification()
1290 def getIcon( self
):
1294 except AttributeError, e
:
1298 def getIconURL( self
):
1299 if self
.getIcon() is None:
1301 return self
._icon
.getURL()
1303 def removeIcon(self
):
1304 if self
.getIcon() is None:
1308 self
.notifyModification()
1310 def recoverIcon(self
, icon
):
1312 if self
.getIcon() != None:
1316 self
.notifyModification()
1318 def getManagerList( self
):
1319 return self
.__ac
.getModifierList()
1321 def grantModification( self
, prin
):
1322 self
.__ac
.grantModification( prin
)
1323 if isinstance(prin
, MaKaC
.user
.Avatar
):
1324 prin
.linkTo(self
, "manager")
1327 def revokeModification( self
, prin
):
1328 self
.__ac
.revokeModification( prin
)
1329 if isinstance(prin
, MaKaC
.user
.Avatar
):
1330 prin
.unlinkTo(self
, "manager")
1333 def canModify( self
, aw
):
1334 return self
.canUserModify( aw
.getUser() )
1336 def canUserModify( self
, av
):
1338 if self
.getOwner() != None:
1339 inherited
= self
.getOwner().canUserModify( av
)
1340 return inherited
or self
.__ac
.canModify( av
)
1343 def getAllowedToAccessList( self
):
1344 return self
.__ac
.getAccessList()
1346 def canKeyAccess( self
, aw
):
1347 # Categories don't allow access keys
1350 def canIPAccess( self
, ip
):
1351 if not self
.__ac
.canIPAccess( ip
):
1354 # if category is inheriting, check protection above
1355 if self
.getAccessProtectionLevel() == 0 and self
.getOwner():
1356 return self
.getOwner().canIPAccess(ip
)
1359 def isProtected( self
):
1360 return self
.__ac
.isProtected()
1362 def getAccessProtectionLevel( self
):
1363 return self
.__ac
.getAccessProtectionLevel()
1365 def isItselfProtected( self
):
1366 return self
.__ac
.isItselfProtected()
1368 def hasAnyProtection( self
):
1369 if self
.__ac
.isProtected() or len(self
.getDomainList())>0:
1371 if self
.getAccessProtectionLevel() == -1: #PUBLIC
1373 if self
.getOwner() is not None:
1374 return self
.getOwner().hasAnyProtection()
1377 def setProtection( self
, private
):
1379 Allows to change the category's access protection
1382 oldProtection
= 1 if self
.isProtected() else -1
1384 self
.__ac
.setProtection( private
)
1385 self
._notify
('protectionChanged', oldProtection
, private
)
1388 def hasProtectedOwner( self
):
1389 return self
.__ac
._getFatherProtection
()
1391 def isAllowedToAccess( self
, av
):
1392 """Says whether an avatar can access a category independently of it is
1393 or not protected or domain filtered
1395 if self
.__ac
.canUserAccess( av
) or self
.canUserModify( av
):
1397 if not self
.isItselfProtected() and self
.getOwner():
1398 return self
.getOwner().isAllowedToAccess( av
)
1400 def canView(self
,aw
):
1401 if self
.canAccess( aw
):
1403 for conf
in self
.getConferenceList():
1404 if conf
.canView( aw
):
1406 for subcateg
in self
.getSubCategoryList():
1407 if subcateg
.canView( aw
):
1411 def canAccess( self
, aw
):
1412 if not self
.hasAnyProtection():
1414 if not self
.isProtected():
1415 #domain checking only triggered if the category is PUBLIC
1416 return self
.canIPAccess( aw
.getIP() ) or \
1417 self
.isAllowedToCreateConference(aw
.getUser()) or \
1418 self
.isAllowedToAccess(aw
.getUser())
1419 return self
.isAllowedToCreateConference(aw
.getUser()) or \
1420 self
.isAllowedToAccess(aw
.getUser())
1422 def grantAccess( self
, prin
):
1423 self
.__ac
.grantAccess( prin
)
1424 if isinstance(prin
, MaKaC
.user
.Avatar
):
1425 prin
.linkTo(self
, "access")
1427 def revokeAccess( self
, prin
):
1428 self
.__ac
.revokeAccess( prin
)
1429 if isinstance(prin
, MaKaC
.user
.Avatar
):
1430 prin
.unlinkTo(self
, "access")
1432 def isConferenceCreationRestricted( self
):
1433 return self
.__confCreationRestricted
1435 def restrictConferenceCreation( self
):
1436 self
.__confCreationRestricted
= 1
1438 def allowConferenceCreation( self
):
1439 self
.__confCreationRestricted
= 0
1441 def grantConferenceCreation( self
, prin
):
1442 if prin
not in self
.__confCreators
:
1443 self
.__confCreators
.append( prin
)
1444 if isinstance(prin
, MaKaC
.user
.Avatar
):
1445 prin
.linkTo(self
, "creator")
1448 def revokeConferenceCreation( self
, prin
):
1449 if prin
in self
.__confCreators
:
1450 self
.__confCreators
.remove( prin
)
1451 if isinstance(prin
, MaKaC
.user
.Avatar
):
1452 prin
.unlinkTo(self
, "creator")
1455 def getConferenceCreatorList( self
):
1456 return self
.__confCreators
1458 def isAllowedToCreateConference( self
, av
):
1460 if self
.canUserModify( av
):
1463 # Avatar is directly in the list
1464 if av
in self
.__confCreators
:
1467 # Otherwise, if it is a member of one of the groups in the list...
1468 for group
in self
.__confCreators
:
1469 if isinstance(group
, MaKaC
.user
.Group
):
1470 if group
.containsUser(av
):
1476 def canCreateConference( self
, av
):
1477 if not self
.isConferenceCreationRestricted():
1479 return self
.isAllowedToCreateConference( av
)
1481 def requireDomain( self
, dom
):
1482 self
.__ac
.requireDomain( dom
)
1483 self
._notify
('accessDomainAdded', dom
)
1485 def freeDomain( self
, dom
):
1486 self
.__ac
.freeDomain( dom
)
1487 self
._notify
('accessDomainRemoved', dom
)
1489 def getDomainList( self
):
1490 return self
.__ac
.getRequiredDomainList()
1492 def getStatistics( self
):
1494 if self
._statistics
:
1496 except AttributeError, e
:
1497 self
._statistics
= {}
1498 return self
._statistics
1500 def notifyModification(self
, raiseEvent
= True):
1501 """Method called to notify the current category has been modified.
1504 self
._notify
('infoChanged')
1509 class CustomLocation(Persistent
):
1511 def __init__(self
, **locationData
):
1516 def setValues(self
, data
):
1517 self
.setName(data
.get("name",""))
1518 self
.setAddress(data
.get("address",""))
1519 self
.setRoom(data
.get("room",""))
1521 def getValues(self
):
1523 d
["name"]=self
.getName()
1524 d
["address"]=self
.getAddress()
1525 d
["room"]=self
.getRoom()
1529 newCL
=CustomLocation()
1530 newCL
.setValues(self
.getValues())
1533 def setName(self
, newName
):
1539 def setAddress(self
, newAddress
):
1540 self
.address
= newAddress
1542 def getAddress(self
):
1545 def setRoom(self
, newRoom
):
1552 class CustomRoom(Persistent
):
1554 def __init__( self
):
1557 def setValues(self
, data
):
1558 self
.setName(data
.get("name",""))
1559 self
.setFullName(data
.get("fullName"))
1561 def getValues(self
):
1563 d
["name"]=self
.getName()
1564 d
["fullName"]=self
.getFullName()
1572 newCR
.setValues(self
.getValues())
1575 def setName( self
, newName
):
1576 self
.name
= newName
.strip()
1578 def getName( self
):
1581 def retrieveFullName(self
, location
):
1584 room
= CrossLocationQueries
.getRooms(roomName
=self
.name
, location
=location
)
1585 self
.fullName
= room
.getFullName() if room
else None
1587 def setFullName(self
, newFullName
):
1588 self
.fullName
= newFullName
1590 def getFullName(self
):
1591 if not hasattr(self
, 'fullName'):
1592 self
.fullName
= None
1593 return self
.fullName
1596 class ConferenceParticipation(Persistent
, Fossilizable
, Observable
):
1598 fossilizes(IConferenceParticipationFossil
, IConferenceParticipationMinimalFossil
)
1604 self
._affiliation
=""
1610 def _notifyModification( self
):
1613 def setValues(self
, data
):
1614 self
.setFirstName(data
.get("firstName", ""))
1615 self
.setFamilyName(data
.get("familyName",""))
1616 self
.setAffiliation(data
.get("affilation",""))
1617 self
.setAddress(data
.get("address",""))
1618 self
.setEmail(data
.get("email",""))
1619 self
.setFax(data
.get("fax",""))
1620 self
.setTitle(data
.get("title",""))
1621 self
.setPhone(data
.get("phone",""))
1622 self
._notifyModification
()
1624 def getValues(self
):
1626 data
["firstName"]=self
.getFirstName()
1627 data
["familyName"]=self
.getFamilyName()
1628 data
["affilation"]=self
.getAffiliation()
1629 data
["address"]=self
.getAddress()
1630 data
["email"]=self
.getEmail()
1631 data
["fax"]=self
.getFax()
1632 data
["title"]=self
.getTitle()
1633 data
["phone"]=self
.getPhone()
1636 def setId(self
, newId
):
1642 def setDataFromAvatar(self
,av
):
1643 # av is an Avatar object.
1646 self
.setFirstName(av
.getName())
1647 self
.setFamilyName(av
.getSurName())
1648 self
.setEmail(av
.getEmail())
1649 self
.setAffiliation(av
.getOrganisation())
1650 self
.setAddress(av
.getAddress())
1651 self
.setPhone(av
.getTelephone())
1652 self
.setTitle(av
.getTitle())
1653 self
.setFax(av
.getFax())
1654 self
._notifyModification
()
1656 def setDataFromOtherCP(self
,cp
):
1657 # cp is a ConferenceParticipation object.
1660 self
.setFirstName(cp
.getFirstName())
1661 self
.setFamilyName(cp
.getFamilyName())
1662 self
.setEmail(cp
.getEmail())
1663 self
.setAffiliation(cp
.getAffiliation())
1664 self
.setAddress(cp
.getAddress())
1665 self
.setPhone(cp
.getPhone())
1666 self
.setTitle(cp
.getTitle())
1667 self
.setFax(cp
.getFax())
1668 self
._notifyModification
()
1671 TrashCanManager().add(self
)
1674 TrashCanManager().remove(self
)
1676 @Updates (['MaKaC.conference.ConferenceParticipation',
1677 'MaKaC.conference.SessionChair',
1678 'MaKaC.conference.SlotChair'], 'firstName')
1679 def setFirstName(self
,newName
):
1681 if tmp
==self
._firstName
:
1684 self
._notifyModification
()
1686 def getFirstName( self
):
1687 return self
._firstName
1689 @Updates (['MaKaC.conference.ConferenceParticipation',
1690 'MaKaC.conference.SessionChair',
1691 'MaKaC.conference.SlotChair'], 'familyName')
1692 def setFamilyName(self
,newName
):
1694 if tmp
==self
._surName
:
1697 self
._notifyModification
()
1699 def getFamilyName( self
):
1700 return self
._surName
1702 @Updates (['MaKaC.conference.ConferenceParticipation',
1703 'MaKaC.conference.SessionChair',
1704 'MaKaC.conference.SlotChair'], 'email')
1705 def setEmail(self
,newMail
):
1707 if tmp
==self
._email
:
1709 self
._email
=newMail
.strip()
1710 self
._notifyModification
()
1712 def getEmail( self
):
1715 @Updates (['MaKaC.conference.ConferenceParticipation',
1716 'MaKaC.conference.SessionChair',
1717 'MaKaC.conference.SlotChair'], 'affiliation')
1718 def setAffiliation(self
,newAffil
):
1719 self
._affiliation
=newAffil
.strip()
1720 self
._notifyModification
()
1722 def getAffiliation(self
):
1723 return self
._affiliation
1725 @Updates (['MaKaC.conference.ConferenceParticipation',
1726 'MaKaC.conference.SessionChair',
1727 'MaKaC.conference.SlotChair'], 'address')
1728 def setAddress(self
,newAddr
):
1729 self
._address
=newAddr
.strip()
1730 self
._notifyModification
()
1732 def getAddress(self
):
1733 return self
._address
1735 @Updates (['MaKaC.conference.ConferenceParticipation',
1736 'MaKaC.conference.SessionChair',
1737 'MaKaC.conference.SlotChair'], 'phone')
1738 def setPhone(self
,newPhone
):
1739 self
._phone
=newPhone
.strip()
1740 self
._notifyModification
()
1745 @Updates (['MaKaC.conference.ConferenceParticipation',
1746 'MaKaC.conference.SessionChair',
1747 'MaKaC.conference.SlotChair'], 'title')
1748 def setTitle(self
,newTitle
):
1749 self
._title
=newTitle
.strip()
1750 self
._notifyModification
()
1755 @Updates (['MaKaC.conference.ConferenceParticipation',
1756 'MaKaC.conference.SessionChair',
1757 'MaKaC.conference.SlotChair'], 'fax')
1758 def setFax(self
,newFax
):
1759 self
._fax
=newFax
.strip()
1760 self
._notifyModification
()
1765 def getFullName( self
):
1766 res
= self
.getFamilyName()
1767 if self
.getFirstName() != "":
1768 if res
.strip() != "":
1769 res
= "%s, %s"%( res
, self
.getFirstName() )
1771 res
= self
.getFirstName()
1772 if self
.getTitle() != "":
1773 res
= "%s %s"%( self
.getTitle(), res
)
1776 def getFullNameNoTitle( self
):
1777 res
= self
.getFamilyName()
1778 if self
.getFirstName() != "":
1779 if res
.strip() != "":
1780 res
= "%s, %s"%( res
, self
.getFirstName() )
1782 res
= self
.getFirstName()
1785 def getDirectFullName( self
):
1786 res
= "%s %s"%( self
.getFirstName(), self
.getFamilyName() )
1788 if self
.getTitle() != "":
1789 res
= "%s %s"%( self
.getTitle(), res
)
1792 def getAbrName(self
):
1793 res
= self
.getFamilyName()
1794 if self
.getFirstName() != "":
1797 res
= "%s%s."%(res
, self
.getFirstName()[0].upper())
1800 def _cmpFamilyName( cp1
, cp2
):
1801 o1
= "%s %s"%(cp1
.getFamilyName(), cp1
.getFirstName())
1802 o2
= "%s %s"%(cp2
.getFamilyName(), cp2
.getFirstName())
1803 o1
=o1
.lower().strip()
1804 o2
=o2
.lower().strip()
1805 return cmp( o1
, o2
)
1806 _cmpFamilyName
=staticmethod(_cmpFamilyName
)
1809 class ConferenceChair(ConferenceParticipation
, Fossilizable
):
1811 fossilizes(IConferenceParticipationFossil
)
1816 ConferenceParticipation
.__init
__(self
)
1818 def _notifyModification( self
):
1819 if self
._conf
!= None:
1820 self
._conf
.notifyModification()
1823 newCC
=ConferenceChair()
1824 newCC
.setValues(self
.getValues())
1827 def getConference(self
):
1833 def includeInConference(self
,conf
,id):
1834 if self
.getConference()==conf
and self
.getId()==id.strip():
1841 ConferenceParticipation
.delete(self
)
1843 def getLocator(self
):
1844 if self
.getConference() is None:
1846 loc
=self
.getConference().getLocator()
1847 loc
["chairId"]=self
.getId()
1850 class SubmitterIndex(Persistent
):
1851 """Index for contribution submitters.
1853 This class allows to index users with submission privileges over the
1854 conference contributions so the owner can answer optimally to the query
1855 if a user has any submission privilege over any contribution
1857 It is implemented by simply using a BTree where the Avatar id is used
1858 as key (because it is unique and non variable) and a list of
1859 contributions over which he has submission privileges is kept as values.
1860 It is the responsability of the index owner (conference contributions)
1861 to keep it up-to-date i.e. notify conference sumitters additions and
1865 def __init__( self
):
1866 self
._idx
= OOBTree()
1867 self
._idxEmail
= OOBTree()
1869 def _getIdxEmail(self
):
1871 return self
._idxEmail
1873 self
._idxEmail
= OOBTree()
1874 return self
._idxEmail
1876 def getContributions(self
,av
):
1877 """Gives a list with the contributions over which a user has
1878 coordination privileges
1882 ret
= self
._idx
.get(av
.getId(),[])
1884 self
._moveEmailtoId
(av
)
1885 ret
= self
._idx
.get(av
.getId(),[])
1888 def index(self
,av
,contrib
):
1889 """Registers in the index a submitter of a contribution.
1891 if av
==None or contrib
==None:
1893 if not self
._idx
.has_key(av
.getId()):
1895 self
._idx
[av
.getId()]=l
1897 l
=self
._idx
[av
.getId()]
1898 if contrib
not in l
:
1900 self
._idx
[av
.getId()]=l
1902 def indexEmail(self
, email
, contrib
):
1903 if not email
or not contrib
:
1905 if not self
._getIdxEmail
().has_key(email
):
1907 self
._getIdxEmail
()[email
] = l
1909 l
= self
._getIdxEmail
()[email
]
1910 if not contrib
in l
:
1912 self
._getIdxEmail
()[email
] = l
1915 def unindex(self
,av
,contrib
):
1916 if av
==None or contrib
==None:
1918 l
=self
._idx
.get(av
.getId(),[])
1921 self
._idx
[av
.getId()]=l
1923 def unindexEmail(self
, email
, contrib
):
1924 if not email
or not contrib
:
1926 if self
._getIdxEmail
().has_key(email
):
1927 l
= self
._getIdxEmail
()[email
]
1931 del self
._getIdxEmail
()[email
]
1933 self
._getIdxEmail
()[email
] = l
1935 def _moveEmailtoId(self
, av
):
1937 email
= av
.getEmail()
1938 if not self
._idx
.has_key(id):
1939 if self
._getIdxEmail
().has_key(email
):
1940 self
._idx
[id] = self
._getIdxEmail
()[email
]
1941 del self
._getIdxEmail
()[email
]
1944 class ReportNumberHolder(Persistent
):
1946 def __init__(self
, owner
):
1953 def addReportNumber(self
, system
, number
):
1954 if system
in self
.getReportNumberKeys() or system
in Config
.getInstance().getReportNumberSystems().keys():
1956 if not number
in self
._reports
[system
]:
1957 self
._reports
[system
].append(number
)
1959 self
._reports
[system
]=[ number
]
1960 self
.notifyModification()
1962 def removeReportNumber(self
, system
, number
):
1963 if self
.hasReportNumbersBySystem(system
):
1964 if number
in self
._reports
[system
]:
1965 self
._reports
[system
].remove(number
)
1966 self
.notifyModification()
1968 def removeReportNumberById(self
, id):
1970 rn
= self
.listReportNumbers()[int(id)]
1971 self
.removeReportNumber(rn
[0], rn
[1])
1975 def hasReportNumbersBySystem(self
, system
):
1976 return self
._reports
.has_key(system
)
1978 def getReportNumbersBySystem(self
, system
):
1979 if self
.hasReportNumbersBySystem(system
):
1980 return self
._reports
[system
]
1983 def getReportNumberKeys(self
):
1984 return self
._reports
.keys()
1986 def listReportNumbersOnKey(self
, key
):
1988 if key
in self
._reports
.keys():
1989 # compatibility with previous versions
1990 if type(self
._reports
[key
]) is str:
1991 self
._reports
[key
] = [ self
._reports
[key
] ]
1992 for number
in self
._reports
[key
]:
1993 reports
.append([key
, number
])
1996 def hasReportNumberOnSystem(self
, system
, number
):
1997 if self
.hasReportNumbersBySystem(system
):
1998 if number
in self
._reports
[system
]:
2002 def listReportNumbers(self
):
2004 keys
= self
._reports
.keys()
2007 # compatibility with previous versions
2008 if type(self
._reports
[key
]) is str:
2009 self
._reports
[key
] = [ self
._reports
[key
] ]
2010 for number
in self
._reports
[key
]:
2011 reports
.append([key
, number
])
2014 def clone(self
, owner
):
2015 newR
=ReportNumberHolder(owner
)
2016 for key
in self
._reports
.keys():
2017 for number
in self
._reports
[key
]:
2018 newR
.addReportNumber(key
, number
)
2021 def notifyModification(self
):
2023 if self
.getOwner() != None:
2024 self
.getOwner().notifyModification()
2027 class Conference(CommonObjectBase
, Locatable
):
2028 """This class represents the real world conferences themselves. Objects of
2029 this class will contain basic data about the confence and will provide
2030 access to other objects representing certain parts of the conferences
2031 (ex: contributions, sessions, ...).
2034 fossilizes(IConferenceFossil
, IConferenceMinimalFossil
, IConferenceEventInfoFossil
)
2036 def __init__(self
, creator
, id="", creationDate
= None, modificationDate
= None):
2037 """Class constructor. Initialise the class attributes to the default
2040 confData -- (Dict) Contains the data the conference object has to
2043 #IndexedObject.__init__(self)
2045 raise MaKaCError( _("A creator must be specified when creating a new Event"), _("Event"))
2046 self
.__creator
= creator
2049 self
.description
= ""
2052 ###################################
2053 # Fermi timezone awareness #
2054 ###################################
2055 self
.startDate
= nowutc()
2056 self
.endDate
= nowutc()
2058 ###################################
2059 # Fermi timezone awareness(end) #
2060 ###################################
2061 self
._screenStartDate
= None
2062 self
._screenEndDate
= None
2063 self
.contactInfo
=""
2064 self
.chairmanText
= ""
2066 self
._chairGen
=Counter()
2069 self
.__sessionGenerator
= Counter() # Provides session unique
2070 # identifiers for this conference
2071 self
.contributions
= {}
2072 self
.__contribGenerator
= Counter() # Provides contribution unique
2073 # identifiers for this conference
2074 self
.programDescription
= ""
2076 self
.__programGenerator
= Counter() # Provides track unique
2077 # identifiers for this conference
2078 self
.__ac
= AccessController(self
)
2080 self
.__materialGenerator
= Counter() # Provides material unique
2081 # identifiers for this conference
2087 self
.__schedule
=None
2090 self
._creationDS
= creationDate
2092 self
._creationDS
= nowutc() #creation timestamp
2093 if modificationDate
:
2094 self
._modificationDS
= modificationDate
2096 self
._modificationDS
= nowutc() #modification timestamp
2099 self
.__alarmCounter
= Counter()
2101 self
.abstractMgr
= review
.AbstractMgr(self
)
2103 self
._trackCoordinators
= TCIndex() #index for the track coordinators
2104 self
._supportInfo
= SupportInfo(self
, "Support")
2105 self
._contribTypes
= {}
2106 self
.___contribTypeGenerator
= Counter()
2107 self
._authorIdx
=AuthorIndex()
2108 self
._speakerIdx
=AuthorIndex()
2109 self
._primAuthIdx
=_PrimAuthIdx(self
)
2110 self
._sessionCoordinators
=SCIndex()
2111 self
._sessionCoordinatorRights
= []
2112 self
._submitterIdx
=SubmitterIndex()
2113 self
._boa
=BOAConfig(self
)
2114 self
._registrationForm
= registration
.RegistrationForm(self
)
2115 self
._evaluationCounter
= Counter()
2116 self
._evaluations
= [Evaluation(self
)]
2117 self
._registrants
= {} #key=registrantId; value=Registrant
2119 self
._registrantGenerator
= Counter()
2122 self
._closed
= False
2123 self
._visibility
= 999
2124 self
._pendingQueuesMgr
=pendingQueues
.ConfPendingQueuesMgr(self
)
2126 self
._participation
= Participation(self
)
2127 self
._logHandler
= LogHandler()
2128 self
._reportNumberHolder
=ReportNumberHolder(self
)
2129 self
._enableSessionSlots
= False
2130 self
._enableSessions
= False
2131 self
._autoSolveConflict
= True
2132 self
.__badgeTemplateManager
= BadgeTemplateManager(self
)
2133 self
.__posterTemplateManager
= PosterTemplateManager(self
)
2135 self
._confPaperReview
= ConferencePaperReview(self
)
2136 self
._confAbstractReview
= ConferenceAbstractReview(self
)
2139 self
._sortUrlTag
= ""
2141 self
._observers
= []
2143 if PluginsHolder().hasPluginType("Collaboration"):
2144 from MaKaC
.plugins
.Collaboration
.base
import CSBookingManager
2145 self
._CSBookingManager
= CSBookingManager(self
)
2148 return "<Conference %s@%s>" % (self
.getId(), hex(id(self
)))
2151 def _cmpByDate(self
, toCmp
):
2152 res
= cmp(self
.getStartDate(), toCmp
.getStartDate())
2156 return cmp(self
, toCmp
)
2158 def __cmp__(self
, toCmp
):
2159 if isinstance(toCmp
, Conference
):
2160 return cmp(self
.getId(), toCmp
.getId())
2162 return cmp(hash(self
), hash(toCmp
))
2164 def __eq__(self
, toCmp
):
2165 return self
is toCmp
2167 def __ne__(self
, toCmp
):
2168 return not(self
is toCmp
)
2170 def setUrlTag(self
, tag
):
2171 self
._sortUrlTag
= tag
2173 def getUrlTag(self
):
2175 return self
._sortUrlTag
2177 self
._sortUrlTag
= ""
2178 return self
._sortUrlTag
2180 def setComments(self
,comm
=""):
2181 self
._comments
= comm
.strip()
2183 def getComments(self
):
2187 except AttributeError,e
:
2189 return self
._comments
2191 def getConfPaperReview(self
):
2192 if not hasattr(self
, "_confPaperReview"):
2193 self
._confPaperReview
= ConferencePaperReview(self
)
2194 return self
._confPaperReview
2196 def getConfAbstractReview(self
):
2197 if not hasattr(self
, "_confAbstractReview"):
2198 self
._confAbstractReview
= ConferenceAbstractReview(self
)
2199 return self
._confAbstractReview
2201 def getOrgText( self
):
2203 return self
._orgText
2208 def setOrgText( self
, org
="" ):
2211 def cleanCache( self
):
2212 minfo
= info
.HelperMaKaCInfo
.getMaKaCInfoInstance()
2213 if minfo
.isCacheActive():
2214 cache
= EventCache({"id":self
.getId(), "type": "normal"})
2216 cache
= EventCache({"id":self
.getId(), "type": "manager"})
2218 cache
= EventCache({"id":self
.getId(), "type": "static"})
2221 if not ContextManager
.get('clean%s'%self
.getUniqueId(), False):
2222 ScheduleToJson
.cleanConferenceCache(self
)
2223 ContextManager
.set('clean%s'%self
.getUniqueId(), True)
2225 def cleanCategoryCache( self
):
2226 if len(self
.getOwnerList()) > 0:
2227 self
.getOwnerList()[0].cleanCache()
2229 def updateNonInheritingChildren(self
, elem
, delete
=False):
2230 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
2232 def getKeywords(self
):
2234 return self
._keywords
2239 def setKeywords(self
, keywords
):
2240 self
._keywords
= keywords
2242 # Room booking related ===================================================
2244 def getRoomBookingList( self
):
2246 Returns list of bookings for this conference.
2248 from MaKaC
.plugins
.RoomBooking
.default
.dalManager
import DALManager
2250 if not DALManager
.isConnected():
2254 for resvGuid
in self
.getRoomBookingGuids():
2255 r
= resvGuid
.getReservation()
2257 self
.removeRoomBookingGuid( resvGuid
)
2262 def getBookedRooms( self
):
2264 Returns list of rooms booked for this conference.
2265 Returns [] if room booking module is off.
2269 for r
in self
.getRoomBookingList():
2270 if not r
.room
in rooms
:
2271 rooms
.append( r
.room
)
2274 def getRoomBookingGuids( self
):
2276 self
.__roomBookingGuids
2277 except AttributeError:
2278 self
.__roomBookingGuids
= []
2279 return self
.__roomBookingGuids
2281 def setRoomBookingGuids( self
, guids
):
2282 self
.__roomBookingGuids
= guids
2284 def addRoomBookingGuid( self
, guid
):
2285 self
.getRoomBookingGuids().append( guid
)
2286 self
._p
_changed
= True
2288 def removeRoomBookingGuid( self
, guid
):
2289 self
.getRoomBookingGuids().remove( guid
)
2290 self
._p
_changed
= True
2292 def __TMP_PopulateRoomBookings( self
):
2293 # TEMPORARY GENERATION OF RESERVATIONS FOR CONFERENCE
2294 from MaKaC
.rb_reservation
import ReservationBase
2295 from MaKaC
.rb_location
import ReservationGUID
, Location
2297 resvs
.append( ReservationBase
.getReservations( resvID
= 395887 ) )
2298 resvs
.append( ReservationBase
.getReservations( resvID
= 381406 ) )
2299 resvs
.append( ReservationBase
.getReservations( resvID
= 387688 ) )
2300 resvs
.append( ReservationBase
.getReservations( resvID
= 383459 ) )
2304 resvGuids
.append( ReservationGUID( Location
.getDefaultLocation(), resv
.id ) )
2306 self
.__roomBookingGuids
= resvGuids
2309 # ========================================================================
2311 def getParticipation(self
):
2313 if self
._participation
:
2315 except AttributeError :
2316 self
._participation
= Participation(self
)
2317 return self
._participation
2319 def getType( self
):
2320 import MaKaC
.webinterface
.webFactoryRegistry
as webFactoryRegistry
2321 wr
= webFactoryRegistry
.WebFactoryRegistry()
2322 wf
= wr
.getFactory(self
)
2329 def getVerboseType( self
):
2330 # Like getType, but returns "Lecture" instead of "simple_type"
2331 type = self
.getType()
2332 if type == "simple_event":
2334 return type.capitalize()
2337 def getLogHandler(self
):
2339 if self
._logHandler
:
2341 except AttributeError :
2342 self
._logHandler
= LogHandler()
2343 return self
._logHandler
2346 def getEnableSessionSlots(self
):
2348 # if self._enableSessionSlots :
2350 #except AttributeError :
2351 # self._enableSessionSlots = True
2352 #if self.getType() == "conference":
2354 #return self._enableSessionSlots
2357 def getEnableSessions(self
):
2359 if self
._enableSessions
:
2361 except AttributeError :
2362 self
._enableSessions
= True
2363 if self
.getType() == "conference":
2365 return self
._enableSessions
2367 def enableSessionSlots(self
):
2368 self
._enableSessionSlots
= True
2370 def disableSessionSlots(self
):
2371 self
._enableSessionSlots
= False
2373 def enableSessions(self
):
2374 self
._enableSessions
= True
2376 def disableSessions(self
):
2377 self
._enableSessions
= False
2379 def setValues(self
, confData
):
2381 Sets SOME values of the current conference object from a dictionary
2382 containing the following key-value pairs:
2388 locationName-(str) => name of the location, if not specified
2389 it will be set to the conference location name.
2390 locationAddress-(str)
2391 roomName-(str) => name of the room, if not specified it will
2392 be set to the conference room name.
2393 Please, note that this method sets SOME values which means that if
2394 needed it can be completed to set more values. Also note that if
2395 the given dictionary doesn't contain all the values, the missing
2396 ones will be set to the default values.
2398 self
.setVisibility(confData
.get("visibility", "999"))
2399 self
.setTitle(confData
.get("title", _("NO TITLE ASSIGNED")))
2400 self
.setDescription(confData
.get("description", ""))
2401 self
.getSupportInfo().setEmail(confData
.get("supportEmail", ""))
2402 self
.setContactInfo(confData
.get("contactInfo", ""))
2403 if confData
.get("locationName", "").strip() == "":
2404 self
.setLocation(None)
2406 #if the location name is defined we must set a new location (or
2407 # modify the existing one) for the conference
2408 loc
= self
.getLocation()
2410 loc
= CustomLocation()
2411 self
.setLocation(loc
)
2412 loc
.setName(confData
["locationName"])
2413 loc
.setAddress(confData
.get("locationAddress", ""))
2414 #same as for the location
2415 if confData
.get("roomName", "").strip() == "":
2418 room
= self
.getRoom()
2422 room
.setName(confData
["roomName"])
2423 self
.notifyModification()
2425 def getVisibility ( self
):
2427 return int(self
._visibility
)
2429 self
._visibility
= 999
2432 def getFullVisibility( self
):
2433 return max(0,min(self
.getVisibility(), self
.getOwnerList()[0].getVisibility()))
2435 def setVisibility( self
, visibility
=999 ):
2436 self
._visibility
= int(visibility
)
2437 catIdx
= indexes
.IndexesHolder().getIndex('category')
2438 catIdx
.reindexConf(self
)
2439 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
2440 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
2441 catDateIdx
.reindexConf(self
)
2442 catDateAllIdx
.reindexConf(self
)
2444 def isClosed( self
):
2448 self
._closed
= False
2451 def setClosed( self
, closed
=True ):
2452 self
._closed
= closed
2454 def indexConf( self
):
2455 # called when event dates change
2456 # see also Category.indexConf()
2458 calIdx
= indexes
.IndexesHolder().getIndex('calendar')
2459 calIdx
.indexConf(self
)
2460 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
2461 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
2462 catDateIdx
.indexConf(self
)
2463 catDateAllIdx
.indexConf(self
)
2464 nameIdx
= indexes
.IndexesHolder().getIndex('conferenceTitle')
2465 nameIdx
.index(self
.getId(), self
.getTitle().decode('utf-8'))
2467 Catalog
.getIdx('categ_conf_sd').index_obj(self
)
2470 def unindexConf( self
):
2471 calIdx
= indexes
.IndexesHolder().getIndex('calendar')
2472 calIdx
.unindexConf(self
)
2473 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
2474 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
2475 catDateIdx
.unindexConf(self
)
2476 catDateAllIdx
.unindexConf(self
)
2477 nameIdx
= indexes
.IndexesHolder().getIndex('conferenceTitle')
2478 nameIdx
.unindex(self
.getId())
2480 Catalog
.getIdx('categ_conf_sd').unindex_obj(self
)
2483 def __generateNewContribTypeId( self
):
2484 """Returns a new unique identifier for the current conference sessions
2487 return str(self
.___contribTypeGenerator
.newCount())
2489 self
.___contribTypeGenerator
= Counter()
2490 return str(self
.___contribTypeGenerator
.newCount())
2492 def addContribType(self
, ct
):
2494 if self
._contribTypes
:
2497 self
._contribTypes
= {}
2498 if ct
in self
._contribTypes
.values():
2502 id = self
.__generateNewContribTypeId
()
2504 self
._contribTypes
[id] = ct
2505 self
.notifyModification()
2507 def newContribType(self
, name
, description
):
2508 ct
= ContributionType(name
, description
, self
)
2509 self
.addContribType(ct
)
2512 def getContribTypeList(self
):
2514 return self
._contribTypes
.values()
2516 self
._contribTypes
= {}
2517 self
.notifyModification()
2518 return self
._contribTypes
.values()
2520 def getContribTypeById(self
, id):
2522 if self
._contribTypes
:
2525 self
._contribTypes
= {}
2526 self
.notifyModification()
2527 if id in self
._contribTypes
.keys():
2528 return self
._contribTypes
[id]
2531 def removeContribType(self
, ct
):
2533 if self
._contribTypes
:
2536 self
._contribTypes
= {}
2537 if not ct
in self
._contribTypes
.values():
2539 del self
._contribTypes
[ct
.getId()]
2540 for cont
in self
.getContributionList():
2541 if cont
.getType() == ct
:
2544 self
.notifyModification()
2546 def recoverContribType(self
, ct
):
2547 ct
.setConference(self
)
2548 self
.addContribType(ct
)
2551 def _getRepository( self
):
2552 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
2554 fr
= dbRoot
["local_repositories"]["main"]
2556 fr
= fileRepository
.MaterialLocalRepository()
2557 dbRoot
["local_repositories"] = OOBTree()
2558 dbRoot
["local_repositories"]["main"] = fr
2561 def removeResource( self
, res
):
2565 cid
= self
.getUrlTag()
2568 return Config
.getInstance().getShortEventURL() + cid
2570 def setLogo( self
, logoFile
):
2571 logoFile
.setOwner( self
)
2572 logoFile
.setId( "logo" )
2573 logoFile
.archive( self
._getRepository
() )
2574 if self
._logo
!= None:
2576 self
._logo
= logoFile
2577 self
.notifyModification()
2579 def getLogo( self
):
2582 def getLogoURL( self
):
2584 if self
._logo
== None:
2586 return self
._logo
.getURL()
2587 except AttributeError:
2591 def removeLogo(self
):
2592 if self
._logo
is None:
2596 self
.notifyModification()
2598 def recoverLogo(self
, logo
):
2600 if self
._logo
!= None:
2604 self
.notifyModification()
2606 def getSession(self
):
2609 def getContribution(self
):
2612 def getSubContribution(self
):
2615 def getAbstractMgr(self
):
2616 return self
.abstractMgr
2618 def notifyModification( self
, date
= None, raiseEvent
= True):
2619 """Method called to notify the current conference has been modified.
2621 self
.setModificationDate()
2624 self
._notify
('infoChanged')
2629 def getModificationDate( self
):
2630 """Returns the date in which the conference was last modified"""
2631 return self
._modificationDS
2633 def getAdjustedModificationDate( self
, tz
):
2634 """Returns the date in which the conference was last modified"""
2635 return self
._modificationDS
.astimezone(timezone(tz
))
2637 def getCreationDate( self
):
2638 """Returns the date in which the conference was created"""
2639 return self
._creationDS
2641 def getAdjustedCreationDate( self
, tz
):
2642 """Returns the date in which the conference was created"""
2643 return self
._creationDS
.astimezone(timezone(tz
))
2645 def getCreator( self
):
2646 return self
.__creator
2648 def setCreator( self
, creator
):
2650 self
.__creator
.unlinkTo(self
, "creator")
2651 creator
.linkTo(self
, "creator")
2652 self
.__creator
= creator
2654 def linkCreator(self
):
2655 self
.__creator
.linkTo(self
, "creator")
2658 """returns (string) the unique identifier of the conference"""
2661 def getUniqueId( self
):
2662 """returns (string) the unique identiffier of the item"""
2663 """used mainly in the web session access key table"""
2664 return "a%s" % self
.id
2666 def setId(self
, newId
):
2667 """changes the current unique identifier of the conference to the
2668 one which is specified"""
2669 self
.id = str(newId
)
2671 def getLocator( self
):
2672 """Gives back (Locator) a globaly unique identification encapsulated in
2673 a Locator object for the conference instance """
2675 d
["confId"] = self
.getId()
2678 def getOwner( self
):
2679 if self
.getOwnerList() == []:
2681 return self
.getOwnerList()[0]
2683 def getOwnerList( self
):
2684 return self
.__owners
2686 def getOwnerPath( self
):
2688 owner
= self
.getOwnerList()[0]
2689 while owner
!= None and owner
.getId() != "0":
2691 owner
= owner
.getOwner()
2694 def getOwnerById( self
, key
):
2695 """Returns one specific category which contains the conference.
2697 - key: The "id" of the category.
2699 for owner
in self
.__owners
:
2700 if key
== owner
.getId():
2704 def addOwner( self
, newOwner
):
2705 if newOwner
== None:
2707 self
.__owners
.append( newOwner
)
2708 self
.notifyModification()
2710 def removeOwner( self
, owner
, notify
=True ):
2711 if not (owner
in self
.__owners
):
2713 self
.__owners
.remove( owner
)
2714 owner
.removeConference( self
)
2716 self
.notifyModification()
2718 def getCategoriesPath(self
):
2719 return [self
.getOwnerList()[0].getCategoryPath()]
2721 def notifyContributions(self
):
2723 for c
in self
.getContributionList():
2724 # take care of subcontributions
2725 for sc
in c
.getSubContributionList():
2726 sc
._notify
('deleted', c
)
2728 c
._notify
('deleted', self
)
2731 """deletes the conference from the system.
2733 #we notify the observers that the conference has been deleted
2735 self
._notify
('deleted', self
.getOwner())
2736 except Exception, e
:
2738 Logger
.get('Conference').error("Exception while notifying the observer of a conference deletion for conference %s: %s" %
2739 (self
.getId(), str(e
)))
2740 except Exception, e2
:
2741 Logger
.get('Conference').error("Exception while notifying a conference deletion: %s (origin: %s)" % (str(e2
), str(e
)))
2743 self
.notifyContributions()
2745 #will have to remove it from all the owners (categories) and the
2746 # conference registry
2747 ConferenceHolder().remove( self
)
2748 for owner
in self
.__owners
:
2749 owner
.removeConference( self
, notify
=False )
2751 for alarm
in self
.getAlarmList():
2752 if not alarm
.getEndedOn():
2753 self
.removeAlarm(alarm
)
2755 self
.removeAllEvaluations()
2757 #Delete the RoomBooking associated reservations
2758 minfo
= info
.HelperMaKaCInfo
.getMaKaCInfoInstance()
2759 if minfo
.getRoomBookingModuleActive() and CrossLocationDB
.isConnected():
2760 for resv
in self
.getRoomBookingList():
2763 #For each conference we have a list of managers. If we delete the conference but we don't delete
2764 #the link in every manager to the conference then, when the manager goes to his "My profile" he
2765 #will see a link to a conference that doesn't exist. Therefore, we need to delete that link as well
2766 for manager
in self
.getManagerList():
2767 if isinstance(manager
, MaKaC
.user
.Avatar
):
2768 manager
.unlinkTo(self
, "manager")
2770 # Remove all links in redis
2771 if redis_write_client
:
2772 avatar_links
.delete_event(self
)
2774 # Remote short URL mappings
2775 sum = ShortURLMapper()
2778 TrashCanManager().add(self
)
2780 def getConference( self
):
2783 def getObservers(self
):
2784 if not hasattr(self
, "_observers"):
2785 self
._observers
= []
2786 return self
._observers
2788 def setDates( self
, sDate
, eDate
=None, check
=1, moveEntries
=0):
2790 Set the start/end date for a conference
2793 oldStartDate
= self
.getStartDate()
2794 oldEndDate
= self
.getEndDate()
2796 # do some checks first
2799 raise MaKaCError( _("Start date cannot be after the end date"), _("Event"))
2801 elif sDate
== oldStartDate
and eDate
== oldEndDate
:
2802 # if there's nothing to do (yet another obvious case)
2805 # if we reached this point, it means either the start or
2806 # the end date (or both) changed
2807 # If only the end date was changed, moveEntries = 0
2808 if sDate
== oldStartDate
:
2811 # Pre-check for moveEntries
2812 if moveEntries
== 1:
2813 # in case the entries are to be simply shifted
2814 # we should make sure the interval is big enough
2815 # just store the old values for later
2817 oldInterval
= oldEndDate
- oldStartDate
2818 newInterval
= eDate
- sDate
2820 entries
= self
.getSchedule().getEntries()
2821 if oldInterval
> newInterval
and entries
:
2822 eventInterval
= entries
[-1].getEndDate() - entries
[0].getStartDate()
2823 diff
= entries
[0].getStartDate() - oldStartDate
2824 if sDate
+ diff
+ eventInterval
> eDate
:
2826 _("The start/end dates were not changed since the selected "
2827 "timespan is not large enough to accomodate the contained "
2828 "timetable entries and spacings."),
2829 explanation
=_("You should try using a larger timespan."))
2831 # so, we really need to try changing something
2836 self
.setStartDate(sDate
, check
=0, moveEntries
= moveEntries
, index
=False, notifyObservers
= False)
2837 self
.setEndDate(eDate
, check
=0, index
=False, notifyObservers
= False)
2840 self
._checkInnerSchedule
()
2842 # reindex the conference
2845 # clear the category cache
2846 self
.cleanCategoryCache()
2850 self
._notify
('dateChanged', {'oldStartDate': oldStartDate
, 'newStartDate': self
.getStartDate(), 'oldEndDate': oldEndDate
, 'newEndDate': self
.getEndDate()})
2851 except Exception, e
:
2853 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" %
2854 (formatDateTime(oldStartDate
), formatDateTime(oldEndDate
),
2855 formatDateTime(self
.getStartDate()), formatDateTime(self
.getEndDate()), self
.getId(), str(e
)))
2856 except Exception, e2
:
2857 Logger
.get('Conference').error("Exception while notifying a start and end date change: %s (origin: %s)" % (str(e2
), str(e
)))
2860 def _checkInnerSchedule( self
):
2861 self
.getSchedule().checkSanity()
2863 def setStartDate(self
, sDate
, check
= 1, moveEntries
= 0, index
= True, notifyObservers
= True):
2864 """ Changes the current conference starting date/time to the one specified by the parameters.
2866 if not sDate
.tzname():
2867 raise MaKaCError("date should be timezone aware")
2868 if sDate
== self
.getStartDate():
2870 ###################################
2871 # Fermi timezone awareness #
2872 ###################################
2873 if sDate
.year
< 1900:
2874 sDate
= timezone('UTC').localize(1900,sDate
.month
, \
2875 sDate
.day
,sDate
.hour
,sDate
.minute
)
2876 ###################################
2877 # Fermi timezone awareness #
2878 ###################################
2880 self
.verifyStartDate(sDate
)
2881 oldSdate
= self
.getStartDate()
2882 diff
= sDate
- oldSdate
2886 self
.startDate
= sDate
2887 if moveEntries
and diff
is not None:
2888 # If the start date changed, we move entries inside the timetable
2889 self
.getSchedule()._startDate
=None
2890 self
.getSchedule()._endDate
=None
2891 #if oldSdate.date() != sDate.date():
2892 # entries = self.getSchedule().getEntries()[:]
2894 # entries = self.getSchedule().getEntriesOnDay(sDate.astimezone(timezone(self.getTimezone())))[:]
2895 entries
= self
.getSchedule().getEntries()[:]
2896 self
.getSchedule().moveEntriesBelow(diff
, entries
)
2897 #datetime object is non-mutable so we must "force" the modification
2898 # otherwise ZODB won't be able to notice the change
2899 self
.notifyModification()
2903 # update the time for the alarms to be sent
2904 self
._updateAlarms
()
2906 # Update redis link timestamp
2907 if redis_write_client
:
2908 avatar_links
.update_event_time(self
)
2910 #if everything went well, we notify the observers that the start date has changed
2913 self
._notify
('startDateChanged', {'newDate': sDate
, 'oldDate': oldSdate
})
2914 except Exception, e
:
2916 Logger
.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s" %
2917 (formatDateTime(oldSdate
), formatDateTime(sDate
), self
.getId(), str(e
)))
2918 except Exception, e2
:
2919 Logger
.get('Conference').error("Exception while notifying a start date change: %s (origin: %s)" % (str(e2
), str(e
)))
2922 def _updateAlarms(self
):
2924 # are there any alarms? if so, update the relative ones
2925 for alarm
in self
.getAlarmList():
2926 tbef
= alarm
.getTimeBefore()
2928 # only relative alarms
2929 c
.moveTask(alarm
, self
.getStartDate() - tbef
)
2931 def verifyStartDate(self
, sdate
, check
=1):
2932 if sdate
>self
.getEndDate():
2933 raise MaKaCError( _("End date cannot be before the Start date"), _("Event"))
2935 def setStartTime(self
, hours
=0, minutes
=0, notifyObservers
= True):
2936 """ Changes the current conference starting time (not date) to the one specified by the parameters.
2939 sdate
= self
.getStartDate()
2940 self
.startDate
= datetime( sdate
.year
, sdate
.month
, sdate
.day
,
2941 int(hours
), int(minutes
) )
2942 self
.verifyStartDate(self
.startDate
)
2943 self
.notifyModification()
2945 #if everything went well, we notify the observers that the start date has changed
2948 self
._notify
('startTimeChanged', sdate
)
2949 #for observer in self.getObservers():
2950 #observer.notifyEventDateChanges(sdate, self.startDate, None, None)
2951 except Exception, e
:
2953 Logger
.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s"%
2954 (formatDateTime(sdate
), formatDateTime(self
.startDate
), self
.getId(), str(e
)))
2955 except Exception, e2
:
2956 Logger
.get('Conference').error("Exception while notifying a start time change: %s (origin: %s)"%(str(e2
), str(e
)))
2958 def getStartDate(self
):
2959 """returns (datetime) the starting date of the conference"""
2960 return self
.startDate
2962 def getUnixStartDate(self
):
2963 return datetimeToUnixTimeInt(self
.startDate
)
2965 ###################################
2966 # Fermi timezone awareness #
2967 ###################################
2969 def getAdjustedStartDate(self
,tz
=None):
2971 tz
= self
.getTimezone()
2972 if tz
not in all_timezones
:
2974 return self
.getStartDate().astimezone(timezone(tz
))
2976 ###################################
2977 # Fermi timezone awareness(end) #
2978 ###################################
2980 def setScreenStartDate(self
, date
):
2981 if date
== self
.getStartDate():
2983 self
._screenStartDate
= date
2984 self
.notifyModification()
2986 def getScreenStartDate(self
):
2988 date
= self
._screenStartDate
2990 date
= self
._screenStartDate
= None
2994 return self
.getStartDate()
2996 def getAdjustedScreenStartDate(self
, tz
=None):
2998 tz
= self
.getTimezone()
2999 return self
.getScreenStartDate().astimezone(timezone(tz
))
3001 def calculateDayStartTime(self
, day
):
3002 """returns (date) the start date of the conference on a given day
3003 day is a tz aware datetime"""
3004 if self
.getStartDate().astimezone(day
.tzinfo
).date() == day
.date():
3005 return self
.getStartDate().astimezone(day
.tzinfo
)
3006 return self
.getSchedule().calculateDayStartDate(day
)
3008 def verifyEndDate(self
, edate
):
3009 if edate
<self
.getStartDate():
3010 raise TimingError( _("End date cannot be before the start date"), _("Event"))
3011 if self
.getSchedule().hasEntriesAfter(edate
):
3012 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"))
3014 def setEndDate(self
, eDate
, check
= 1, index
= True, notifyObservers
= True):
3015 """ Changes the current conference end date/time to the one specified by the parameters.
3017 if not eDate
.tzname():
3018 raise MaKaCError("date should be timezone aware")
3019 if eDate
== self
.getEndDate():
3021 if eDate
.year
< 1900:
3022 eDate
= datetime(1900,eDate
.month
,eDate
.day
,eDate
.hour
,eDate
.minute
)
3024 self
.verifyEndDate(eDate
)
3028 oldEdate
= self
.endDate
3029 self
.endDate
= eDate
3030 #datetime object is non-mutable so we must "force" the modification
3031 # otherwise ZODB won't be able to notice the change
3032 self
.notifyModification()
3036 #if everything went well, we notify the observers that the start date has changed
3039 self
._notify
('endDateChanged', {'newDate': eDate
, 'oldDate': oldEdate
})
3040 except Exception, e
:
3042 Logger
.get('Conference').error("Exception while notifying the observer of a end date change from %s to %s for conference %s: " %
3043 (formatDateTime(oldEdate
), formatDateTime(eDate
), self
.getId(), str(e
)))
3044 except Exception, e2
:
3045 Logger
.get('Conference').error("Exception while notifying a end date change: %s (origin: %s)" % (str(e2
), str(e
)))
3048 def setEndTime(self
, hours
= 0, minutes
= 0, notifyObservers
= True):
3049 """ Changes the current conference end time (not date) to the one specified by the parameters.
3051 edate
= self
.getEndDate()
3052 self
.endDate
= datetime( edate
.year
, edate
.month
, edate
.day
, int(hours
), int(minutes
) )
3053 self
.verifyEndDate(self
.endDate
)
3054 self
.notifyModification()
3056 #if everything went well, we notify the observers that the start date has changed
3059 self
._notify
('endTimeChanged', edate
)
3060 #for observer in self.getObservers():
3061 except Exception, e
:
3062 #observer.notifyEventDateChanges(None, None, edate, self.endDate)
3064 Logger
.get('Conference').error("Exception while notifying the observer of a end timet change from %s to %s for conference %s: %s" %
3065 (formatDateTime(edate
), formatDateTime(self
.endDate
), self
.getId(), str(e
)))
3066 except Exception, e2
:
3067 Logger
.get('Conference').error("Exception while notifying a end time change: %s (origin: %s)"%(str(e2
), str(e
)))
3069 def getEndDate(self
):
3070 """returns (datetime) the ending date of the conference"""
3073 ##################################
3074 # Fermi timezone awareness #
3075 ##################################
3077 def getAdjustedEndDate(self
,tz
=None):
3079 tz
= self
.getTimezone()
3080 if tz
not in all_timezones
:
3082 return self
.getEndDate().astimezone(timezone(tz
))
3084 ##################################
3085 # Fermi timezone awareness(end) #
3086 ##################################
3088 def setScreenEndDate(self
, date
):
3089 if date
== self
.getEndDate():
3091 self
._screenEndDate
= date
3092 self
.notifyModification()
3094 def getScreenEndDate(self
):
3096 date
= self
._screenEndDate
3098 date
= self
._screenEndDate
= None
3102 return self
.getEndDate()
3104 def getAdjustedScreenEndDate(self
, tz
=None):
3106 tz
= self
.getTimezone()
3107 return self
.getScreenEndDate().astimezone(timezone(tz
))
3109 def isEndDateAutoCal( self
):
3110 """Says whether the end date has been explicitely set for the session
3111 or it must be calculated automatically
3113 return self
._endDateAutoCal
3115 ####################################
3116 # Fermi timezone awareness #
3117 ####################################
3118 def setTimezone(self
, tz
):
3120 oldTimezone
= self
.timezone
3121 except AttributeError:
3124 #for observer in self.getObservers():
3126 #observer.notifyTimezoneChange(oldTimezone, tz)
3127 self
._notify
('timezoneChanged', oldTimezone
)
3128 except Exception, e
:
3130 Logger
.get('Conference').error("Exception while notifying the observer of a timezone change from %s to %s for conference %s: %s" %
3131 (str(oldTimezone
), str(tz
), self
.getId(), str(e
)))
3132 except Exception, e2
:
3133 Logger
.get('Conference').error("Exception while notifying a timezone change: %s (origin: %s)"%(str(e2
), str(e
)))
3135 def getTimezone(self
):
3137 return self
.timezone
3141 def moveToTimezone(self
, tz
):
3142 if self
.getTimezone() == tz
:
3144 sd
=self
.getAdjustedStartDate()
3145 ed
=self
.getAdjustedEndDate()
3146 self
.setTimezone(tz
)
3148 sDate
= timezone(tz
).localize(datetime(sd
.year
, \
3153 eDate
= timezone(tz
).localize(datetime(ed
.year
, \
3158 except ValueError,e
:
3159 raise MaKaCError("Error moving the timezone: %s"%e)
3160 self
.setDates( sDate
.astimezone(timezone('UTC')), \
3161 eDate
.astimezone(timezone('UTC')),
3166 ####################################
3167 # Fermi timezone awareness(end) #
3168 ####################################
3171 """returns (String) the title of the conference"""
3174 def setTitle(self
, title
):
3175 """changes the current title of the conference to the one specified"""
3176 oldTitle
= self
.title
3179 self
.cleanCategoryCache()
3180 self
.notifyModification()
3182 nameIdx
= indexes
.IndexesHolder().getIndex('conferenceTitle')
3183 nameIdx
.unindex(self
.getId())
3184 nameIdx
.index(self
.getId(), self
.getTitle().decode('utf-8'))
3186 #we notify the observers that the conference's title has changed
3188 self
._notify
('eventTitleChanged', oldTitle
, title
)
3189 except Exception, e
:
3190 Logger
.get('Conference').exception("Exception while notifying the observer of a conference title change for conference %s: %s" %
3191 (self
.getId(), str(e
)))
3194 def getDescription(self
):
3195 """returns (String) the description of the conference"""
3196 return self
.description
3198 def setDescription(self
, desc
):
3199 """changes the current description of the conference"""
3200 oldDescription
= self
.description
3201 self
.description
= desc
3202 self
._notify
('eventDescriptionChanged', oldDescription
, desc
)
3203 self
.notifyModification()
3205 def getSupportInfo(self
):
3206 if not hasattr(self
, "_supportInfo"):
3207 self
._supportInfo
= SupportInfo(self
, "Support")
3208 return self
._supportInfo
3210 def setSupportInfo(self
, supportInfo
):
3211 self
._supportInfo
= supportInfo
3213 def getChairmanText( self
):
3215 if self
.chairmanText
:
3217 except AttributeError, e
:
3218 self
.chairmanText
= ""
3219 return self
.chairmanText
3221 def setChairmanText( self
, newText
):
3222 self
.chairmanText
= newText
.strip()
3224 def appendChairmanText( self
, newText
):
3225 self
.setChairmanText( "%s, %s"%(self
.getChairmanText(), newText
.strip()) )
3226 self
._chairGen
=Counter()
3229 def _resetChairs(self
):
3233 except AttributeError:
3235 for oc
in self
.chairmans
:
3236 newChair
=ConferenceChair()
3237 newChair
.setDataFromAvatar(oc
)
3238 self
._addChair
(newChair
)
3240 def getChairList(self
):
3241 """Method returning a list of the conference chairmans (Avatars)
3246 def _addChair(self
,newChair
):
3247 for chair
in self
._chairs
:
3248 if newChair
.getEmail() != "" and newChair
.getEmail() == chair
.getEmail():
3253 except AttributeError:
3254 self
._chairGen
=Counter()
3255 id = newChair
.getId()
3257 id=int(self
._chairGen
.newCount())
3258 if isinstance(newChair
,ConferenceChair
):
3259 newChair
.includeInConference(self
,id)
3260 self
._chairs
.append(newChair
)
3261 if isinstance(newChair
, MaKaC
.user
.Avatar
):
3262 newChair
.linkTo(self
, "chair")
3263 self
.notifyModification()
3265 def addChair(self
,newChair
):
3266 """includes the specified user in the list of conference
3269 self
._addChair
(newChair
)
3271 def removeChair(self
,chair
):
3272 """removes the specified user from the list of conference
3275 if chair
not in self
._chairs
:
3277 self
._chairs
.remove(chair
)
3278 if isinstance(chair
, MaKaC
.user
.Avatar
):
3279 chair
.unlinkTo(self
, "chair")
3281 self
.notifyModification()
3283 def recoverChair(self
, ch
):
3287 def getChairById(self
,id):
3289 for chair
in self
._chairs
:
3290 if chair
.getId()==id:
3294 def getAllSessionsConvenerList(self
) :
3296 for session
in self
.getSessionList() :
3297 for convener
in session
.getConvenerList() :
3298 key
= convener
.getEmail()+" "+convener
.getFirstName().lower()+" "+convener
.getFamilyName().lower()
3299 dictionary
.setdefault(key
, set()).add(convener
)
3300 for slot
in session
.getSlotList():
3301 for convener
in slot
.getConvenerList() :
3302 key
= convener
.getEmail()+" "+convener
.getFirstName().lower()+" "+convener
.getFamilyName().lower()
3303 dictionary
.setdefault(key
, set()).add(convener
)
3307 def getContactInfo(self
):
3308 return self
.contactInfo
3310 def setContactInfo(self
, contactInfo
):
3311 self
.contactInfo
= contactInfo
3312 self
.notifyModification()
3314 def getLocationParent( self
):
3316 Returns the object from which the room/location
3317 information should be inherited.
3318 For Conferences, it's None, since they can't inherit
3323 def getLocation( self
):
3324 return self
.getOwnLocation()
3326 def getAddress( self
):
3327 if self
.getOwnLocation():
3328 return self
.getOwnLocation().getAddress()
3332 def getRoom( self
):
3333 return self
.getOwnRoom()
3335 def getLocationList(self
):
3336 """Method returning a list of "location" objects which contain the
3337 information about the different places the conference is gonna
3342 def getFavoriteRooms(self
):
3344 roomList
.extend(self
.getRoomList())
3345 #roomList.extend(map(lambda x: x._getName(), self.getBookedRooms()))
3349 def addLocation(self
, newPlace
):
3350 self
.places
.append( newPlace
)
3351 self
.notifyModification()
3353 def setAccessKey(self
, accessKey
=""):
3354 """sets the access key of the conference"""
3355 self
._accessKey
= accessKey
3356 self
.notifyModification()
3358 def getAccessKey(self
):
3360 return self
._accessKey
3361 except AttributeError:
3362 self
._accessKey
= ""
3363 return self
._accessKey
3365 def setModifKey(self
, modifKey
=""):
3366 """sets the modification key of the conference"""
3367 self
._modifKey
= modifKey
3368 self
.notifyModification()
3370 def getModifKey(self
):
3372 return self
._modifKey
3373 except AttributeError:
3375 return self
._modifKey
3377 def __generateNewSessionId( self
):
3378 """Returns a new unique identifier for the current conference sessions
3380 return str(self
.__sessionGenerator
.newCount())
3382 def addSession(self
,newSession
, check
= 2, id = None):
3383 """Adds a new session object to the conference taking care of assigning
3384 a new unique id to it
3388 1: check and raise error in case of problem
3389 2: check and adapt the owner dates"""
3391 if self
.hasSession(newSession
):
3393 if self
.getSchedule().isOutside(newSession
):
3395 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")
3397 if self
.getSchedule().getStartDate() > newSession
.getStartDate():
3398 self
.setStartDate(newSession
.getStartDate())
3399 if self
.getSchedule().getEndDate() < newSession
.getEndDate():
3400 self
.setEndDate(newSession
.getEndDate())
3404 sessionId
=self
.__generateNewSessionId
()
3405 self
.sessions
[sessionId
]=newSession
3406 newSession
.includeInConference(self
,sessionId
)
3407 #keep the session coordinator index updated
3408 for sc
in newSession
.getCoordinatorList():
3409 self
.addSessionCoordinator(newSession
,sc
)
3410 self
.notifyModification()
3412 def hasSession(self
,session
):
3413 if session
!= None and session
.getConference()==self
and \
3414 self
.sessions
.has_key(session
.getId()):
3418 def removeSession(self
,session
, deleteContributions
=False):
3419 if self
.hasSession(session
):
3420 for sc
in session
.getCoordinatorList():
3421 self
.removeSessionCoordinator(session
,sc
)
3423 if deleteContributions
:
3424 for contrib
in session
.getContributionList():
3427 del self
.sessions
[session
.getId()]
3430 self
.notifyModification()
3432 def recoverSession(self
, session
, check
, isCancelled
):
3433 self
.addSession(session
, check
, session
.getId())
3434 session
.recover(isCancelled
)
3436 def getSessionById( self
, sessionId
):
3437 """Returns the session from the conference list corresponding to the
3438 unique session id specified
3440 return self
.sessions
.get(sessionId
,None)
3442 def getRoomList(self
):
3444 for session
in self
.sessions
.values():
3445 if session
.getRoom()!=None:
3446 roomname
= session
.getRoom().getName()
3447 if roomname
not in roomList
:
3448 roomList
.append(roomname
)
3451 def getSessionList( self
):
3452 """Retruns a list of the conference session objects
3454 return self
.sessions
.values()
3456 def getSessionListSorted( self
):
3457 """Retruns a sorted list of the conference sessions
3460 for entry
in self
.getSchedule().getEntries():
3461 if isinstance(entry
,LinkedTimeSchEntry
) and \
3462 isinstance(entry
.getOwner(),SessionSlot
):
3463 session
=entry
.getOwner().getSession()
3464 if session
not in res
:
3468 def getNumberOfSessions( self
):
3469 return len(self
.sessions
)
3471 def _generateNewContributionId( self
):
3472 """Returns a new unique identifier for the current conference
3475 return str(self
.__contribGenerator
.newCount())
3477 def genNewAbstractId(self
):
3478 return str(self
.__contribGenerator
.newCount())
3480 def syncContribCounter(self
):
3481 self
.__contribGenerator
.sync(self
.getAbstractMgr()._getOldAbstractCounter
())
3482 return self
.__contribGenerator
._getCount
()
3484 def addContribution(self
,newContrib
,id=""):
3485 """Adds a new contribution object to the conference taking care of
3486 assigning a new unique id to it
3488 if self
.hasContribution(newContrib
):
3490 if isinstance(newContrib
.getCurrentStatus(),ContribStatusWithdrawn
):
3491 raise MaKaCError( _("Cannot add a contribution which has been withdrawn"), _("Event"))
3492 if id is None or id=="":
3493 contribId
=self
._generateNewContributionId
()
3494 while self
.contributions
.has_key(contribId
):
3495 contribId
=self
._generateNewContributionId
()
3498 if self
.contributions
.has_key(contribId
):
3499 raise MaKaCError( _("Cannot add this contribution id:(%s) as it has already been used")%contribId
, _("Event"))
3500 newContrib
.includeInConference(self
,contribId
)
3501 self
.contributions
[contribId
]=newContrib
3502 for auth
in newContrib
.getAuthorList():
3503 self
.indexAuthor(auth
)
3504 for spk
in newContrib
.getSpeakerList():
3505 self
.indexSpeaker(spk
)
3506 for sub
in newContrib
.getSubmitterList():
3507 self
.addContribSubmitter(newContrib
,sub
)
3509 newContrib
._notify
('created', self
)
3510 self
.notifyModification()
3512 def hasContribution(self
,contrib
):
3513 return contrib
.getConference()==self
and \
3514 self
.contributions
.has_key(contrib
.getId())
3516 def removeContribution( self
, contrib
, callDelete
=True ):
3517 if not self
.contributions
.has_key( contrib
.getId() ):
3519 for sub
in contrib
.getSubmitterList()[:]:
3520 self
.removeContribSubmitter(contrib
,sub
)
3521 for auth
in contrib
.getPrimaryAuthorList()[:]:
3522 contrib
.removePrimaryAuthor(auth
)
3523 for auth
in contrib
.getCoAuthorList()[:]:
3524 contrib
.removeCoAuthor(auth
)
3525 for spk
in contrib
.getSpeakerList()[:]:
3526 contrib
.removeSpeaker(spk
)
3527 del self
.contributions
[ contrib
.getId() ]
3532 self
.notifyModification()
3534 def recoverContribution(self
, contrib
):
3535 self
.addContribution(contrib
, contrib
.getId())
3538 # Note: this kind of factories should never be used as they only allow to
3539 # create a single type of contributions
3540 def newContribution( self
, id=None ):
3541 """Creates and returns a new contribution object already added to the
3542 conference list (all its data is set to the default)
3545 self
.addContribution( c
, id )
3548 def getOwnContributionById( self
, id ):
3549 """Returns the contribution from the conference list corresponding to
3550 the unique contribution id specified
3552 if self
.contributions
.has_key( id ):
3553 return self
.contributions
[ id ]
3556 def getContributionById( self
, id ):
3557 """Returns the contribution corresponding to the id specified
3559 return self
.contributions
.get(str(id).strip(),None)
3561 def getContributionList(self
):
3562 """Returns a list of the conference contribution objects
3564 return self
.contributions
.values()
3566 def iterContributions(self
):
3567 return self
.contributions
.itervalues()
3569 def getContributionListWithoutSessions(self
):
3570 """Returns a list of the conference contribution objects which do not have a session
3572 return [c
for c
in self
.contributions
.values() if not c
.getSession()]
3575 def getContributionListSorted(self
, includeWithdrawn
=True, key
="id"):
3576 """Returns a list of the conference contribution objects, sorted by key provided
3578 contributions
= self
.contributions
.values()
3579 if not includeWithdrawn
:
3580 contributions
= filter(lambda c
: not isinstance(c
.getCurrentStatus(), ContribStatusWithdrawn
), contributions
)
3581 contributions
.sort(key
= lambda c
: getattr(c
, key
))
3582 return contributions
3584 def getNumberOfContributions(self
, only_scheduled
=False):
3586 return len(filter(lambda c
: c
.isScheduled(), self
.contributions
.itervalues()))
3588 return len(self
.contributions
)
3590 def getProgramDescription(self
):
3592 return self
.programDescription
3594 self
.programDescription
= ""
3595 return self
.programDescription
3597 def setProgramDescription(self
, txt
):
3598 self
.programDescription
= txt
3600 def _generateNewTrackId( self
):
3603 return str(self
.__programGenerator
.newCount())
3605 def addTrack( self
, newTrack
):
3608 #XXX: The conference program shoul be isolated in a separated object
3609 if newTrack
in self
.program
:
3612 trackId
= newTrack
.getId()
3613 if trackId
== "not assigned":
3614 trackId
= self
._generateNewTrackId
()
3615 self
.program
.append( newTrack
)
3616 newTrack
.setConference( self
)
3617 newTrack
.setId( trackId
)
3618 self
.notifyModification()
3620 def removeTrack( self
, track
):
3621 if track
in self
.program
:
3623 if track
in self
.program
:
3624 self
.program
.remove( track
)
3625 self
.notifyModification()
3627 def recoverTrack(self
, track
):
3628 self
.addTrack(track
)
3631 def newTrack( self
):
3638 def getTrackById( self
, id ):
3641 for track
in self
.program
:
3642 if track
.getId() == id.strip():
3646 def getTrackList( self
):
3651 def isLastTrack(self
,track
):
3654 return self
.getTrackPos(track
)==(len(self
.program
)-1)
3656 def isFirstTrack(self
,track
):
3659 return self
.getTrackPos(track
)==0
3661 def getTrackPos(self
,track
):
3664 return self
.program
.index(track
)
3666 def moveTrack(self
,track
,newPos
):
3669 self
.program
.remove(track
)
3670 self
.program
.insert(newPos
,track
)
3671 self
.notifyModification()
3673 def moveUpTrack(self
,track
):
3676 if self
.isFirstTrack(track
):
3678 newPos
=self
.getTrackPos(track
)-1
3679 self
.moveTrack(track
,newPos
)
3681 def moveDownTrack(self
,track
):
3684 if self
.isLastTrack(track
):
3686 newPos
=self
.getTrackPos(track
)+1
3687 self
.moveTrack(track
,newPos
)
3689 def _cmpTracks( self
, t1
, t2
):
3690 o1
= self
.program
.index(t1
)
3691 o2
= self
.program
.index(t2
)
3692 return cmp( o1
, o2
)
3694 def sortTrackList( self
, l
):
3695 """Sorts out a list of tracks according to the current programme order.
3705 res
.sort( self
._cmpTracks
)
3708 def canIPAccess( self
, ip
):
3709 if not self
.__ac
.canIPAccess( ip
):
3712 # if event is inheriting, check IP protection above
3713 if self
.getAccessProtectionLevel() == 0:
3714 for owner
in self
.getOwnerList():
3715 if not owner
.canIPAccess(ip
):
3720 def requireDomain( self
, dom
):
3721 self
.__ac
.requireDomain( dom
)
3722 self
._notify
('accessDomainAdded', dom
)
3724 def freeDomain( self
, dom
):
3725 self
.__ac
.freeDomain( dom
)
3726 self
._notify
('accessDomainRemoved', dom
)
3728 def getDomainList( self
):
3729 return self
.__ac
.getRequiredDomainList()
3731 def isProtected( self
):
3732 """Tells whether a conference is protected for accessing or not
3734 return self
.__ac
.isProtected()
3736 def getAccessProtectionLevel( self
):
3737 return self
.__ac
.getAccessProtectionLevel()
3739 def isItselfProtected( self
):
3740 return self
.__ac
.isItselfProtected()
3742 def hasAnyProtection( self
):
3743 """Tells whether a conference has any kind of protection over it:
3744 access or domain protection.
3746 if self
.isProtected():
3748 if self
.getDomainList():
3751 if self
.getAccessProtectionLevel() == -1:
3754 for owner
in self
.getOwnerList():
3755 if owner
.hasAnyProtection():
3760 def hasProtectedOwner( self
):
3761 return self
.__ac
._getFatherProtection
()
3763 def setProtection( self
, private
):
3765 Allows to change the conference access protection
3768 oldValue
= 1 if self
.isProtected() else -1
3770 self
.getAccessController().setProtection( private
)
3771 self
.cleanCategoryCache()
3773 if oldValue
!= private
:
3775 self
._notify
('protectionChanged', oldValue
, private
)
3777 def grantAccess( self
, prin
):
3778 self
.__ac
.grantAccess( prin
)
3779 if isinstance(prin
, MaKaC
.user
.Avatar
):
3780 prin
.linkTo(self
, "access")
3782 def revokeAccess( self
, prin
):
3783 self
.__ac
.revokeAccess( prin
)
3784 if isinstance(prin
, MaKaC
.user
.Avatar
):
3785 prin
.unlinkTo(self
, "access")
3787 def canView( self
, aw
):
3788 """tells whether the specified access wrappers has access to the current
3789 object or any of its parts"""
3790 if self
.canAccess( aw
):
3792 for session
in self
.getSessionList():
3793 if session
.canView( aw
):
3795 for contrib
in self
.getContributionList():
3796 if contrib
.canView( aw
):
3800 def isAllowedToAccess( self
, av
):
3801 """tells if a user has privileges to access the current conference
3802 (independently that it is protected or not)
3806 if (av
in self
.getChairList()) or (self
.__ac
.canUserAccess( av
)) or (self
.canUserModify( av
)):
3809 # if the conference is not protected by itself
3810 if not self
.isItselfProtected():
3811 # then inherit behavior from parent category
3812 for owner
in self
.getOwnerList():
3813 if owner
.isAllowedToAccess( av
):
3816 # track coordinators are also allowed to access the conference
3817 for track
in self
.getTrackList():
3818 if track
.isCoordinator( av
):
3821 # paper reviewing team should be also allowed to access
3822 if self
.getConfPaperReview().isInReviewingTeam(av
):
3825 # video services managers are also allowed to access the conference
3826 if PluginsHolder().hasPluginType("Collaboration"):
3827 if self
.getCSBookingManager().isPluginManagerOfAnyPlugin(av
):
3829 from MaKaC
.webinterface
.rh
.collaboration
import RCCollaborationAdmin
, RCCollaborationPluginAdmin
3830 if RCCollaborationAdmin
.hasRights(user
=av
) or \
3831 RCCollaborationPluginAdmin
.hasRights(user
=av
, plugins
='any'):
3836 def canAccess( self
, aw
):
3837 """Tells whether an access wrapper is allowed to access the current
3838 conference: when the conference is protected, only if the user is a
3839 chair or is granted to access the conference, when the client ip is
3842 # Allow harvesters (Invenio, offline cache) to access
3844 if self
.__ac
.isHarvesterIP(aw
.getIP()):
3847 # Managers have always access
3848 if self
.canUserModify(aw
.getUser()):
3851 if self
.isProtected():
3852 if self
.isAllowedToAccess( aw
.getUser() ):
3855 return self
.canKeyAccess(aw
)
3857 # Domain control is triggered just for PUBLIC events
3858 return self
.canIPAccess(aw
.getIP())
3860 def canKeyAccess( self
, aw
, key
=None ):
3861 sess
= aw
.getSession()
3862 accessKey
= self
.getAccessKey()
3863 if accessKey
!= "" and sess
:
3864 if key
and key
== accessKey
:
3866 keys
= sess
.getVar("accessKeys")
3868 if keys
.has_key(self
.getUniqueId()):
3869 if keys
[self
.getUniqueId()] == accessKey
:
3873 def canKeyModify( self
, aw
):
3874 sess
= aw
.getSession()
3875 modifKey
= self
.getModifKey()
3876 if modifKey
!= "" and sess
:
3877 keys
= sess
.getVar("modifKeys")
3879 if keys
.has_key(self
.id):
3880 if keys
[self
.id] == modifKey
:
3884 def grantModification( self
, prin
, sendEmail
=True ):
3886 if isinstance(prin
, ConferenceChair
):
3887 email
= prin
.getEmail()
3888 elif isinstance(prin
, str):
3894 results
=ah
.match({"email":email
}, exact
=1)
3895 #No registered user in Indico with that email
3896 if len(results
) == 0:
3897 self
.__ac
.grantModificationEmail(email
)
3898 if sendEmail
and isinstance(prin
, ConferenceChair
):
3899 notif
= pendingQueues
._PendingConfManagerNotification
( [prin
] )
3900 mail
.GenericMailer
.sendAndLog( notif
, self
.getConference() )
3901 #The user is registered in Indico and is activated as well
3902 elif len(results
) == 1 and results
[0] is not None and results
[0].isActivated():
3903 self
.__ac
.grantModification(results
[0])
3904 results
[0].linkTo(self
, "manager")
3906 self
.__ac
.grantModification( prin
)
3907 if isinstance(prin
, MaKaC
.user
.Avatar
):
3908 prin
.linkTo(self
, "manager")
3910 def revokeModification( self
, prin
):
3911 self
.__ac
.revokeModification( prin
)
3912 if isinstance(prin
, MaKaC
.user
.Avatar
):
3913 prin
.unlinkTo(self
, "manager")
3915 def canUserModify( self
, av
):
3918 if ( av
== self
.getCreator()) or self
.getAccessController().canModify( av
):
3920 for owner
in self
.getOwnerList():
3921 if owner
.canUserModify( av
):
3925 def canModify( self
, aw
):
3926 """Tells whether an access wrapper is allowed to modify the current
3927 conference: only if the user is granted to modify the conference and
3928 he is accessing from an IP address which is not restricted.
3930 return self
.canUserModify( aw
.getUser() ) or self
.canKeyModify( aw
)
3932 def getManagerList( self
):
3933 return self
.__ac
.getModifierList()
3935 def addToRegistrars(self
, av
):
3936 self
.getRegistrarList().append(av
)
3937 self
.notifyModification()
3938 if isinstance(av
, MaKaC
.user
.Avatar
):
3939 av
.linkTo(self
, "registrar")
3941 def removeFromRegistrars(self
, av
):
3942 self
.getRegistrarList().remove(av
)
3943 self
.notifyModification()
3944 if isinstance(av
, MaKaC
.user
.Avatar
):
3945 av
.unlinkTo(self
, "registrar")
3947 def isRegistrar(self
, av
):
3951 return av
in self
.getRegistrarList()
3952 except AttributeError:
3955 def getRegistrarList(self
):
3957 return self
.__registrars
3958 except AttributeError:
3959 self
.__registrars
= []
3960 return self
.__registrars
3962 def canManageRegistration(self
, av
):
3963 return self
.isRegistrar(av
) or self
.canUserModify(av
)
3965 def getAllowedToAccessList( self
):
3966 return self
.__ac
.getAccessList()
3968 def addMaterial( self
, newMat
):
3969 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
3970 newMat
.setOwner( self
)
3971 self
.materials
[ newMat
.getId() ] = newMat
3972 self
.notifyModification()
3974 def removeMaterial( self
, mat
):
3975 if mat
.getId() in self
.materials
.keys():
3977 self
.materials
[mat
.getId()].setOwner(None)
3978 del self
.materials
[ mat
.getId() ]
3979 self
.notifyModification()
3980 elif mat
.getId().lower() == 'paper':
3982 self
.notifyModification()
3983 elif mat
.getId().lower() == 'slides':
3985 self
.notifyModification()
3986 elif mat
.getId().lower() == 'minutes':
3987 self
.removeMinutes()
3988 self
.notifyModification()
3989 elif mat
.getId().lower() == 'video':
3991 self
.notifyModification()
3992 elif mat
.getId().lower() == 'poster':
3994 self
.notifyModification()
3996 def recoverMaterial(self
, recMat
):
3997 # Id must already be set in recMat.
3998 recMat
.setOwner(self
)
3999 self
.materials
[recMat
.getId()] = recMat
4001 self
.notifyModification()
4003 def getMaterialRegistry(self
):
4005 Return the correct material registry for this type
4007 from MaKaC
.webinterface
.materialFactories
import ConfMFRegistry
4008 return ConfMFRegistry
4010 def getMaterialById( self
, matId
):
4011 if matId
.lower() == 'paper':
4012 return self
.getPaper()
4013 elif matId
.lower() == 'slides':
4014 return self
.getSlides()
4015 elif matId
.lower() == 'video':
4016 return self
.getVideo()
4017 elif matId
.lower() == 'poster':
4018 return self
.getPoster()
4019 elif matId
.lower() == 'minutes':
4020 return self
.getMinutes()
4021 elif self
.materials
.has_key(matId
):
4022 return self
.materials
[ matId
]
4025 def getMaterialList( self
):
4026 return self
.materials
.values()
4028 def getAllMaterialList(self
, sort
=True):
4029 l
= self
.getMaterialList()
4031 l
.append( self
.getPaper() )
4032 if self
.getSlides():
4033 l
.append( self
.getSlides() )
4035 l
.append( self
.getVideo() )
4036 if self
.getPoster():
4037 l
.append( self
.getPoster() )
4038 if self
.getMinutes():
4039 l
.append( self
.getMinutes() )
4041 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
4044 def _getMaterialFiles(self
, material
):
4046 Adaption of _getMaterialFiles in WPTPLConferenceDisplay for desired format, objects
4047 seemed mutually exclusive hence use of similar logic here specific to Conference.
4052 for res
in material
.getResourceList():
4054 ftype
= res
.getFileType()
4055 fname
= res
.getFileName()
4056 furl
= urlHandlers
.UHFileAccess
.getURL(res
)
4058 if fname
in processed
:
4059 fname
= "%s - %s" % (fname
, processed
.count(fname
))
4061 processed
.append(res
.getFileName())
4063 # If we are here then the resource is a Link object.
4064 fname
, ftype
, furl
= str(res
.getURL()), "link", str(res
.getURL())
4065 fdesc
= res
.getDescription()
4066 files
.append({'title': fname
,
4067 'description': fdesc
,
4072 def getAllMaterialDict(self
, child
=None):
4074 This method iterates through the children of the conference, creating
4075 a dictionary which maps type to material link URLs.
4078 child
= self
if child
is None else child
4081 node
['title'] = child
.getTitle()
4084 node
['type'] = child
.getType()
4086 # If we land here, it's a session which doesn't have 'getType'
4087 node
['type'] = 'session'
4089 node
['children'] = []
4090 node
['material'] = []
4092 if node
['type'] in ['conference', 'meeting']:
4093 for session
in child
.getSessionList():
4094 node
['children'].append(self
.getAllMaterialDict(session
))
4096 for contrib
in child
.getContributionList():
4097 node
['children'].append(self
.getAllMaterialDict(contrib
))
4099 for material
in child
.getAllMaterialList():
4100 files
= self
._getMaterialFiles
(material
)
4104 materialNode
['type'] = 'material'
4105 materialNode
['title'] = material
.getTitle()
4107 if material
.getTitle() != 'Minutes':
4108 materialNode
['title'] += ' - ' + f
['title']
4110 materialNode
['materialType'] = f
['type']
4111 materialNode
['url'] = str(f
['url'])
4113 node
['material'].append(materialNode
)
4117 def setPaper( self
, newPaper
):
4118 if self
.getPaper() != None:
4119 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
4121 self
.paper
.setOwner( self
)
4122 self
.notifyModification()
4124 def removePaper( self
):
4125 if self
.paper
is None:
4128 self
.paper
.setOwner(None)
4130 self
.notifyModification()
4132 def recoverPaper(self
, p
):
4136 def getPaper( self
):
4140 except AttributeError:
4144 def setSlides( self
, newSlides
):
4145 if self
.getSlides() != None:
4146 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
4147 self
.slides
=newSlides
4148 self
.slides
.setOwner( self
)
4149 self
.notifyModification()
4151 def removeSlides( self
):
4152 if self
.slides
is None:
4154 self
.slides
.delete()
4155 self
.slides
.setOwner( None )
4157 self
.notifyModification()
4159 def recoverSlides(self
, s
):
4163 def getSlides( self
):
4167 except AttributeError:
4171 def setVideo( self
, newVideo
):
4172 if self
.getVideo() != None:
4173 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
4175 self
.video
.setOwner( self
)
4176 self
.notifyModification()
4178 def removeVideo( self
):
4179 if self
.getVideo() is None:
4182 self
.video
.setOwner(None)
4184 self
.notifyModification()
4186 def recoverVideo(self
, v
):
4190 def getVideo( self
):
4194 except AttributeError:
4198 def setPoster( self
, newPoster
):
4199 if self
.getPoster() != None:
4200 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
4201 self
.poster
=newPoster
4202 self
.poster
.setOwner( self
)
4203 self
.notifyModification()
4205 def removePoster( self
):
4206 if self
.getPoster() is None:
4208 self
.poster
.delete()
4209 self
.poster
.setOwner(None)
4211 self
.notifyModification()
4213 def recoverPoster(self
, p
):
4217 def getPoster( self
):
4221 except AttributeError:
4225 def setMinutes( self
, newMinutes
):
4226 if self
.getMinutes() != None:
4227 raise MaKaCError( _("The Minutes for this conference has already been set"))
4228 self
.minutes
=newMinutes
4229 self
.minutes
.setOwner( self
)
4230 self
.notifyModification()
4232 def createMinutes( self
):
4233 if self
.getMinutes() != None:
4234 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
4235 self
.minutes
= Minutes()
4236 self
.minutes
.setOwner( self
)
4237 self
.notifyModification()
4240 def removeMinutes( self
):
4241 if self
.getMinutes() is None:
4243 self
.minutes
.delete()
4244 self
.minutes
.setOwner( None )
4246 self
.notifyModification()
4248 def recoverMinutes(self
, min):
4249 self
.removeMinutes() # To ensure that the current minutes are put in
4252 self
.minutes
.setOwner( self
)
4254 self
.notifyModification()
4257 def getMinutes( self
):
4262 except AttributeError, e
:
4266 def _setSchedule( self
, sch
=None ):
4267 self
.__schedule
=ConferenceSchedule(self
)
4268 for session
in self
.getSessionList():
4269 for slot
in session
.getSlotList():
4270 self
.__schedule
.addEntry(slot
.getConfSchEntry())
4272 def getSchedule( self
):
4274 if not self
.__schedule
:
4276 except AttributeError, e
:
4278 return self
.__schedule
4281 sch
= self
.getSchedule()
4283 sDate
= sch
.calculateStartDate()
4284 eDate
= sch
.calculateEndDate()
4285 self
.setStartDate(sDate
)
4286 self
.setEndDate(eDate
)
4288 def fitSlotsOnDay( self
, day
):
4289 for entry
in self
.getSchedule().getEntriesOnDay(day
) :
4290 if isinstance(entry
.getOwner(), SessionSlot
) :
4291 entry
.getOwner().fit()
4293 def getDisplayMgr(self
):
4295 Return the display manager for the conference
4297 from MaKaC
.webinterface
import displayMgr
4298 return displayMgr
.ConfDisplayMgrRegistery().getDisplayMgr(self
)
4300 def getDefaultStyle( self
):
4301 return self
.getDisplayMgr().getDefaultStyle()
4303 def clone( self
, startDate
, options
, eventManager
=None, userPerformingClone
= None ):
4304 # startDate must be in the timezone of the event (to avoid problems with daylight-saving times)
4305 cat
= self
.getOwnerList()[0]
4306 managing
= options
.get("managing",None)
4307 if managing
is not None:
4310 creator
= self
.getCreator()
4311 conf
= cat
.newConference(creator
)
4312 if managing
is not None :
4313 conf
.grantModification(managing
)
4314 conf
.setTitle(self
.getTitle())
4315 conf
.setDescription(self
.getDescription())
4316 conf
.setTimezone(self
.getTimezone())
4317 for loc
in self
.getLocationList():
4319 conf
.addLocation(loc
.clone())
4320 if self
.getRoom() is not None:
4321 conf
.setRoom(self
.getRoom().clone())
4322 startDate
= timezone(self
.getTimezone()).localize(startDate
).astimezone(timezone('UTC'))
4323 timeDelta
= startDate
- self
.getStartDate()
4324 endDate
= self
.getEndDate() + timeDelta
4325 conf
.setDates( startDate
, endDate
, moveEntries
=1 )
4326 conf
.setContactInfo(self
.getContactInfo())
4327 conf
.setChairmanText(self
.getChairmanText())
4328 conf
.setVisibility(self
.getVisibility())
4329 conf
.setSupportInfo(self
.getSupportInfo().clone(self
))
4330 conf
.setReportNumberHolder(self
.getReportNumberHolder().clone(self
))
4331 for ch
in self
.getChairList():
4332 conf
.addChair(ch
.clone())
4333 ContextManager
.setdefault("clone.unique_id_map", {})[self
.getUniqueId()] = conf
.getUniqueId()
4335 from MaKaC
.webinterface
import displayMgr
4336 selfDispMgr
=displayMgr
.ConfDisplayMgrRegistery().getDisplayMgr(self
)
4337 selfDispMgr
.clone(conf
)
4338 # Contribution Types' List (main detailes of the conference)
4339 for t
in self
.getContribTypeList() :
4340 conf
.addContribType(t
.clone(conf
))
4341 for item
in self
.getSections() :
4342 conf
._sections
.append(item
)
4343 if options
.get("sessions", False):
4344 for entry
in self
.getSchedule().getEntries():
4345 if isinstance(entry
,BreakTimeSchEntry
):
4346 conf
.getSchedule().addEntry(entry
.clone(conf
))
4347 db_root
= DBMgr
.getInstance().getDBConnection().root()
4348 if db_root
.has_key( "webfactoryregistry" ):
4349 confRegistry
= db_root
["webfactoryregistry"]
4351 confRegistry
= OOBTree
.OOBTree()
4352 db_root
["webfactoryregistry"] = confRegistry
4354 # if the event is a meeting or a lecture
4355 if confRegistry
.get(str(self
.getId()), None) is not None :
4357 confRegistry
[str(conf
.getId())] = confRegistry
[str(self
.getId())]
4358 # if it's a conference, no web factory is needed
4359 # Tracks in a conference
4360 if options
.get("tracks",False) :
4361 for tr
in self
.getTrackList() :
4362 conf
.addTrack(tr
.clone(conf
))
4363 # Meetings' and conferences' sessions cloning
4364 if options
.get("sessions",False) :
4365 for s
in self
.getSessionList() :
4366 newSes
= s
.clone(timeDelta
, conf
, options
)
4367 ContextManager
.setdefault("clone.unique_id_map", {})[s
.getUniqueId()] = newSes
.getUniqueId()
4368 conf
.addSession(newSes
)
4369 # Materials' cloning
4370 if options
.get("materials",False) :
4371 for m
in self
.getMaterialList() :
4372 conf
.addMaterial(m
.clone(conf
))
4373 if self
.getPaper() is not None:
4374 conf
.setPaper(self
.getPaper().clone(conf
))
4375 if self
.getSlides() is not None:
4376 conf
.setSlides(self
.getSlides().clone(conf
))
4377 if self
.getVideo() is not None:
4378 conf
.setVideo(self
.getVideo().clone(conf
))
4379 if self
.getPoster() is not None:
4380 conf
.setPoster(self
.getPoster().clone(conf
))
4381 if self
.getMinutes() is not None:
4382 conf
.setMinutes(self
.getMinutes().clone(conf
))
4383 # access and modification keys
4384 if options
.get("keys", False) :
4385 conf
.setAccessKey(self
.getAccessKey())
4386 conf
.setModifKey(self
.getModifKey())
4387 # Access Control cloning
4388 if options
.get("access",False) :
4389 conf
.setProtection(self
.getAccessController()._getAccessProtection
())
4390 for mgr
in self
.getManagerList() :
4391 conf
.grantModification(mgr
)
4392 for user
in self
.getAllowedToAccessList() :
4393 conf
.grantAccess(user
)
4394 for right
in self
.getSessionCoordinatorRights():
4395 conf
.addSessionCoordinatorRight(right
)
4396 for domain
in self
.getDomainList():
4397 conf
.requireDomain(domain
)
4398 # conference's registration form
4399 if options
.get("registration",False) :
4400 conf
.setRegistrationForm(self
.getRegistrationForm().clone(conf
))
4402 # conference's evaluation
4403 if options
.get("evaluation",False) :
4404 #Modify this, if you have now many evaluations.
4405 #You will have to clone every evaluations of this conference.
4406 conf
.setEvaluations([self
.getEvaluation().clone(conf
)])
4408 #conference's abstracts
4409 if options
.get("abstracts",False) :
4410 conf
.abstractMgr
= self
.abstractMgr
.clone(conf
)
4411 # conference's alerts
4412 if options
.get("alerts",False) :
4413 for alarm
in self
.getAlarmList() :
4414 # for absoulte alarms, only clone alarms that will happen in the future
4415 if alarm
._relative
is not None or alarm
.getStartOn() > nowutc():
4416 # .clone takes care of enqueuing it
4418 # Meetings' and conferences' contributions cloning
4419 if options
.get("contributions",False) :
4420 sch
= conf
.getSchedule()
4421 for cont
in self
.getContributionList():
4422 if cont
.getSession() is None :
4424 nc
= cont
.clone(conf
, options
, timeDelta
)
4425 conf
.addContribution(nc
)
4426 if cont
.isScheduled() :
4427 sch
.addEntry(nc
.getSchEntry())
4428 ContextManager
.setdefault("clone.unique_id_map", {})[cont
.getUniqueId()] = nc
.getUniqueId()
4429 elif cont
.isScheduled():
4430 # meetings...only scheduled
4431 nc
= cont
.clone(conf
, options
, timeDelta
)
4432 conf
.addContribution(nc
)
4433 sch
.addEntry(nc
.getSchEntry())
4434 ContextManager
.setdefault("clone.unique_id_map", {})[cont
.getUniqueId()] = nc
.getUniqueId()
4435 # Participants' module settings and list cloning
4436 if options
.get("participants",False) :
4437 self
.getParticipation().clone(conf
, options
, eventManager
)
4438 conf
.notifyModification()
4440 #we inform the plugins in case they want to add anything to the new conference
4441 self
._notify
('cloneEvent', {'conf': conf
, 'user': userPerformingClone
, 'options': options
})
4444 def newAlarm(self
, when
, enqueue
=True):
4446 if type(when
) == timedelta
:
4453 confRelId
= self
._getNextAlarmId
()
4454 al
= tasks
.AlarmTask(self
, confRelId
,
4455 startDateTime
=dtStart
,
4458 self
.addAlarm(al
, enqueue
)
4461 def removeAlarm(self
, alarm
):
4462 confRelId
= alarm
.getConfRelativeId()
4464 if confRelId
in self
.alarmList
:
4465 del self
.alarmList
[confRelId
]
4471 raise Exception("alarm not in list!")
4473 def _getNextAlarmId(self
):
4474 return self
.__alarmCounter
.newCount()
4476 def addAlarm(self
, alarm
, enqueue
= True):
4481 self
.alarmList
[alarm
.getConfRelativeId()] = alarm
4484 def recoverAlarm(self
, alarm
):
4485 self
.addAlarm(alarm
)
4489 def getAlarmList(self
):
4490 return self
.alarmList
.values()
4492 def getAlarmById(self
, id):
4493 """For given id returns corresponding Alarm or None if not found."""
4494 return self
.alarmList
.get(id, None)
4496 def getCoordinatedTracks( self
, av
):
4497 """Returns a list with the tracks for which a user is coordinator.
4500 if self
._trackCoordinators
:
4502 except AttributeError:
4503 self
._trackCoordinators
= TCIndex()
4504 self
.notifyModification()
4505 return self
._trackCoordinators
.getTracks( av
)
4507 def addTrackCoordinator( self
, track
, av
):
4508 """Makes a user become coordinator for a track.
4511 if self
._trackCoordinators
:
4513 except AttributeError:
4514 self
._trackCoordinators
= TCIndex()
4515 self
.notifyModification()
4516 if track
in self
.program
:
4517 track
.addCoordinator( av
)
4518 self
._trackCoordinators
.indexCoordinator( av
, track
)
4519 self
.notifyModification()
4521 def removeTrackCoordinator( self
, track
, av
):
4522 """Removes a user as coordinator for a track.
4525 if self
._trackCoordinators
:
4527 except AttributeError:
4528 self
._trackCoordinators
= TCIndex()
4529 self
.notifyModification()
4530 if track
in self
.program
:
4531 track
.removeCoordinator( av
)
4532 self
._trackCoordinators
.unindexCoordinator( av
, track
)
4533 self
.notifyModification()
4535 def _rebuildAuthorIndex(self
):
4536 self
._authorIdx
=AuthorIndex()
4537 for contrib
in self
.getContributionList():
4538 if not isinstance(contrib
.getCurrentStatus(),ContribStatusWithdrawn
):
4539 for auth
in contrib
.getAuthorList():
4540 self
._authorIdx
.index(auth
)
4542 def getAuthorIndex(self
):
4546 except AttributeError:
4547 self
._rebuildAuthorIndex
()
4548 return self
._authorIdx
4550 def indexAuthor(self
,auth
):
4551 c
=auth
.getContribution()
4552 if c
.isAuthor(auth
):
4553 if not isinstance(c
.getCurrentStatus(),ContribStatusWithdrawn
):
4554 self
.getAuthorIndex().index(auth
)
4555 if c
.isPrimaryAuthor(auth
):
4556 self
._getPrimAuthIndex
().index(auth
)
4558 def unindexAuthor(self
,auth
):
4559 c
=auth
.getContribution()
4560 if c
.isAuthor(auth
):
4561 self
.getAuthorIndex().unindex(auth
)
4562 if c
.isPrimaryAuthor(auth
):
4563 self
._getPrimAuthIndex
().unindex(auth
)
4565 def _rebuildSpeakerIndex(self
):
4566 self
._speakerIdx
=AuthorIndex()
4567 for contrib
in self
.getContributionList():
4568 if not isinstance(contrib
.getCurrentStatus(),ContribStatusWithdrawn
):
4569 for auth
in contrib
.getSpeakerList():
4570 self
._speakerIdx
.index(auth
)
4571 for subcontrib
in contrib
.getSubContributionList():
4572 for auth
in subcontrib
.getSpeakerList():
4573 self
._speakerIdx
.index(auth
)
4575 def getSpeakerIndex(self
):
4577 if self
._speakerIdx
:
4579 except AttributeError:
4580 self
._rebuildSpeakerIndex
()
4581 return self
._speakerIdx
4583 def indexSpeaker(self
,auth
):
4584 c
=auth
.getContribution()
4585 if not isinstance(c
.getCurrentStatus(),ContribStatusWithdrawn
):
4586 self
.getSpeakerIndex().index(auth
)
4588 def unindexSpeaker(self
,auth
):
4589 c
=auth
.getContribution()
4590 if c
and not isinstance(c
.getCurrentStatus(),ContribStatusWithdrawn
):
4591 self
.getSpeakerIndex().unindex(auth
)
4593 def getRegistrationForm(self
):
4595 if self
._registrationForm
is None:
4596 self
._registrationForm
= registration
.RegistrationForm(self
)
4597 except AttributeError,e
:
4598 self
._registrationForm
= registration
.RegistrationForm(self
)
4599 return self
._registrationForm
4601 def setRegistrationForm(self
,rf
):
4602 self
._registrationForm
= rf
4603 rf
.setConference(self
)
4605 def removeRegistrationForm(self
):
4607 self
._registrationForm
.delete()
4608 self
._registrationForm
.setConference(None)
4609 self
._registrationForm
= None
4610 except AttributeError:
4611 self
._registrationForm
= None
4613 def recoverRegistrationForm(self
, rf
):
4614 self
.setRegistrationForm(rf
)
4617 def getEvaluation(self
, id=0):
4618 ############################################################################
4619 #For the moment only one evaluation per conference is used. #
4620 #In the future if there are more than one evaluation, modify this function.#
4621 ############################################################################
4622 """ Return the evaluation given by its ID or None if nothing found.
4624 id -- id of the wanted evaluation
4626 for evaluation
in self
.getEvaluations():
4627 if str(evaluation
.getId()) == str(id) :
4629 if HelperMaKaCInfo
.getMaKaCInfoInstance().isDebugActive():
4630 raise Exception(_("Error with id: expected '%s', found '%s'.")%(id, self
.getEvaluations()[0].getId()))
4632 return self
.getEvaluations()[0]
4634 def getEvaluations(self
):
4635 if not hasattr(self
, "_evaluations"):
4636 self
._evaluations
= [Evaluation(self
)]
4637 return self
._evaluations
4639 def setEvaluations(self
, evaluationsList
):
4640 self
._evaluations
= evaluationsList
4641 for evaluation
in self
._evaluations
:
4642 evaluation
.setConference(self
)
4644 def removeEvaluation(self
, evaluation
):
4645 """remove the given evaluation from its evaluations."""
4646 evaluations
= self
.getEvaluations()
4647 if evaluations
.count(evaluation
)>0:
4648 evaluations
.remove(evaluation
)
4649 evaluation
.removeReferences()
4650 self
.notifyModification()
4652 def removeAllEvaluations(self
):
4653 for evaluation
in self
.getEvaluations():
4654 evaluation
.removeReferences()
4655 self
._evaluations
= []
4656 self
.notifyModification()
4658 def _getEvaluationCounter(self
):
4659 if not hasattr(self
, "_evaluationCounter"):
4660 self
._evaluationCounter
= Counter()
4661 return self
._evaluationCounter
4663 ## Videoconference bookings related
4664 def getBookings(self
):
4668 except AttributeError, e
:
4670 self
.notifyModification()
4671 return self
._bookings
4673 def getBookingsList(self
, sort
= False):
4674 bl
= self
.getBookings().values()
4679 def _getBookingGenerator(self
):
4681 return self
._bookingGenerator
4682 except AttributeError, e
:
4683 self
._bookingGenerator
= Counter()
4684 return self
._bookingGenerator
4686 def getNewBookingId(self
):
4687 return str(self
._getBookingGenerator
().newCount())
4689 def addBooking(self
, bp
):
4690 if (bp
.getId() == ""):
4691 bp
.setId(self
.getNewBookingId())
4692 self
.getBookings()[bp
.getId()] = bp
4693 self
.notifyModification()
4695 def hasBooking(self
,booking
):
4696 return booking
.getConference()==self
and \
4697 self
.getBookings().has_key(booking
.getId())
4699 def removeBooking(self
, booking
):
4700 if self
.hasBooking(booking
):
4701 deletion
= booking
.deleteBooking()
4702 if deletion
[0] != 1:
4703 del self
.getBookings()[booking
.getId()]
4704 self
.notifyModification()
4707 def getBookingByType(self
, type):
4708 if self
.getBookings().has_key(type):
4709 return self
.getBookings()[type]
4712 def getBookingById(self
, id):
4713 if self
.getBookings().has_key(id):
4714 return self
.getBookings()[id]
4717 ## End of Videoconference bookings related
4719 def getModPay(self
):
4721 if self
._modPay
is None:
4722 self
._modPay
= epayment
.EPayment(self
)
4723 except AttributeError,e
:
4724 self
._modPay
= epayment
.EPayment(self
)
4727 def getRegistrants(self
):
4729 if self
._registrants
:
4731 except AttributeError, e
:
4732 self
._registrants
= {}
4733 self
.notifyModification()
4734 return self
._registrants
4736 def getRegistrantsByEmail(self
):
4738 if self
._registrantsByEmail
:
4740 except AttributeError, e
:
4741 self
._registrantsByEmail
= self
._createRegistrantsByEmail
()
4742 self
.notifyModification()
4743 return self
._registrantsByEmail
4745 def _createRegistrantsByEmail(self
):
4747 for r
in self
.getRegistrantsList():
4748 dicByEmail
[r
.getEmail()] = r
4751 def getRegistrantsList(self
, sort
= False):
4752 rl
= self
.getRegistrants().values()
4754 rl
.sort(registration
.Registrant
._cmpFamilyName
)
4757 def _getRegistrantGenerator(self
):
4759 return self
._registrantGenerator
4760 except AttributeError, e
:
4761 self
._registrantGenerator
= Counter()
4762 return self
._registrantGenerator
4764 def addRegistrant(self
, rp
, user
):
4765 rp
.setId( str(self
._getRegistrantGenerator
().newCount()) )
4767 self
.getRegistrants()[rp
.getId()] = rp
4768 self
._notify
('registrantAdded', user
)
4769 self
.notifyModification()
4771 def updateRegistrantIndexByEmail(self
, rp
, newEmail
):
4772 oldEmail
= rp
.getEmail()
4773 if oldEmail
!= newEmail
:
4774 if self
.getRegistrantsByEmail().has_key(oldEmail
):
4775 del self
.getRegistrantsByEmail()[oldEmail
]
4776 self
.getRegistrantsByEmail()[newEmail
] = rp
4777 self
.notifyModification()
4779 def hasRegistrant(self
,rp
):
4780 return rp
.getConference()==self
and \
4781 self
.getRegistrants().has_key(rp
.getId())
4783 def hasRegistrantByEmail(self
, email
):
4784 # Return true if there is someone with the email of the param "email"
4785 return self
.getRegistrantsByEmail().has_key(email
)
4787 def removeRegistrant(self
, id):
4788 part
= self
.getRegistrants()[id]
4789 self
._registrationForm
.notifyRegistrantRemoval(self
.getRegistrants()[id])
4790 del self
.getRegistrantsByEmail()[self
.getRegistrantById(id).getEmail()]
4791 del self
.getRegistrants()[id]
4792 if part
.getAvatar() is not None:
4793 part
.getAvatar().removeRegistrant(part
)
4794 self
._notify
('registrantRemoved', part
)
4795 TrashCanManager().add(part
)
4796 self
.notifyModification()
4798 def getRegistrantById(self
, id):
4799 if self
.getRegistrants().has_key(id):
4800 return self
.getRegistrants()[id]
4803 def _getPrimAuthIndex(self
):
4805 if self
._primAuthIdx
:
4807 except AttributeError:
4808 self
._primAuthIdx
=_PrimAuthIdx(self
)
4809 return self
._primAuthIdx
4811 def getContribsMatchingAuth(self
,query
,onlyPrimary
=True):
4812 if str(query
).strip()=="":
4813 return self
.getContributionList()
4814 res
=self
._getPrimAuthIndex
().match(query
)
4815 return [self
.getContributionById(id) for id in res
]
4817 def getCoordinatedSessions( self
, av
):
4818 """Returns a list with the sessions for which a user is coordinator.
4821 if self
._sessionCoordinators
:
4823 except AttributeError:
4824 self
._sessionCoordinators
= SCIndex()
4825 sessions
= self
._sessionCoordinators
.getSessions( av
)
4826 for session
in self
.getSessionList():
4827 if session
not in sessions
and av
!= None:
4828 for email
in av
.getEmails():
4829 if email
in session
.getCoordinatorEmailList():
4830 sessions
.append(session
)
4834 def getManagedSession( self
, av
):
4836 for session
in self
.getSessionList():
4839 for email
in av
.getEmails():
4840 if email
in session
.getAccessController().getModificationEmail():
4843 if av
in session
.getManagerList() or pending
:
4847 def addSessionCoordinator(self
,session
,av
):
4848 """Makes a user become coordinator for a session.
4851 if self
._sessionCoordinators
:
4853 except AttributeError:
4854 self
._sessionCoordinators
= SCIndex()
4855 if self
.sessions
.has_key(session
.getId()):
4856 session
.addCoordinator(av
)
4857 self
._sessionCoordinators
.index(av
,session
)
4859 def removeSessionCoordinator( self
, session
, av
):
4860 """Removes a user as coordinator for a session.
4863 if self
._sessionCoordinators
:
4865 except AttributeError:
4866 self
._sessionCoordinators
= SCIndex()
4867 if self
.sessions
.has_key(session
.getId()):
4868 session
.removeCoordinator( av
)
4869 self
._sessionCoordinators
.unindex(av
,session
)
4871 def _getSubmitterIdx(self
):
4873 return self
._submitterIdx
4874 except AttributeError:
4875 self
._submitterIdx
=SubmitterIndex()
4876 return self
._submitterIdx
4878 def addContribSubmitter(self
,contrib
,av
):
4879 self
._getSubmitterIdx
().index(av
,contrib
)
4881 def removeContribSubmitter(self
,contrib
,av
):
4882 self
._getSubmitterIdx
().unindex(av
,contrib
)
4884 def getContribsForSubmitter(self
,av
):
4885 return self
._getSubmitterIdx
().getContributions(av
)
4887 def getBOAConfig(self
):
4891 except AttributeError:
4892 self
._boa
=BOAConfig(self
)
4895 def getSessionCoordinatorRights(self
):
4897 if self
._sessionCoordinatorRights
:
4899 except AttributeError, e
:
4900 self
._sessionCoordinatorRights
= []
4901 self
.notifyModification()
4902 return self
._sessionCoordinatorRights
4904 def hasSessionCoordinatorRight(self
, right
):
4905 return right
in self
.getSessionCoordinatorRights()
4907 def addSessionCoordinatorRight(self
, right
):
4908 if SessionCoordinatorRights().hasRight(right
) and not self
.hasSessionCoordinatorRight(right
):
4909 self
._sessionCoordinatorRights
.append(right
)
4910 self
.notifyModification()
4912 def removeSessionCoordinatorRight(self
, right
):
4913 if SessionCoordinatorRights().hasRight(right
) and self
.hasSessionCoordinatorRight(right
):
4914 self
._sessionCoordinatorRights
.remove(right
)
4915 self
.notifyModification()
4917 def getSections(self
):
4921 except AttributeError, e
:
4922 self
._sections
= ConfSectionsMgr().getSectionKeys()
4923 self
.notifyModification()
4924 return self
._sections
4926 def hasEnabledSection(self
, section
):
4927 # This hack is there since there is no more enable/disable boxes
4928 # in the conference managment area corresponding to those features.
4929 # Until the managment area is improved to get a more user-friendly
4930 # way of enabling/disabling those features, we always make them
4931 # available for the time being, but we keep the previous code for
4932 # further improvements
4935 def enableSection(self
, section
):
4936 if ConfSectionsMgr().hasSection(section
) and not self
.hasEnabledSection(section
):
4937 self
._sections
.append(section
)
4938 self
.notifyModification()
4940 def disableSection(self
, section
):
4941 if ConfSectionsMgr().hasSection(section
) and self
.hasEnabledSection(section
):
4942 self
._sections
.remove(section
)
4943 self
.notifyModification()
4945 def getPendingQueuesMgr(self
):
4947 if self
._pendingQueuesMgr
:
4949 except AttributeError, e
:
4950 self
._pendingQueuesMgr
=pendingQueues
.ConfPendingQueuesMgr(self
)
4951 return self
._pendingQueuesMgr
4953 def getAccessController(self
):
4956 def _cmpTitle( c1
, c2
):
4957 o1
= c1
.getTitle().lower().strip()
4958 o2
= c2
.getTitle().lower().strip()
4959 return cmp( o1
, o2
)
4960 _cmpTitle
=staticmethod(_cmpTitle
)
4962 def getReportNumberHolder(self
):
4964 if self
._reportNumberHolder
:
4966 except AttributeError, e
:
4967 self
._reportNumberHolder
=ReportNumberHolder(self
)
4968 return self
._reportNumberHolder
4970 def setReportNumberHolder(self
, rnh
):
4971 self
._reportNumberHolder
=rnh
4973 def getBadgeTemplateManager(self
):
4975 if self
.__badgeTemplateManager
:
4977 except AttributeError:
4978 self
.__badgeTemplateManager
= BadgeTemplateManager(self
)
4979 return self
.__badgeTemplateManager
4981 def setBadgeTemplateManager(self
, badgeTemplateManager
):
4982 self
.__badgeTemplateManager
= badgeTemplateManager
4984 def getPosterTemplateManager(self
):
4986 if self
.__posterTemplateManager
:
4988 except AttributeError:
4989 self
.__posterTemplateManager
= PosterTemplateManager(self
)
4991 return self
.__posterTemplateManager
4993 def setPosterTemplateManager(self
, posterTemplateManager
):
4994 self
.__posterTemplateManager
= posterTemplateManager
4996 def getCSBookingManager(self
):
4998 if PluginsHolder().hasPluginType("Collaboration"):
4999 if not hasattr(self
, "_CSBookingManager"):
5000 from MaKaC
.plugins
.Collaboration
.base
import CSBookingManager
5001 self
._CSBookingManager
= CSBookingManager(self
)
5002 return self
._CSBookingManager
5007 class DefaultConference(Conference
):
5008 """ 'default' conference, which stores the
5009 default templates for posters and badges
5012 def indexConf(self
):
5016 """ Default constructor
5019 Conference
.__init
__(self
, AdminList
.getInstance().getList()[0], "default")
5021 raise MaKaCError(_("""There are no admin users. The "default" conference that stores the template cannot be created.
5022 Please add at least 1 user to the admin list."""))
5025 class ConferenceHolder( ObjectHolder
):
5026 """Specialised ObjectHolder dealing with conference objects. It gives a
5027 common entry point and provides simple methods to access and
5028 maintain the collection of stored conferences (DB).
5030 idxName
= "conferences"
5031 counterName
= "CONFERENCE"
5034 id = ObjectHolder
._newId
( self
)
5037 def getById( self
, id, quiet
=False ):
5038 """returns an object from the index which id corresponds to the one
5042 if (id == "default"):
5043 return CategoryManager().getDefaultConference()
5047 if self
._getIdx
().has_key(str(id)):
5048 return self
._getIdx
()[str(id)]
5052 raise NoReportError( _("The specified event with id \"%s\" does not exist or has been deleted.") % escape_html(str(id)) )
5054 class ConfSectionsMgr
:
5058 "cfa": "Call for abstracts",
5059 "paperReviewing" : "Paper Reviewing",
5060 "evaluation": "Evaluation Form",
5061 "videoconference": "Videoconference", # only for meetings
5062 "collaboration": "Collaboration", # only for meetings
5063 "regForm": "Registration Form"
5066 def hasSection(self
, s
):
5067 # This hack is there since there is no more enable/disable boxes
5068 # in the conference managment area corresponding to those features.
5069 # Until the managment area is improved to get a more user-friendly
5070 # way of enabling/disabling those features, we always make them
5071 # available in the side menu for the time being, but we keep
5072 # the previous code for further improvements
5073 #return self._sections.has_key(s)
5076 def getSections(self
):
5077 return self
._sections
5079 def getSectionList(self
, sort
=False):
5080 l
=self
._sections
.values()
5085 def getSectionKeys(self
, sort
=False):
5086 l
=self
._sections
.keys()
5091 def getSection(self
, id):
5092 if self
._sections
.has_key(id):
5093 return self
._sections
[id]
5097 class Observer(object):
5098 """ Base class for Observer objects.
5099 Inheriting classes should overload the following boolean class attributes:
5100 _shouldBeTitleNotified
5101 _shouldBeDateChangeNotified
5102 _shouldBeLocationChangeNotified
5103 _shouldBeDeletionNotified
5104 And set them to True if they want to be notified of the corresponding event.
5105 In that case, they also have to implement the corresponding methods:
5106 _notifyTitleChange (for title notification)
5107 _notifyEventDateChanges and _notifyTimezoneChange (for date / timezone notification)
5108 _shouldBeLocationChangeNotified (for location notification)
5109 _notifyDeletion (for deletion notification).
5110 The interface for those methods is also specified in this class. If the corresponding
5111 class attribute is set to False but the method is not implemented, an exception will be thrown.
5113 _shouldBeTitleNotified
= False
5114 _shouldBeDateChangeNotified
= False
5115 _shouldBeLocationChangeNotified
= False
5116 _shouldBeDeletionNotified
= False
5118 def getObserverName(self
):
5119 name
= "'Observer of class" + self
.__class
__.__name
__
5121 conf
= self
.getOwner()
5122 name
= name
+ " of event " + conf
.getId() + "'"
5123 except AttributeError:
5127 def notifyTitleChange(self
, oldTitle
, newTitle
):
5128 if self
._shouldBeTitleNotified
:
5129 self
._notifyTitleChange
(oldTitle
, newTitle
)
5131 def notifyEventDateChanges(self
, oldStartDate
= None, newStartDate
= None, oldEndDate
= None, newEndDate
= None):
5132 if self
._shouldBeDateChangeNotified
:
5133 self
._notifyEventDateChanges
(oldStartDate
, newStartDate
, oldEndDate
, newEndDate
)
5135 def notifyTimezoneChange(self
, oldTimezone
, newTimezone
):
5136 if self
._shouldBeDateChangeNotified
:
5137 self
._notifyTimezoneChange
(oldTimezone
, newTimezone
)
5139 def notifyLocationChange(self
, newLocation
):
5140 if self
._shouldBeLocationChangeNotified
:
5141 self
._notifyLocationChange
(newLocation
)
5143 def notifyDeletion(self
):
5144 if self
._shouldBeDeletionNotified
:
5145 self
._notifyDeletion
()
5147 def _notifyTitleChange(self
, oldTitle
, newTitle
):
5148 """ To be implemented by inheriting classes
5149 Notifies the observer that the Conference object's title has changed
5151 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method _notifyTitleChange")
5153 def _notifyEventDateChanges(self
, oldStartDate
, newStartDate
, oldEndDate
, newEndDate
):
5154 """ To be implemented by inheriting classes
5155 Notifies the observer that the start and / or end dates of the object it is attached to has changed.
5156 If the observer finds any problems during whatever he needs to do as a consequence of
5157 the event dates changing, he should write strings describing the problems
5158 in the 'dateChangeNotificationProblems' context variable (which is a list of strings).
5160 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyStartDateChange")
5162 def _notifyTimezoneChange(self
, oldTimezone
, newTimezone
):
5163 """ To be implemented by inheriting classes.
5164 Notifies the observer that the end date of the object it is attached to has changed.
5165 This method has to return a list of strings describing problems encountered during
5166 whatever the DateChangeObserver object does as a consequence of the notification.
5167 If there are no problems, the DateChangeObserver should return an empty list.
5169 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyTimezoneChange")
5171 def _notifyLocationChange(self
):
5172 """ To be implemented by inheriting classes
5173 Notifies the observer that the location of the object it is attached to has changed.
5175 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyLocationChange")
5177 def _notifyDeletion(self
):
5178 """ To be implemented by inheriting classes
5179 Notifies the observer that the Conference object it is attached to has been deleted
5181 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyDeletion")
5183 class TitleChangeObserver(Observer
):
5184 """ Base class for objects who want to be notified of a Conference object being deleted.
5185 Inheriting classes have to implement the notifyTitleChange method, and probably the __init__ method too.
5188 def notifyTitleChange(self
, oldTitle
, newTitle
):
5189 """ To be implemented by inheriting classes
5190 Notifies the observer that the Conference object's title has changed
5192 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyTitleChange")
5195 class SessionChair(ConferenceParticipation
):
5200 ConferenceParticipation
.__init
__(self
)
5202 def _notifyModification( self
):
5203 if self
._session
!= None:
5204 self
._session
.notifyModification()
5207 chair
= SessionChair()
5208 chair
.setValues(self
.getValues())
5211 def getSession(self
):
5212 return self
._session
5214 def getConference(self
):
5218 return s
.getConference()
5220 def includeInSession(self
,session
,id):
5221 if self
.getSession()==session
and self
.getId()==id.strip():
5223 self
._session
=session
5228 ConferenceParticipation
.delete(self
)
5230 def getLocator(self
):
5231 if self
.getSession() is None:
5233 loc
=self
.getSession().getLocator()
5234 loc
["convId"]=self
.getId()
5237 def isSessionManager(self
):
5239 if self
.getEmail() in self
._session
.getAccessController().getModificationEmail():
5242 for manager
in self
._session
.getManagerList():
5243 if self
.getEmail() == manager
.getEmail():
5247 def isSessionCoordinator(self
):
5248 # pendings coordinators
5249 if self
.getEmail() in self
._session
.getConference().getPendingQueuesMgr().getPendingCoordinatorsKeys():
5252 for coord
in self
._session
.getCoordinatorList():
5253 if self
.getEmail() == coord
.getEmail():
5258 class SlotChair(ConferenceParticipation
):
5263 ConferenceParticipation
.__init
__(self
)
5265 def _notifyModification( self
):
5266 if self
._slot
!= None:
5267 self
._slot
.notifyModification()
5271 chair
.setValues(self
.getValues())
5277 def getSession(self
):
5281 return s
.getSession()
5283 def getConference(self
):
5287 return s
.getConference()
5289 def includeInSlot(self
,slot
,id):
5290 if self
.getSlot()==slot
and self
.getId()==id.strip():
5297 ConferenceParticipation
.delete(self
)
5299 def getLocator(self
):
5300 if self
.getSlot() is None:
5302 loc
=self
.getSlot().getLocator()
5303 loc
["convId"]=self
.getId()
5306 class SessionCoordinatorRights
:
5309 self
._rights
= {"modifContribs": "Modify the contributions",
5310 "unrestrictedSessionTT": "Unrestricted session timetable management"
5313 def hasRight(self
, r
):
5314 return self
._rights
.has_key(r
)
5316 def getRights(self
):
5319 def getRightList(self
, sort
=False):
5320 l
=self
._rights
.values()
5325 def getRightKeys(self
):
5326 return self
._rights
.keys()
5328 def getRight(self
, id):
5329 if self
._rights
.has_key(id):
5330 return self
._rights
[id]
5333 class SCIndex(Persistent
):
5334 """Index for conference session coordinators.
5336 This class allows to index conference session coordinators so the owner
5337 can answer optimally to the query if a user is coordinating
5338 any conference session.
5339 It is implemented by simply using a BTree where the Avatar id is used
5340 as key (because it is unique and non variable) and a list of
5341 coordinated sessions is kept as keys. It is the responsability of the
5342 index owner (conference) to keep it up-to-date i.e. notify session
5343 coordinator additions and removals.
5346 def __init__( self
):
5350 def getSessions(self
,av
):
5351 """Gives a list with the sessions a user is coordinating.
5355 return self
._idx
.get(av
.getId(),[])
5357 def index(self
,av
,session
):
5358 """Registers in the index a coordinator of a session.
5360 if av
== None or session
== None:
5362 if not self
._idx
.has_key(av
.getId()):
5364 self
._idx
[av
.getId()]=l
5366 l
=self
._idx
[av
.getId()]
5367 if session
not in l
:
5369 self
.notifyModification()
5371 def unindex(self
,av
,session
):
5372 if av
==None or session
==None:
5374 l
=self
._idx
.get(av
.getId(),[])
5377 self
.notifyModification()
5379 def notifyModification(self
):
5380 self
._idx
._p
_changed
=1
5383 class Session(CommonObjectBase
, Locatable
):
5384 """This class implements a conference session, being the different parts
5385 in which the conference can be divided and the contributions can be
5386 organised in. The class contains necessary attributes to store session
5387 basic data and provides the operations related to sessions. In
5388 principle, a session has no sense to exist without being related to a
5389 conference but it is allowed for flexibility.
5392 fossilizes(ISessionFossil
)
5395 def __init__(self
, **sessionData
):
5396 """Class constructor. Initialise the class attributes to the default
5399 sessionData -- (Dict) Contains the data the session object has to
5402 self
.conference
=None
5403 self
.id="not assigned"
5406 #################################
5407 # Fermi timezone awareness #
5408 #################################
5409 self
.startDate
= nowutc()
5410 #################################
5411 # Fermi timezone awareness(end) #
5412 #################################
5414 self
.duration
=timedelta(minutes
=1)
5417 self
.conveners
=[] # This attribute must not be used and should disappear someday
5419 self
._convenerGen
=Counter()
5420 self
.convenerText
=""
5421 self
.contributions
={}
5422 self
._contributionDuration
=timedelta(minutes
=20)
5423 self
.__ac
=AccessController(self
)
5425 self
.__materialGenerator
=Counter()
5429 self
.__slotGenerator
=Counter()
5431 self
._coordinators
=OOBTree()
5432 self
._coordinatorsEmail
= []
5434 self
._color
="#e3f2d3"
5435 self
._textColor
="#202020"
5436 self
._textColorToLinks
=False
5437 self
._ttType
=SlotSchTypeFactory
.getDefaultId()
5438 self
._closed
= False
5439 self
._registrationSession
= None
5440 self
._creationDS
= nowutc()
5441 self
._modificationDS
= nowutc()
5444 def __cmp__(self
, other
):
5445 if type(self
) is not type(other
):
5446 # This is actually dangerous and the ZODB manual says not to do this
5447 # because it relies on memory order. However, this branch should never
5448 # be taken anyway since we do not store different types in the same set
5449 # or use them as keys.
5450 return cmp(hash(self
), hash(other
))
5451 if self
.getConference() == other
.getConference():
5452 return cmp(self
.getId(), other
.getId())
5453 return cmp(self
.getConference(), other
.getConference())
5455 def getTimezone( self
):
5456 return self
.getConference().getTimezone()
5458 def updateNonInheritingChildren(self
, elem
, delete
=False, propagate
=True):
5459 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
5460 if propagate
== True:
5461 self
.notify_protection_to_owner(elem
, delete
)
5463 def notify_protection_to_owner(self
, elem
, delete
=False):
5464 """ This methods notifies the owner that the protection has been changed,
5465 so it can update its list of non inheriting children """
5466 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
5468 def getKeywords(self
):
5470 return self
._keywords
5475 def setKeywords(self
, keywords
):
5476 self
._keywords
= keywords
5478 def notifyModification( self
, raiseEvent
= True, date
= None, cleanCache
= True ):
5479 """Method called to notify the current session has been modified.
5481 self
.setModificationDate(date
)
5483 parent
= self
.getConference()
5485 parent
.setModificationDate(date
)
5487 for slot
in self
.getSlotList():
5491 def getModificationDate( self
):
5492 """Returns the date in which the session was last modified"""
5494 return self
._modificationDS
5496 self
._modificationDS
= nowutc()
5497 return self
._modificationDS
5499 def getCreationDate( self
):
5500 """Returns the date in which the session was created"""
5502 return self
._creationDS
5504 self
._creationDS
= nowutc()
5505 return self
._creationDS
5507 def getLogInfo(self
):
5509 data
["subject"] = self
.title
5510 data
["session id"] = self
.id
5511 data
["session code"] = self
._code
5512 data
["title"] = self
.title
5513 data
["description"] = self
.description
5514 data
["start date"] = self
.startDate
5515 data
["duration"] = self
.duration
5516 for p
in self
.places
:
5517 data
["place"] = p
.getName()
5518 for r
in self
.rooms
:
5519 data
["room"] = r
.getName()
5520 for sc
in self
.getConvenerList() :
5521 data
["convener %s"%sc.getId()] = sc
.getFullName()
5522 for co
in self
.getCoordinatorList() :
5523 data
["coordinators %s"%co.getId()] = co
.getFullName()
5527 def getEnableSessionSlots(self
):
5529 return self
.getConference().getEnableSessionSlots()
5533 def cmpSessionByTitle(session1
, session2
):
5534 return cmp(session1
.getTitle(), session2
.getTitle())
5535 cmpSessionByTitle
= staticmethod(cmpSessionByTitle
)
5537 def hasRegistrationSession(self
):
5538 return self
.getRegistrationSession() is not None
5540 def getRegistrationSession(self
):
5542 if self
._registrationSession
:
5544 except AttributeError, e
:
5545 self
._registrationSession
= None
5546 return self
._registrationSession
5548 def setRegistrationSession(self
, rs
):
5549 self
._registrationSession
= rs
5551 def isClosed( self
):
5552 if self
.getConference().isClosed():
5557 self
._closed
= False
5560 def setClosed( self
, closed
=True ):
5561 self
._closed
= closed
5562 self
.notifyModification(cleanCache
= False)
5564 def includeInConference(self
,conf
,newId
):
5565 self
.conference
=conf
5567 for slot
in self
.getSlotList():
5568 conf
.getSchedule().addEntry(slot
.getConfSchEntry(),2)
5569 self
.getConference().addSession(self
)
5570 self
.notifyModification()
5573 while len(self
.getConvenerList()) > 0:
5574 self
.removeConvener(self
.getConvenerList()[0])
5575 while len(self
.getMaterialList()) > 0:
5576 self
.removeMaterial(self
.getMaterialList()[0])
5577 self
.removeMinutes()
5578 for c
in self
.getCoordinatorList()[:]:
5579 self
.removeCoordinator(c
)
5580 while len(self
.contributions
.values())>0:
5581 self
.removeContribution(self
.contributions
.values()[0])
5582 while len(self
.slots
.values())>0:
5583 self
._removeSlot
(self
.slots
.values()[0])
5584 if self
.getConference() is not None:
5585 self
.getConference().removeSession(self
)
5586 if self
.hasRegistrationSession():
5587 self
.getConference().getRegistrationForm().getSessionsForm().removeSession(self
.getId())
5588 self
.getRegistrationSession().setRegistrationForm(None)
5589 TrashCanManager().add(self
.getRegistrationSession())
5590 self
.notify_protection_to_owner(self
, delete
=True)
5591 self
.conference
=None
5592 TrashCanManager().add(self
)
5594 def recover(self
, isCancelled
):
5595 if self
.hasRegistrationSession():
5597 self
.getRegistrationSession().setRegistrationForm(self
.getConference().getRegistrationForm())
5598 self
.getConference().getRegistrationForm().getSessionsForm().addSession(self
.getRegistrationSession())
5599 TrashCanManager().remove(self
.getRegistrationSession())
5600 TrashCanManager().remove(self
)
5602 def getLocator( self
):
5603 """Gives back a globaly unique identification encapsulated in a Locator
5604 object for the session instance
5606 if self
.conference
== None:
5608 lconf
= self
.conference
.getLocator()
5609 lconf
["sessionId"] = self
.getId()
5612 def getConference( self
):
5613 return self
.conference
5615 def getSession( self
):
5618 def getOwner( self
):
5619 return self
.getConference()
5624 def getUniqueId( self
):
5625 """returns (string) the unique identiffier of the item"""
5626 """used mainly in the web session access key table"""
5627 return "%ss%s" % (self
.getConference().getUniqueId(),self
.id)
5629 def getModifKey( self
):
5630 return self
.getConference().getModifKey()
5632 def getAccessKey( self
):
5633 return self
.getConference().getAccessKey()
5635 def getContribDuration(self
):
5637 return self
._contributionDuration
5639 self
._contributionDuration
= timedelta(minutes
=20)
5640 return self
._contributionDuration
5642 def setContribDuration(self
, hour
=0, min=20, dur
=None):
5644 self
._contributionDuration
=dur
5646 self
._contributionDuration
= timedelta(hours
=hour
,minutes
=min)
5649 #if not self.getConference().getEnableSessionSlots():
5650 # self.getSlotList()[0].fit()
5651 self
.setStartDate(self
.getMinSlotStartDate(),0,0)
5652 self
.setEndDate(self
.getMaxSlotEndDate(),0)
5654 def addSlot(self
,newSlot
):
5655 id = newSlot
.getId()
5656 if id == "not assigned":
5657 newSlot
.setId(str(self
.__slotGenerator
.newCount()))
5658 self
.slots
[newSlot
.getId()]=newSlot
5660 self
.getSchedule().addEntry(newSlot
.getSessionSchEntry(),2)
5661 if self
.getConference() is not None:
5662 self
.getConference().getSchedule().addEntry(newSlot
.getConfSchEntry(),2)
5663 self
.notifyModification()
5665 def _removeSlot(self
,slot
):
5666 del self
.slots
[slot
.getId()]
5667 self
.getSchedule().removeEntry(slot
.getSessionSchEntry())
5668 if self
.getConference() is not None:
5669 self
.getConference().getSchedule().removeEntry(slot
.getConfSchEntry())
5672 def removeSlot(self
, slot
, force
=False):
5673 if self
.slots
.has_key(slot
.getId()):
5674 if len(self
.slots
)==1 and not force
:
5675 raise MaKaCError( _("A session must have at least one slot"), _("Session"))
5676 self
._removeSlot
(slot
)
5678 self
.notifyModification()
5680 def recoverSlot(self
, slot
):
5684 def getSlotById(self
,slotId
):
5685 return self
.slots
.get(slotId
,None)
5687 def getSlotList(self
):
5688 return self
.slots
.values()
5690 def getSortedSlotList(self
):
5691 sl
= self
.getSlotList()
5692 sl
.sort(utils
.sortSlotByDate
)
5695 def getMinSlotStartTime(self
):
5697 for slot
in self
.getSlotList():
5698 if slot
.isMoreThanDay():
5700 shour
= slot
.getStartDate().hour
5701 smin
= slot
.getStartDate().minute
5702 if (shour
, smin
) < min:
5706 def getMaxSlotEndTime(self
):
5708 for slot
in self
.getSlotList():
5709 if slot
.isMoreThanDay():
5711 endDate
= slot
.getEndDate()
5712 if (endDate
.hour
, endDate
.minute
) > max:
5713 newEndDate
= endDate
- timedelta(0, 0, 0)
5714 max = (newEndDate
.hour
, newEndDate
.minute
)
5717 def getMinSlotStartDate(self
):
5718 slotList
= self
.getSlotList()
5719 if len(slotList
)==0:
5720 return self
.getStartDate()
5722 sDate
= self
.getEndDate()
5723 for slot
in slotList
:
5724 if slot
.getStartDate() < sDate
:
5725 sDate
= slot
.getStartDate()
5728 def getMaxSlotEndDate(self
):
5729 slotList
= self
.getSlotList()
5730 if len(slotList
)==0:
5731 return self
.getEndDate()
5733 eDate
= self
.getStartDate()
5734 for slot
in slotList
:
5735 if slot
.getEndDate() > eDate
:
5736 eDate
= slot
.getEndDate()
5739 def _getCorrectColor(self
, color
):
5740 if not color
.startswith("#"):
5742 m
= re
.match("^#[0-9A-Fa-f]{6}$", color
)
5747 def _getCorrectBgColor(self
, color
):
5748 color
=self
._getCorrectColor
(color
)
5753 def _getCorrectTextColor(self
, color
):
5754 color
=self
._getCorrectColor
(color
)
5756 return self
._textColor
5759 def setValues( self
, sessionData
,check
=2,moveEntries
=0 ):
5760 """Sets all the values of the current session object from a dictionary
5761 containing the following key-value pairs:
5764 locationName-(str) => name of the location, if not specified
5765 it will be set to the conference location name.
5766 locationAddress-(str)
5767 roomName-(str) => name of the room, if not specified it will
5768 be set to the conference room name.
5769 sDate - (datetime) => starting date of the session, if not
5770 specified it will be set to now.
5771 eDate - (datetime) => ending date of the session, if not
5772 specified the end date will be set to the start one
5773 durHour - (int) => hours of duration for each entry in the session
5775 durMin - (int) => hours of duration for each entry in the session
5780 1: check and raise error in case of problem
5781 2: check and adapt the owner dates
5782 Please, note that this method sets ALL values which means that if
5783 the given dictionary doesn't contain any of the keys the value
5784 will set to a default value.
5787 self
.setTitle( sessionData
.get("title", "NO TITLE ASSIGNED") )
5788 self
.setDescription( sessionData
.get("description", "") )
5789 code
= sessionData
.get("code", "")
5790 if code
.strip() == "":
5791 if self
.getId()=="not assigned":
5792 self
.setCode("no code")
5794 self
.setCode(self
.getId())
5797 bgcolor
= sessionData
.get("backgroundColor", "")
5798 if bgcolor
.strip() != "":
5799 self
.setColor(self
._getCorrectBgColor
(bgcolor
))
5800 textcolor
= sessionData
.get("textColor", "")
5801 if textcolor
.strip() != "":
5802 if sessionData
.has_key("autotextcolor"):
5803 self
.setTextColor(utils
.getTextColorFromBackgroundColor(self
.getColor()))
5805 self
.setTextColor(self
._getCorrectTextColor
(textcolor
))
5806 self
.setTextColorToLinks(sessionData
.has_key("textcolortolinks"))
5808 if "locationName" in sessionData
:
5809 loc
= self
.getOwnLocation()
5811 loc
= CustomLocation()
5812 self
.setLocation( loc
)
5813 loc
.setName( sessionData
["locationName"] )
5814 loc
.setAddress( sessionData
.get("locationAddress", "") )
5816 self
.setLocation(None)
5818 #same as for the location
5819 if "roomName" in sessionData
:
5820 room
= self
.getOwnRoom()
5823 self
.setRoom( room
)
5824 room
.setName( sessionData
["roomName"] )
5828 if sessionData
.get("sDate",None) is not None:
5829 self
.setStartDate(sessionData
["sDate"],check
,moveEntries
=moveEntries
)
5830 if sessionData
.get("eDate",None) is not None:
5831 self
.setEndDate(sessionData
["eDate"],check
)
5832 self
._checkInnerSchedule
()
5833 if sessionData
.get("contribDuration","")!="":
5834 self
._contributionDuration
= sessionData
.get("contribDuration")
5836 self
._contributionDuration
= timedelta(hours
=int(sessionData
.get("durHour",0)), minutes
=int(sessionData
.get("durMin",20)))
5837 self
.notifyModification()
5839 def move(self
, sDate
):
5841 Move a session from the old start date to a new start date, and
5842 it moves all the entries of the session as well, without date validations.
5844 if sDate
is not None:
5845 oldStartDate
=self
.startDate
5846 self
.startDate
=copy
.copy(sDate
)
5847 diff
=self
.startDate
-oldStartDate
5848 # Check date to not be prior conference start date and to not surpass conference end date
5849 # The schedule is returning the datetime object as timezone aware relative to the conference
5850 # timezone. Must adjust the startdate accordingly for comparison. JMF
5851 conftz
= self
.getConference().getTimezone()
5852 if self
.getStartDate() < self
.getConference().getSchedule().getStartDate() or \
5853 self
.getEndDate() > self
.getConference().getSchedule().getEndDate():
5854 raise MaKaCError( _("Impossible to move the session because it would be out of the conference dates"))
5855 for entry
in self
.getSchedule().getEntries():
5856 if isinstance(entry
,LinkedTimeSchEntry
) and \
5857 isinstance(entry
.getOwner(), SessionSlot
):
5858 e
= entry
.getOwner()
5859 e
.move(e
.getStartDate() + diff
)
5860 self
.getSchedule().reSchedule()
5861 self
.getConference().getSchedule().reSchedule()
5862 self
.notifyModification()
5864 def clone(self
, deltaTime
, conf
, options
):
5866 conf
.addSession(ses
,check
=0)
5867 ses
.setTitle(self
.getTitle())
5868 ses
.setDescription(self
.getDescription())
5869 startDate
= self
.getStartDate() + deltaTime
5870 ses
.setStartDate(startDate
, check
=1)
5871 ses
.setDuration(dur
=self
.getDuration())
5873 if self
.getOwnLocation() is not None:
5874 ses
.addLocation(self
.getOwnLocation().clone())
5875 if self
.getOwnRoom() is not None:
5876 ses
.setRoom(self
.getOwnRoom().clone())
5877 ses
.setColor(self
.getColor())
5878 ses
.setTextColor(self
.getTextColor())
5879 ses
.setTextColorToLinks(self
.isTextColorToLinks())
5880 ses
.setCode(self
.getCode())
5881 ses
.setContribDuration(dur
=self
.getContribDuration())
5882 ses
.setScheduleType(self
.getScheduleType())
5883 ses
.setComments(self
.getComments())
5885 # Access Control cloning
5886 if options
.get("access", False) :
5887 ses
.setProtection(self
.getAccessController()._getAccessProtection
())
5888 for mgr
in self
.getManagerList() :
5889 ses
.grantModification(mgr
)
5890 for user
in self
.getAllowedToAccessList() :
5891 ses
.grantAccess(user
)
5892 for domain
in self
.getDomainList():
5893 ses
.requireDomain(domain
)
5894 for coord
in self
.getCoordinatorList():
5895 ses
.addCoordinator(coord
)
5897 #slots in timeschedule
5898 for slot
in self
.getSlotList() :
5899 newslot
= slot
.clone(ses
, options
)
5900 ses
.addSlot(newslot
)
5901 ContextManager
.setdefault("clone.unique_id_map", {})[slot
.getUniqueId()] = newslot
.getUniqueId()
5903 ses
.notifyModification()
5908 def setTitle( self
, newTitle
):
5909 self
.title
= newTitle
5910 self
.notifyModification()
5912 def getTitle( self
):
5915 def setDescription(self
, newDescription
):
5916 self
.description
= newDescription
5917 self
.notifyModification()
5919 def getDescription(self
):
5920 return self
.description
5926 except AttributeError:
5930 def setCode(self
,newCode
):
5931 self
._code
=str(newCode
).strip()
5937 except AttributeError:
5938 self
._color
="#e3f2d3"
5942 def setColor(self
,newColor
):
5943 self
._color
=str(newColor
).strip()
5944 self
.notifyModification()
5947 def getTextColor(self
):
5951 except AttributeError:
5952 self
._textColor
="#202020"
5953 return self
._textColor
5955 def setTextColor(self
,newColor
):
5956 self
._textColor
=str(newColor
).strip()
5957 self
.notifyModification()
5959 def isTextColorToLinks(self
):
5961 if self
._textColorToLink
:
5963 except AttributeError:
5964 self
._textColorToLink
=False
5965 return self
._textColorToLink
5967 def setTextColorToLinks(self
, v
):
5968 self
._textColorToLink
=v
5969 self
.notifyModification()
5971 def getStartDate(self
):
5972 return self
.startDate
5974 def getAdjustedStartDate(self
,tz
=None):
5976 tz
= self
.getConference().getTimezone()
5977 if tz
not in all_timezones
:
5979 return self
.startDate
.astimezone(timezone(tz
))
5981 def verifyStartDate(self
, sdate
, check
=2):
5984 1: check and raise error in case of problem (default)
5985 2: check and adapt the owner dates
5988 conf
=self
.getConference()
5990 if conf
is not None and sdate
< conf
.getSchedule().getStartDate():
5992 raise ParentTimingError( _("The session starting date cannot be prior to the event starting date"), _("Session"))
5994 ContextManager
.get('autoOps').append((self
, "OWNER_START_DATE_EXTENDED",
5995 conf
, sdate
.astimezone(timezone(conf
.getTimezone()))))
5996 conf
.setStartDate(sdate
,check
=0,moveEntries
=0)
5998 def setStartDate(self
,newDate
,check
=2,moveEntries
=0):
6000 moveEntries parameter:
6001 0: do not move inner slots
6003 2: do not move but check that session is not out of the conference dates
6006 if not newDate
.tzname():
6007 raise MaKaCError("date should be timezone aware")
6009 self
.verifyStartDate(newDate
,check
)
6010 oldSdate
= self
.getStartDate()
6012 tz
= str(self
.getStartDate().tzinfo
)
6015 diff
= newDate
- oldSdate
6016 self
.startDate
=copy
.copy(newDate
)
6017 if moveEntries
== 1 and diff
is not None and diff
!= timedelta(0):
6018 # If the start date changed, we move entries inside the timetable
6019 newDateTz
= newDate
.astimezone(timezone(tz
))
6020 if oldSdate
.astimezone(timezone(tz
)).date() != newDateTz
.date():
6021 entries
= self
.getSchedule().getEntries()[:]
6023 entries
= self
.getSchedule().getEntriesOnDay(newDateTz
)[:]
6024 self
.getSchedule().moveEntriesBelow(diff
, entries
)
6026 if moveEntries
!= 0 and self
.getConference() and \
6027 not self
.getConference().getEnableSessionSlots() and \
6028 self
.getSlotList() != [] and \
6029 self
.getSlotList()[0].getStartDate() != newDate
:
6030 self
.getSlotList()[0].startDate
= newDate
6033 self
._checkInnerSchedule
()
6034 self
.notifyModification()
6036 def _checkInnerSchedule( self
):
6037 self
.getSchedule().checkSanity()
6039 def getEndDate(self
):
6040 return self
.startDate
+self
.duration
6042 ####################################
6043 # Fermi timezone awareness #
6044 ####################################
6046 def getAdjustedEndDate(self
,tz
=None):
6047 return self
.getAdjustedStartDate(tz
) + self
.duration
6049 ####################################
6050 # Fermi timezone awareness(end) #
6051 ####################################
6053 def verifyEndDate(self
, edate
,check
=1):
6056 1: check and raise error in case of problem
6057 2: check and adapt the owner dates
6060 tz
= timezone(self
.getConference().getTimezone())
6062 tz
= timezone('UTC')
6063 # compare end date with start date
6064 if edate
<=self
.getStartDate():
6066 raise MaKaCError( _("End date cannot be prior to the Start date"), _("Session"))
6068 self
.setStartDate(edate
)
6069 # check conference dates
6070 if (self
.getConference()):
6071 conf
=self
.getConference()
6072 confStartDate
= conf
.getSchedule().getStartDate()
6073 confEndDate
= conf
.getSchedule().getEndDate()
6074 if conf
is not None and (edate
>confEndDate
or edate
<=confStartDate
):
6076 raise ParentTimingError( _("The end date has to be between the event dates (%s - %s)")%\
6077 (confStartDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
6078 confEndDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
6081 if edate
>confEndDate
:
6082 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
6083 self
.getConference(),
6084 edate
.astimezone(tz
)))
6085 self
.getConference().setEndDate(edate
)
6086 if edate
<=confStartDate
:
6087 ContextManager
.get('autoOps').append((self
, "OWNER_START_DATE_EXTENDED",
6088 self
.getConference(),
6089 edate
.astimezone(tz
)))
6090 self
.getConference().setStartDate(edate
)
6091 # check inner schedule
6092 if len(self
.getSlotList()) != 0 and self
.getSlotList()[-1].getSchedule().hasEntriesAfter(edate
):
6093 raise TimingError( _("Cannot change end date: some entries in the session schedule end after the new date"), _("Session"))
6095 def setEndDate(self
,newDate
,check
=2):
6096 if not newDate
.tzname():
6097 raise MaKaCError("date should be timezone aware")
6099 self
.verifyEndDate(newDate
,check
)
6100 self
.duration
=newDate
-self
.getStartDate()
6101 # A session is not always linked to a conference (for eg. at creation time)
6102 #if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSlotList()[0].getEndDate() != newDate:
6103 # self.getSlotList()[0].duration = self.duration
6104 self
.notifyModification()
6106 def setDates(self
,sDate
,eDate
,check
=1,moveEntries
=0):
6108 tz
= timezone(self
.getConference().getTimezone())
6109 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"))
6110 self
.setStartDate(sDate
,check
,moveEntries
)
6111 self
.setEndDate(eDate
,check
)
6112 self
._checkInnerSchedule
()
6114 def getDuration( self
):
6115 return self
.duration
6117 def setDuration(self
,hours
=0,minutes
=15,dur
=0):
6119 dur
= timedelta(hours
=int(hours
),minutes
=int(minutes
))
6120 if dur
.seconds
<= 0:
6121 raise MaKaCError( _("The duration cannot be less than zero"), _("Session"))
6123 self
.verifyEndDate(self
.getEndDate())
6124 self
.notifyModification()
6126 def getStartOnDay(self
, day
, tz
=None):
6128 tz
= self
.getConference().getTimezone()
6129 if type(day
) is datetime
:
6130 day
= day
.astimezone(timezone(tz
))
6131 if day
.date() < self
.getStartDate().astimezone(timezone(tz
)).date() or day
.date() > self
.getEndDate().astimezone(timezone(tz
)).date() :
6133 minTime
= self
.getEndDate()
6134 for e
in self
.getSchedule().getEntriesOnDay(day
) :
6135 if e
.getStartDate() < minTime
:
6136 minTime
= e
.getStartDate()
6137 if minTime
== self
.getEndDate() :
6138 minTime
= day
.replace(hour
=8, minute
=0)#datetime.combine(day,time(hour=8, minute=0))
6139 if minTime
< self
.getStartDate() :
6140 return self
.getStartDate()
6143 def getEndOnDay(self
, day
, tz
=None):
6145 tz
= self
.getConference().getTimezone()
6146 if type(day
) is datetime
:
6147 day
= day
.astimezone(timezone(tz
))
6148 if day
.date() < self
.getStartDate().astimezone(timezone(tz
)).date() or day
.date() > self
.getEndDate().astimezone(timezone(tz
)).date() :
6150 maxTime
= self
.getStartDate();
6151 for e
in self
.getSchedule().getEntriesOnDay(day
) :
6152 if e
.getEndDate() > maxTime
:
6153 maxTime
= e
.getEndDate()
6154 if maxTime
== self
.getStartDate() :
6155 maxTime
= day
.replace(hour
=19, minute
=0)#datetime.combine(day,time(19,0))
6156 if maxTime
> self
.getEndDate() :
6157 return self
.getEndDate()
6160 def getLocationParent( self
):
6162 Returns the object from which the room/location
6163 information should be inherited
6165 return self
.getConference()
6167 def getLocationList(self
):
6168 """Method returning a list of "location" objects which contain the
6169 information about the different places the conference is gonna
6174 def addLocation(self
, newPlace
):
6175 self
.places
.append( newPlace
)
6176 self
.notifyModification()
6178 def _resetConveners(self
):
6182 except AttributeError:
6184 for oc
in self
.conveners
:
6185 newConv
=SessionChair()
6186 newConv
.setDataFromAvatar(oc
)
6187 self
._addConvener
(newConv
)
6189 def getConvenerList(self
):
6190 self
._resetConveners
()
6191 return self
._conveners
6193 def getAllConvenerList(self
):
6194 convenerList
= set()
6195 for slot
in self
.getSlotList():
6196 for convener
in slot
.getConvenerList():
6197 convenerList
.add(convener
)
6200 def _addConvener(self
,newConv
):
6201 if newConv
in self
._conveners
:
6204 if self
._convenerGen
:
6206 except AttributeError:
6207 self
._convenerGen
=Counter()
6208 id = newConv
.getId()
6210 id=int(self
._convenerGen
.newCount())
6211 newConv
.includeInSession(self
,id)
6212 self
._conveners
.append(newConv
)
6213 self
.notifyModification()
6215 def addConvener(self
,newConv
):
6216 self
._resetConveners
()
6217 self
._addConvener
(newConv
)
6218 if isinstance(newConv
, MaKaC
.user
.Avatar
):
6219 conv
.unlinkTo(self
, "convener")
6221 def removeConvener(self
,conv
):
6222 self
._resetConveners
()
6223 if conv
not in self
._conveners
:
6225 #--Pending queue: remove pending Convener waiting to became manager if anything
6226 self
.getConference().getPendingQueuesMgr().removePendingManager(conv
)
6228 #--Pending queue: remove pending Convener waiting to became coordinator if anything
6229 self
.getConference().getPendingQueuesMgr().removePendingCoordinator(conv
)
6231 self
._conveners
.remove(conv
)
6232 if isinstance(conv
, MaKaC
.user
.Avatar
):
6233 conv
.linkTo(self
, "convener")
6235 self
.notifyModification()
6237 def recoverConvener(self
, con
):
6238 self
.addConvener(con
)
6241 def getConvenerById(self
,id):
6243 for conv
in self
._conveners
:
6244 if conv
.getId()==id:
6248 def getConvenerText( self
):
6251 if self
.convenerText
:
6253 except AttributeError, e
:
6254 self
.convenerText
= ""
6255 return self
.convenerText
6257 def setConvenerText( self
, newText
):
6258 self
.convenerText
= newText
.strip()
6260 def appendConvenerText( self
, newText
):
6261 self
.setConvenerText( "%s, %s"%(self
.getConvenerText(), newText
.strip()) )
6263 def addContribution(self
, newContrib
, id=None):
6264 """Registers the contribution passed as parameter within the session
6265 assigning it a unique id.
6267 if self
.hasContribution(newContrib
):
6269 self
.getConference().addContribution(newContrib
,id)
6270 self
.contributions
[newContrib
.getId()]=newContrib
6271 newContrib
.setSession(self
)
6273 self
.updateNonInheritingChildren(newContrib
)
6274 for child
in newContrib
.getAccessController().getNonInheritingChildren():
6275 self
.updateNonInheritingChildren(child
)
6277 self
.notifyModification()
6279 def hasContribution(self
,contrib
):
6280 return contrib
.getSession()==self
and \
6281 self
.contributions
.has_key(contrib
.getId())
6283 def removeContribution(self
,contrib
):
6284 """Removes the indicated contribution from the session
6286 if not self
.hasContribution(contrib
):
6288 if contrib
.isScheduled():
6289 # unschedule the contribution
6290 contrib
._notify
("contributionUnscheduled")
6291 sch
=contrib
.getSchEntry().getSchedule()
6292 sch
.removeEntry(contrib
.getSchEntry())
6293 del self
.contributions
[contrib
.getId()]
6295 self
.updateNonInheritingChildren(contrib
, delete
=True, propagate
=False)
6296 for child
in contrib
.getAccessController().getNonInheritingChildren():
6297 self
.updateNonInheritingChildren(child
, delete
=True, propagate
=False)
6299 contrib
.setSession(None)
6301 self
.notifyModification()
6303 def newContribution( self
, params
= None, id=None ):
6307 self
.addContribution( c
, id )
6310 def getContributionById(self
,id):
6312 if self
.contributions
.has_key( id ):
6313 return self
.contributions
[ id ]
6316 def getContributionList( self
):
6317 return self
.contributions
.values()
6319 def getNumberOfContributions(self
, only_scheduled
=False):
6321 return len(filter(lambda c
: c
.isScheduled(), self
.contributions
.itervalues()))
6323 return len(self
.contributions
)
6325 def canIPAccess( self
, ip
):
6326 if not self
.__ac
.canIPAccess( ip
):
6328 if self
.getOwner() != None:
6329 return self
.getOwner().canIPAccess(ip
)
6332 def isProtected( self
):
6333 # tells if a session is protected or not
6334 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
6336 def getAccessProtectionLevel( self
):
6337 return self
.__ac
.getAccessProtectionLevel()
6339 def isItselfProtected( self
):
6340 return self
.__ac
.isItselfProtected()
6342 def hasAnyProtection( self
):
6343 """Tells whether a session has any kind of protection over it:
6344 access or domain protection.
6346 if self
.__ac
.isProtected():
6348 if self
.getDomainList():
6350 if self
.getAccessProtectionLevel() == -1:
6353 return self
.getOwner().hasAnyProtection()
6355 def hasProtectedOwner( self
):
6356 if self
.getOwner() != None:
6357 return self
.getOwner().isProtected()
6360 def setProtection( self
, private
):
6361 self
.__ac
.setProtection( private
)
6362 self
.notify_protection_to_owner(self
)
6364 def grantAccess( self
, prin
):
6365 self
.__ac
.grantAccess( prin
)
6366 if isinstance(prin
, MaKaC
.user
.Avatar
):
6367 prin
.linkTo(self
, "access")
6369 def revokeAccess( self
, prin
):
6370 self
.__ac
.revokeAccess( prin
)
6371 if isinstance(prin
, MaKaC
.user
.Avatar
):
6372 prin
.unlinkTo(self
, "access")
6374 def canView( self
, aw
):
6375 """tells whether the specified user has access to the current object
6376 or any of its sub-objects
6378 if self
.canAccess( aw
):
6380 ### TODO: Replace this code when plugins allow extension points+notifications ##################
6381 from MaKaC
.webinterface
.rh
.collaboration
import RCCollaborationAdmin
, RCCollaborationPluginAdmin
6382 if RCCollaborationAdmin
.hasRights(user
= aw
.getUser()) or \
6383 RCCollaborationPluginAdmin
.hasRights(user
= aw
.getUser(), plugins
= "any"):
6385 ################################################################################################
6386 for contrib
in self
.getContributionList():
6387 if contrib
.canView( aw
):
6391 def isAllowedToAccess( self
, user
):
6394 if user
in self
.getCoordinatorList() or self
.__ac
.canUserAccess( user
) \
6395 or self
.canUserModify( user
) or (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess(user
)):
6399 def canAccess( self
, aw
):
6400 # Allow harvesters (Invenio, offline cache) to access
6402 if self
.__ac
.isHarvesterIP(aw
.getIP()):
6404 #####################################################
6406 if not self
.canIPAccess(aw
.getIP()) and not self
.canUserModify(aw
.getUser()) and not self
.isAllowedToAccess( aw
.getUser() ):
6408 if not self
.isProtected():
6410 flag
= self
.isAllowedToAccess( aw
.getUser() )
6411 return flag
or self
.conference
.canKeyAccess( aw
)
6413 def grantModification( self
, sb
, sendEmail
=True ):
6414 if isinstance(sb
, SessionChair
) or isinstance(sb
, SlotChair
):
6416 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
6419 if sb
.getEmail().lower().strip() in [j
.lower().strip() for j
in i
.getEmails()]:
6422 if r
is not None and r
.isActivated():
6423 self
.__ac
.grantModification( r
)
6424 r
.linkTo(self
, "manager")
6425 elif sb
.getEmail() != "":
6426 modificationEmailGranted
= self
.__ac
.grantModificationEmail(sb
.getEmail())
6427 if modificationEmailGranted
and sendEmail
:
6428 notif
= pendingQueues
._PendingManagerNotification
( [sb
] )
6429 mail
.GenericMailer
.sendAndLog( notif
, self
.getConference() )
6431 self
.__ac
.grantModification( sb
)
6432 if isinstance(sb
, MaKaC
.user
.Avatar
):
6433 sb
.linkTo(self
, "manager")
6435 def revokeModification( self
, prin
):
6436 self
.__ac
.revokeModification( prin
)
6437 if isinstance(prin
, MaKaC
.user
.Avatar
):
6438 prin
.unlinkTo(self
, "manager")
6440 def canModify( self
, aw
):
6441 return self
.canUserModify( aw
.getUser() ) or self
.getConference().canKeyModify( aw
)
6443 def canUserModify( self
, av
):
6444 """Tells whether a user is allowed to modify the current session:
6445 only if the user is granted to modify the session or the user
6446 can modify the corresponding conference.
6448 return self
.getConference().canUserModify( av
) or self
.__ac
.canModify( av
)
6450 def getManagerList( self
):
6451 return self
.__ac
.getModifierList()
6453 def getAllowedToAccessList( self
):
6454 return self
.__ac
.getAccessList()
6456 def addMaterial( self
, newMat
):
6457 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
6458 newMat
.setOwner( self
)
6459 self
.materials
[ newMat
.getId() ] = newMat
6460 self
.notifyModification()
6462 def removeMaterial( self
, mat
):
6463 if mat
.getId() in self
.materials
.keys():
6465 self
.materials
[mat
.getId()].setOwner(None)
6466 del self
.materials
[ mat
.getId() ]
6467 self
.notifyModification()
6468 return "done: %s"%mat
.getId()
6469 elif mat
.getId().lower() == 'minutes':
6470 self
.removeMinutes()
6471 return "done: %s"%mat
.getId()
6472 return "not done: %s"%mat
.getId()
6474 def recoverMaterial(self
, recMat
):
6475 # Id must already be set in recMat.
6476 recMat
.setOwner( self
)
6477 self
.materials
[ recMat
.getId() ] = recMat
6479 self
.notifyModification()
6481 def getMaterialRegistry(self
):
6483 Return the correct material registry for this type
6485 from MaKaC
.webinterface
.materialFactories
import SessionMFRegistry
6486 return SessionMFRegistry
6488 def getMaterialById( self
, matId
):
6489 if matId
.lower() == 'minutes':
6490 return self
.getMinutes()
6491 elif self
.materials
.has_key(matId
):
6492 return self
.materials
[ matId
]
6495 def getMaterialList( self
):
6496 return self
.materials
.values()
6498 def getAllMaterialList(self
, sort
=True):
6499 l
= self
.getMaterialList()
6500 if self
.getMinutes():
6501 l
.append( self
.getMinutes() )
6503 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
6506 def _setSchedule(self
):
6507 self
.__schedule
=SessionSchedule(self
)
6508 sl
=self
.getSlotList()
6509 for slot
in self
.getSlotList():
6510 self
.__schedule
.addEntry(slot
.getSchEntry())
6512 def getSchedule( self
):
6514 if self
.__schedule
is None or not isinstance(self
.__schedule
,SessionSchedule
):
6516 except AttributeError, e
:
6518 return self
.__schedule
6520 def getMasterSchedule( self
):
6521 return self
.getOwner().getSchedule()
6523 def requireDomain( self
, dom
):
6524 self
.__ac
.requireDomain( dom
)
6526 def freeDomain( self
, dom
):
6527 self
.__ac
.freeDomain( dom
)
6529 def getDomainList( self
):
6530 return self
.__ac
.getRequiredDomainList()
6532 def setComments(self
,comm
):
6533 self
._comments
= comm
.strip()
6535 def getComments(self
):
6539 except AttributeError,e
:
6541 return self
._comments
6543 def createMinutes( self
):
6544 if self
.getMinutes() != None:
6545 raise MaKaCError( _("The minutes for this session have already been created"), _("Session"))
6546 self
.minutes
= Minutes()
6547 self
.minutes
.setOwner( self
)
6548 self
.notifyModification()
6551 def removeMinutes( self
):
6552 if self
.minutes
is None:
6554 self
.minutes
.delete()
6555 self
.minutes
.setOwner( None )
6557 self
.notifyModification()
6559 def recoverMinutes(self
, min):
6560 self
.removeMinutes() # To ensure that the current minutes are put in
6563 self
.minutes
.setOwner( self
)
6565 self
.notifyModification()
6568 def getMinutes( self
):
6573 except AttributeError, e
:
6578 def _addCoordinator(self
, av
):
6579 if av
is None or self
._coordinators
.has_key(av
.getId()):
6581 self
._coordinators
[av
.getId()]=av
6582 if self
.getConference() is not None:
6583 self
.getConference().addSessionCoordinator(self
,av
)
6585 def getCoordinatorEmailList(self
):
6587 return self
._coordinatorsEmail
6589 self
._coordinatorsEmail
= []
6590 return self
._coordinatorsEmail
6592 def _addCoordinatorEmail(self
, email
):
6593 if not email
in self
.getCoordinatorEmailList():
6594 self
.getCoordinatorEmailList().append(email
)
6596 def removeCoordinatorEmail(self
, email
):
6597 if email
in self
.getCoordinatorEmailList():
6598 if email
in self
.getCoordinatorEmailList():
6599 self
.getCoordinatorEmailList().remove(email
)
6602 def addCoordinator( self
, sb
, sendEmail
=True ):
6603 """Grants coordination privileges to user.
6606 sb -- It can be either:
6607 (MaKaC.user.Avatar) the user to which
6608 coordination privileges must be granted.
6610 (MaKaC.conference.SessionChair) a non-existing which
6611 has to become indico user before to be granted with privileges.
6614 if self
._coordinators
:
6616 except AttributeError, e
:
6617 self
._coordinators
=OOBTree()
6619 if isinstance(sb
, SessionChair
):
6621 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
6625 if sb
.getEmail().lower().strip() in [j
.lower().strip() for j
in i
.getEmails()]:
6629 if r
is not None and r
.isActivated():
6631 self
._addCoordinator
(r
)
6632 r
.linkTo(self
, "coordinator")
6634 self
.getConference().getPendingQueuesMgr().addPendingCoordinator(sb
)
6636 self
._addCoordinator
(sb
)
6637 if isinstance(sb
, MaKaC
.user
.Avatar
):
6638 sb
.linkTo(self
, "coordinator")
6640 def removeCoordinator( self
, av
):
6641 """Revokes coordination privileges to user.
6644 av -- (MaKaC.user.Avatar) user for which coordination privileges
6648 if self
._coordinators
:
6650 except AttributeError, e
:
6651 self
._coordinators
=OOBTree()
6653 if av
is None or not self
._coordinators
.has_key(av
.getId()):
6655 del self
._coordinators
[av
.getId()]
6656 if isinstance(av
, MaKaC
.user
.Avatar
):
6657 av
.unlinkTo(self
, "coordinator")
6658 if self
.getConference() is not None:
6659 self
.getConference().removeSessionCoordinator(self
,av
)
6661 def isCoordinator( self
, av
):
6662 """Tells whether the specified user is a coordinator of the session.
6665 av -- (MaKaC.user.Avatar) user to be checked
6667 Return value: (boolean)
6670 if self
._coordinators
:
6672 except AttributeError, e
:
6673 self
._coordinators
=OOBTree()
6674 if (av
is not None) and self
._coordinators
.has_key(av
.getId()):
6677 if isinstance(av
, MaKaC
.user
.Avatar
):
6678 for email
in av
.getEmails():
6679 if email
in self
.getCoordinatorEmailList():
6680 self
.addCoordinator(av
)
6681 self
.removeCoordinatorEmail(email
)
6685 def hasConvenerByEmail(self
, email
):
6686 for convener
in self
.getConvenerList():
6687 if email
== convener
.getEmail():
6692 def getCoordinatorList( self
):
6693 """Return all users which have privileges to coordinate the session.
6695 Return value: (list)
6698 if self
._coordinators
:
6700 except AttributeError, e
:
6701 self
._coordinators
=OOBTree()
6703 return self
._coordinators
.values()
6705 def canCoordinate(self
,aw
, right
=""):
6706 """Tells if a user has coordination privileges.
6708 Only session coordinators have coordination privileges over a
6712 aw -- (MaKaC.accessControl.AccessWrapper) User access
6713 information for which the coordination privileges must be
6716 Return value: (boolean)
6719 return self
.isCoordinator(aw
.getUser()) and self
.getConference().hasSessionCoordinatorRight(right
)
6720 return self
.isCoordinator(aw
.getUser())
6723 def getScheduleType(self
):
6727 except AttributeError:
6728 self
._ttType
=SlotSchTypeFactory
.getDefaultId()
6731 def setScheduleType(self
,t
):
6735 except AttributeError:
6736 self
._ttType
=SlotSchTypeFactory
.getDefaultId()
6737 t
=str(t
).strip().lower()
6738 if t
not in SlotSchTypeFactory
.getIdList() or t
==self
._ttType
:
6741 for slot
in self
.getSlotList():
6742 slot
.setScheduleType(t
)
6744 def getAccessController(self
):
6748 def _cmpTitle( s1
, s2
):
6749 s1
=s1
.getTitle().lower().strip()
6750 s2
=s2
.getTitle().lower().strip()
6751 return cmp( s1
, s2
)
6752 _cmpTitle
=staticmethod(_cmpTitle
)
6754 class SessionSlot(Persistent
, Fossilizable
, Locatable
):
6756 fossilizes(ISessionSlotFossil
)
6758 def __init__(self
,session
,**sessionSlotData
):
6759 self
.session
= session
6760 self
.id = "not assigned"
6763 self
.duration
= timedelta(minutes
=1)
6766 self
._conveners
= []
6767 self
._convenerGen
=Counter()
6768 self
._schedule
=SlotSchTypeFactory
.getDefaultKlass()(self
)
6769 self
._sessionSchEntry
=LinkedTimeSchEntry(self
)
6770 self
._confSchEntry
=LinkedTimeSchEntry(self
)
6771 self
._contributionDuration
= None
6773 def getTimezone( self
):
6774 return self
.getConference().getTimezone()
6776 def getLogInfo(self
):
6778 data
["id"] = self
.id
6779 data
["title"] = self
.title
6780 data
["session"] = self
.session
.getTitle()
6781 data
["start date"] = self
.startDate
6782 data
["duration"] = self
.duration
6784 for p
in self
.places
:
6785 data
["place %s"%i] = p
.getName()
6788 for r
in self
.rooms
:
6789 data
["room %s"%i] = r
.getName()
6791 for c
in self
._conveners
:
6792 data
["convener %s"%c.getId()] = c
.getFullName()
6795 def clone(self
,session
, options
):
6797 slot
= SessionSlot(session
)
6798 slot
.session
= session
6799 slot
.setTitle(self
.getTitle())
6800 timeDifference
= session
.getConference().getStartDate() - self
.getSession().getConference().getStartDate()
6801 slot
.setStartDate(self
.getStartDate() + timeDifference
)
6802 slot
.setDuration(dur
=self
.getDuration(), check
=2)
6805 if self
.getOwnLocation() is not None:
6806 slot
.setLocation(self
.getOwnLocation().clone())
6808 if self
.getOwnRoom() is not None:
6809 slot
.setRoom(self
.getOwnRoom().clone())
6812 for ch
in self
.getOwnConvenerList() :
6813 slot
.addConvener(ch
.clone())
6815 #populate the timetable
6816 if options
.get("contributions", False) :
6817 for entry
in self
.getEntries() :
6818 if isinstance(entry
, BreakTimeSchEntry
) :
6819 newentry
= entry
.clone(slot
)
6820 slot
.getSchedule().addEntry(newentry
,0)
6821 elif isinstance(entry
, ContribSchEntry
) :
6822 contrib
= entry
.getOwner()
6823 newcontrib
= contrib
.clone(session
, options
, timeDifference
)
6824 slot
.getSchedule().addEntry(newcontrib
.getSchEntry(),0)
6825 ContextManager
.setdefault("clone.unique_id_map", {})[contrib
.getUniqueId()] = newcontrib
.getUniqueId()
6827 slot
.setContribDuration(0, 0, self
.getContribDuration())
6828 slot
.notifyModification(cleanCache
= False)
6834 sets the start date of the slot to the start date of the first son
6835 and the end date to the end date of the last son
6837 sch
= self
.getSchedule()
6838 entries
= sch
.getEntries()
6839 if len(entries
) > 0:
6840 self
.setStartDate(entries
[0].getStartDate(),0,0)
6841 self
.setEndDate(sch
.calculateEndDate(), check
=0)
6843 def recalculateTimes( self
, type, diff
):
6845 recalculate and reschedule the contributions of the session slot with a time "diff" of separation.
6847 if type=="duration":
6848 entries
= self
.getSchedule().getEntries()[:]
6850 while i
<len(entries
):
6852 if i
+1 == len(entries
):
6853 dur
=self
.getEndDate()-entry
.getStartDate()
6855 nextentry
=entries
[i
+1]
6856 dur
=nextentry
.getStartDate()-entry
.getStartDate()-diff
6857 if dur
<timedelta(0):
6858 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())
6859 entry
.setDuration(dur
=dur
)
6861 if len(entries
) != 0 and self
.getEndDate() < entry
.getEndDate():
6862 self
.setEndDate(entry
.getEndDate(),2)
6863 elif type=="startingTime":
6864 st
= self
.getStartDate()
6865 entries
= self
.getSchedule().getEntries()[:]
6866 for entry
in entries
:
6867 entry
.setStartDate(st
,0,0)
6868 # add diff to last item end date if and only if the item is
6870 #if not isinstance(entry, BreakTimeSchEntry):
6871 # st=entry.getEndDate()+diff
6873 # st=entry.getEndDate()
6874 st
=entry
.getEndDate()+diff
6875 if len(entries
) != 0 and self
.getEndDate() < st
:
6876 self
.setEndDate(st
,2)
6878 def setValues(self
,data
,check
=2, moveEntriesBelow
=0):
6881 1: check and raise error in case of problem
6882 2: check and adapt the owner dates
6885 # In order to move the entries below, it is needed to know the diff (we have to move them)
6886 # and the list of entries to move. It's is needed to take those datas in advance because they
6887 # are going to be modified before the moving.
6888 if moveEntriesBelow
== 1:
6889 oldStartDate
=copy
.copy(self
.getStartDate())
6890 oldDuration
=copy
.copy(self
.getDuration())
6891 i
=self
.getConfSchEntry().getSchedule().getEntries().index(self
.getConfSchEntry())+1
6892 entriesList
= self
.getConfSchEntry().getSchedule().getEntries()[i
:]
6893 self
.title
=data
.get("title", "NO TITLE ASSIGNED")
6894 # Do we move all entries in the slot
6895 move
= int(data
.get("move",0))
6897 if "locationName" in data
:
6898 loc
= self
.getOwnLocation()
6900 loc
= CustomLocation()
6901 self
.setLocation( loc
)
6902 loc
.setName( data
["locationName"] )
6903 loc
.setAddress( data
.get("locationAddress", "") )
6905 self
.setLocation( None )
6907 if "roomName" in data
:
6908 room
= self
.getOwnRoom()
6911 self
.setRoom( room
)
6912 room
.setName( data
["roomName"] )
6914 self
.setRoom( None )
6915 sDate
= eDate
= None
6916 confTZ
= self
.getOwner().getConference().getTimezone()
6917 if data
.get("sDate",None) is not None:
6918 sd
= data
.get("sDate")
6919 sDate
= timezone(confTZ
).localize(datetime(sd
.year
,sd
.month
,sd
.day
,sd
.hour
,sd
.minute
))
6920 elif data
.get("sYear","")!="" and data
.get("sMonth","")!="" and \
6921 data
.get("sDay","")!="" and data
.get("sHour","")!="" and \
6922 data
.get("sMinute","")!="":
6923 sDate
= timezone(confTZ
).localize(datetime(int(data
["sYear"]),int(data
["sMonth"]),
6924 int(data
["sDay"]),int(data
["sHour"]),
6925 int(data
["sMinute"])))
6926 if data
.get("eDate",None) is not None:
6927 ed
= data
.get("eDate")
6928 eDate
= timezone(confTZ
).localize(datetime(ed
.year
,ed
.month
,ed
.day
,ed
.hour
,ed
.minute
))
6929 elif data
.get("eYear","")!="" and data
.get("eMonth","")!="" and \
6930 data
.get("eDay","")!="" and data
.get("eHour","")!="" and \
6931 data
.get("eMinute","")!="":
6932 eDate
= timezone(confTZ
).localize(datetime(int(data
["eYear"]),int(data
["eMonth"]),
6933 int(data
["eDay"]),int(data
["eHour"]),
6934 int(data
["eMinute"])))
6935 if sDate
!= None and eDate
!= None:
6936 sDateUTC
= sDate
.astimezone(timezone('UTC'))
6937 eDateUTC
= eDate
.astimezone(timezone('UTC'))
6938 self
.setDates(sDateUTC
,eDateUTC
,check
,moveEntries
=move
)
6940 sDateUTC
= sDate
.astimezone(timezone('UTC'))
6941 self
.setStartDate(sDateUTC
,check
,moveEntries
=move
)
6942 if data
.get("durHours","")!="" and data
.get("durMins","")!="":
6943 self
.setDuration(hours
=data
["durHours"],minutes
=data
["durMins"],check
=check
)
6944 if data
.get("contribDurHours","")!="" and data
.get("contribDurMins","")!="":
6945 self
.setContribDuration(int(data
["contribDurHours"]),int(data
["contribDurMins"]))
6946 elif data
.get("contribDuration","")!="":
6947 self
.setContribDuration(dur
=data
.get("contribDuration"))
6949 self
.setContribDuration(None,None)
6950 conveners
= data
.get("conveners",None)
6951 if conveners
is not None:
6952 self
.clearConvenerList()
6953 for conv
in conveners
:
6955 sc
.setTitle(conv
.getTitle())
6956 sc
.setFirstName(conv
.getFirstName())
6957 sc
.setFamilyName(conv
.getFamilyName())
6958 sc
.setAffiliation(conv
.getAffiliation())
6959 sc
.setEmail(conv
.getEmail())
6960 self
.addConvener(sc
)
6961 if moveEntriesBelow
== 1:
6962 diff
= (self
.getStartDate() - oldStartDate
) + (self
.getDuration() - oldDuration
)
6963 self
.getSchedule().moveEntriesBelow(diff
, entriesList
)
6964 self
._checkInnerSchedule
()
6965 self
.notifyModification()
6967 def _checkInnerSchedule( self
):
6968 self
.getSchedule().checkSanity()
6970 def setContribDuration(self
, hour
=0, min=0, dur
=None):
6971 self
._contributionDuration
= None
6973 self
._contributionDuration
=dur
6974 elif hour
!= None and min != None:
6975 self
._contributionDuration
= timedelta(hours
=hour
,minutes
=min)
6977 def getContribDuration(self
):
6979 Duration by default for contributions within the slots.
6982 if self
._contributionDuration
:
6984 except AttributeError, e
:
6985 self
._contributionDuration
= None
6986 return self
._contributionDuration
6988 def notifyModification( self
, cleanCache
= True, cleanCacheEntries
= False):
6989 self
.getSession().notifyModification(cleanCache
= False)
6991 self
.cleanCache(cleanCacheEntries
)
6994 def cleanCache(self
, cleanCacheEntries
= False):
6995 if not ContextManager
.get('clean%s'%self
.getUniqueId(), False):
6996 ScheduleToJson
.cleanCache(self
)
6997 ContextManager
.set('clean%s'%self
.getUniqueId(), True)
6998 if cleanCacheEntries
:
6999 for entry
in self
.getSchedule().getEntries():
7000 entry
.getOwner().cleanCache(cleanConference
= False)
7002 def getLocator( self
):
7003 l
=self
.getSession().getLocator()
7004 l
["slotId"]=self
.getId()
7007 def getConference( self
):
7008 return self
.getSession().getConference()
7010 def getSession(self
):
7013 def getOwner( self
):
7016 def _setSchedule(self
,klass
):
7017 old_sch
=self
.getSchedule()
7018 self
._schedule
=klass(self
)
7019 #after removing old entries, one could try to fit them into the new
7020 # schedule, but there are several things to consider which are left
7021 # for later implementation (breaks, entries not fitting in the
7023 while len(old_sch
.getEntries())>0:
7024 entry
=old_sch
.getEntries()[0]
7025 old_sch
.removeEntry(entry
)
7026 self
.notifyModification()
7028 def getSchedule(self
):
7029 return self
._schedule
7031 def getMasterSchedule( self
):
7032 return self
.getOwner().getSchedule()
7034 def getConfSchEntry( self
):
7036 if self
._confSchEntry
:
7038 except AttributeError:
7039 self
._confSchEntry
=LinkedTimeSchEntry(self
)
7040 return self
._confSchEntry
7042 def getSessionSchEntry( self
):
7044 if self
._sessionSchEntry
:
7046 except AttributeError:
7047 self
._sessionSchEntry
=self
._schEntry
7048 return self
._sessionSchEntry
7050 def setId( self
, newId
):
7052 self
.notifyModification()
7057 def getUniqueId( self
):
7058 """Returns (string) the unique identiffier of the item.
7059 Used mainly in the web session access key table"""
7060 return "%sl%s" % (self
.getSession().getUniqueId(),self
.id)
7062 def setTitle( self
, newTitle
):
7064 self
.notifyModification()
7066 def getTitle( self
):
7070 except AttributeError,e
:
7074 def getFullTitle( self
):
7075 return self
.getSession().getTitle() + (": " + self
.getTitle() if self
.getTitle() else "")
7078 return "slot %s"%self
.getId()
7080 def getDescription(self
):
7081 return self
.getSession().getDescription()
7083 def setDates(self
,sDate
,eDate
,check
=2,moveEntries
=0):
7086 1: check and raise error in case of problem
7087 2: check and adapt the owner dates"""
7090 raise MaKaCError(_("End date cannot be prior to Start date"),_("Slot"))
7092 self
.setStartDate(sDate
, check
, moveEntries
, checkDuration
=False)
7093 self
.setDuration(0, 0, 0, eDate
-sDate
, check
)
7094 self
.notifyModification()
7096 def getEntries(self
):
7097 entriesList
= self
.getSchedule().getEntries()
7100 def move(self
, sDate
):
7101 diff
=sDate
-self
.startDate
7102 self
.startDate
= sDate
7103 for slotEntry
in self
.getSchedule().getEntries():
7104 if isinstance(slotEntry
, BreakTimeSchEntry
):
7105 slotEntry
.startDate
= slotEntry
.getStartDate() + diff
7107 se
= slotEntry
.getOwner()
7108 se
.startDate
= se
.getStartDate() + diff
7109 self
.getSchedule().reSchedule()
7111 def verifyStartDate(self
, sDate
,check
=2):
7114 1: check and raise error in case of problem
7115 2: check and adapt the owner dates"""
7117 tz
= timezone(self
.getConference().getTimezone())
7119 if sDate
< self
.getSession().getStartDate():
7121 raise ParentTimingError(_("The slot \"%s\" cannot start (%s) before its parent session starts (%s)")%\
7122 (self
.getTitle(), sDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
7123 self
.getSession().getStartDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
7126 self
.getSession().setStartDate(sDate
, check
, 0)
7128 def setStartDate(self
,sDate
,check
=2,moveEntries
=0,checkDuration
=True):
7131 1: check and raise error in case of problem
7132 2: check and adapt the owner dates"""
7135 if not sDate
.tzname():
7136 raise MaKaCError("date should be timezone aware")
7138 #If not using .fit() at the end of this method, comment it out
7139 #if self.getSession().getStartDate() > sDate:
7140 # self.getSession().duration += self.getSession().getStartDate() - sDate
7141 self
.verifyStartDate(sDate
,check
)
7143 # calculate the difference betwwen old and new date
7145 if self
.startDate
is not None:
7146 difference
= sDate
- self
.getStartDate()
7148 self
.startDate
=copy
.copy(sDate
)
7150 if difference
!= None and difference
!= timedelta(0) and moveEntries
:
7151 ContextManager
.get('autoOps').append((self
, "ENTRIES_MOVED",
7152 self
, sDate
.astimezone(timezone(self
.getTimezone()))))
7153 self
.getSchedule().moveEntriesBelow(difference
,self
.getSchedule().getEntries()[:])
7155 if self
.getConference() and not self
.getConference().getEnableSessionSlots() and self
.getSession().getStartDate() != sDate
:
7156 self
.getSession().setStartDate(sDate
, check
, 0)
7157 if check
!= 0 and self
.getSession() and checkDuration
:
7158 self
.verifyDuration(self
.getDuration(), check
=check
)
7160 # synchronize with other timetables
7161 self
.getSessionSchEntry().synchro()
7162 self
.getConfSchEntry().synchro()
7163 self
.getSession().fit()
7164 self
.notifyModification()
7166 def setEndDate(self
,eDate
,check
=2):
7167 if not eDate
.tzname():
7168 raise MaKaCError("date should be timezone aware")
7170 self
.verifyDuration(eDate
-self
.startDate
, check
)
7171 self
.setDuration(dur
=eDate
-self
.startDate
,check
=check
)
7172 if self
.getConference() and not self
.getConference().getEnableSessionSlots() and self
.getSession().getEndDate() != eDate
:
7173 self
.getSession().setEndDate(eDate
, check
)
7174 self
.getSession().fit()
7175 self
.notifyModification()
7177 def getStartDate( self
):
7178 return self
.startDate
7180 def getAdjustedStartDate(self
,tz
=None):
7182 tz
= self
.getConference().getTimezone()
7183 if tz
not in all_timezones
:
7185 return self
.startDate
.astimezone(timezone(tz
))
7187 def getEndDate( self
):
7188 if self
.startDate
is None:
7190 return self
.startDate
+self
.duration
7192 def getAdjustedEndDate( self
, tz
=None ):
7194 tz
= self
.getConference().getTimezone()
7195 if tz
not in all_timezones
:
7197 if self
.getEndDate():
7198 return self
.getEndDate().astimezone(timezone(tz
))
7201 def getDuration( self
):
7202 return self
.duration
7204 def isMoreThanDay(self
):
7205 if self
.getDuration() >= timedelta(days
=1):
7209 def verifyDuration(self
, dur
, check
=1):
7212 1: check and raise error in case of problem
7213 2: check and adapt the owner dates"""
7215 tz
= timezone(self
.getConference().getTimezone())
7216 if dur
<= timedelta(0):
7217 raise MaKaCError( _("The duration cannot be less than zero"), _("Slot"))
7219 raise MaKaCError( _("The duration cannot be more than one day"), _("Slot"))
7220 if self
.startDate
is not None:
7221 sessionStartDate
= self
.getSession().getStartDate()
7222 sessionEndDate
= self
.getSession().getEndDate()
7223 # end date has to be between the session dates
7224 eDate
= self
.startDate
+ dur
7225 if eDate
> sessionEndDate
:
7227 raise EntryTimingError(_("The session slot cannot end (%s) after its parent session (%s)") \
7228 % (eDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
7229 sessionEndDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
7232 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
7233 self
.getSession(), eDate
.astimezone(tz
)))
7234 self
.getSession().setEndDate(eDate
,check
)
7235 if eDate
.astimezone(tz
).date() > self
.startDate
.astimezone(tz
).date():
7236 raise TimingError( _("The time slot must end on the same day it has started"), _("Slot"))
7237 # do not modify if slot entries will be affected
7238 sch
= self
.getSchedule()
7239 entries
= sch
.getEntries()
7241 if eDate
< sch
.calculateEndDate():
7242 raise TimingError(_("The session slot cannot end at (%s) because there is a contribution (%s) ending after that time. ")%\
7243 (eDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
7244 sch
.calculateEndDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
7247 def setDuration(self
, days
=0,hours
=0,minutes
=0,dur
=0,check
=1):
7250 1: check and raise error in case of problem
7251 2: check and adapt the owner dates"""
7254 dur
= timedelta(days
=int(days
),hours
=int(hours
),minutes
=int(minutes
))
7255 if dur
==0 and check
==2:
7256 ContextManager
.get('autoOps').append((self
, "DURATION_SET",
7258 dur
= timedelta(minutes
=1)
7259 if dur
> timedelta(days
=1) and check
==2:
7260 pass#dur = timedelta(days=1)
7262 self
.verifyDuration(dur
, check
)
7264 self
.getSessionSchEntry().synchro()
7265 self
.getConfSchEntry().synchro()
7266 self
.getSession().fit()
7267 self
.notifyModification()
7269 def getLocationParent( self
):
7271 Returns the object from which the room/location
7272 information should be inherited
7274 return self
.session
.conference
7277 self
.getSchedule().clear()
7278 if self
.getSession() is not None:
7279 self
.getSession().removeSlot(self
)
7281 TrashCanManager().add(self
)
7284 TrashCanManager().remove(self
)
7286 def getAccessController( self
):
7287 return self
.getSession().getAccessController()
7289 def canAccess(self
,aw
):
7290 return self
.getSession().canAccess(aw
)
7292 def canView(self
,aw
):
7293 return self
.getSession().canView(aw
)
7295 def isProtected(self
):
7296 return self
.getSession().isProtected()
7298 def getAccessKey( self
):
7299 return self
.getSession().getAccessKey()
7301 def setScheduleType(self
,id):
7302 id=str(id).strip().lower()
7303 currentId
=SlotSchTypeFactory
.getId(self
.getSchedule())
7304 if id not in SlotSchTypeFactory
.getIdList() or id==currentId
:
7306 self
._setSchedule
(SlotSchTypeFactory
.getScheduleKlass(id))
7308 def getConvenerList(self
):
7312 except AttributeError:
7313 self
._conveners
= []
7314 if self
._conveners
== []:
7315 return self
.getSession().getConvenerList()
7316 return self
._conveners
7318 def addConvener(self
,newConv
):
7319 if newConv
in self
._conveners
:
7322 if self
._convenerGen
:
7324 except AttributeError:
7325 self
._convenerGen
=Counter()
7326 id = newConv
.getId()
7328 id=int(self
._convenerGen
.newCount())
7329 newConv
.includeInSlot(self
,id)
7330 self
._conveners
.append(newConv
)
7331 self
.notifyModification()
7333 def removeConvener(self
,conv
):
7334 if conv
not in self
._conveners
:
7336 self
._conveners
.remove(conv
)
7338 self
.notifyModification()
7340 def recoverConvener(self
, con
):
7341 self
.addConvener(con
)
7344 def getConvenerById(self
,id):
7346 for conv
in self
._conveners
:
7347 if conv
.getId()==id:
7351 def getOwnConvenerList(self
):
7355 except AttributeError:
7356 self
._conveners
= []
7357 return self
._conveners
7359 def clearConvenerList(self
):
7360 while len(self
.getOwnConvenerList()) > 0:
7361 self
._conveners
.pop()
7362 self
.notifyModification()
7366 if self
.getSession() is not None:
7367 res
=self
.getSession().getColor()
7370 def getTextColor(self
):
7372 if self
.getSession() is not None:
7373 res
=self
.getSession().getTextColor()
7376 def getAllMaterialList(self
, sort
=True):
7377 return self
.getSession().getAllMaterialList(sort
=sort
)
7380 class ContributionParticipation(Persistent
, Fossilizable
):
7382 fossilizes(IContributionParticipationFossil
, IContributionParticipationMinimalFossil
,\
7383 IContributionParticipationTTDisplayFossil
,\
7384 IContributionParticipationTTMgmtFossil
)
7386 def __init__( self
):
7387 self
._contrib
= None
7389 self
._firstName
= ""
7392 self
._affiliation
= ""
7398 def _notifyModification( self
):
7399 if self
._contrib
!= None:
7400 self
._contrib
.notifyModification()
7402 def setValues(self
, data
):
7403 self
.setFirstName(data
.get("firstName", ""))
7404 self
.setFamilyName(data
.get("familyName",""))
7405 self
.setAffiliation(data
.get("affilation",""))
7406 self
.setAddress(data
.get("address",""))
7407 self
.setEmail(data
.get("email",""))
7408 self
.setFax(data
.get("fax",""))
7409 self
.setTitle(data
.get("title",""))
7410 self
.setPhone(data
.get("phone",""))
7411 self
._notifyModification
()
7413 def getValues(self
):
7415 data
["firstName"]=self
.getFirstName()
7416 data
["familyName"]=self
.getFamilyName()
7417 data
["affilation"]=self
.getAffiliation()
7418 data
["address"]=self
.getAddress()
7419 data
["email"]=self
.getEmail()
7420 data
["fax"]=self
.getFax()
7421 data
["title"]=self
.getTitle()
7422 data
["phone"]=self
.getPhone()
7426 part
= ContributionParticipation()
7427 part
.setValues(self
.getValues())
7430 def setDataFromAvatar(self
,av
):
7431 # av is an Avatar object.
7434 self
.setFirstName(av
.getName())
7435 self
.setFamilyName(av
.getSurName())
7436 self
.setEmail(av
.getEmail())
7437 self
.setAffiliation(av
.getOrganisation())
7438 self
.setAddress(av
.getAddress())
7439 self
.setPhone(av
.getTelephone())
7440 self
.setTitle(av
.getTitle())
7441 self
.setFax(av
.getFax())
7442 self
._notifyModification
()
7444 def setDataFromOtherCP(self
,cp
):
7445 # cp is a ContributionParticipation object.
7448 self
.setFirstName(cp
.getFirstName())
7449 self
.setFamilyName(cp
.getFamilyName())
7450 self
.setEmail(cp
.getEmail())
7451 self
.setAffiliation(cp
.getAffiliation())
7452 self
.setAddress(cp
.getAddress())
7453 self
.setPhone(cp
.getPhone())
7454 self
.setTitle(cp
.getTitle())
7455 self
.setFax(cp
.getFax())
7456 self
._notifyModification
()
7458 def includeInContribution( self
, contrib
, id ):
7459 if self
.getContribution() == contrib
and self
.getId()==id.strip():
7461 self
._contrib
= contrib
7465 self
._contrib
= None
7466 TrashCanManager().add(self
)
7469 TrashCanManager().remove(self
)
7471 def setId(self
, newId
):
7477 def getContribution( self
):
7478 return self
._contrib
7480 def getConference(self
):
7481 return self
._contrib
.getConference()
7483 def getLocator(self
):
7484 if self
.getContribution() is None:
7486 loc
=self
.getContribution().getLocator()
7487 loc
["authId"]=self
.getId()
7491 contrib
=self
.getContribution()
7492 if contrib
is not None:
7493 conf
=contrib
.getConference()
7494 if conf
is not None:
7495 conf
.unindexAuthor(self
)
7496 conf
.unindexSpeaker(self
)
7499 contrib
=self
.getContribution()
7500 if contrib
is not None:
7501 conf
=contrib
.getConference()
7502 if conf
is not None:
7503 conf
.indexAuthor(self
)
7504 conf
.indexSpeaker(self
)
7506 @Updates ('MaKaC.conference.ContributionParticipation', 'firstName')
7507 def setFirstName( self
, newName
):
7509 if tmp
==self
._firstName
:
7514 self
._notifyModification
()
7516 def getFirstName( self
):
7517 return self
._firstName
7519 def getName( self
):
7520 return self
._firstName
7523 @Updates ('MaKaC.conference.ContributionParticipation', 'familyName')
7524 def setFamilyName( self
, newName
):
7526 if tmp
==self
._surName
:
7531 self
._notifyModification
()
7533 def getFamilyName( self
):
7534 return self
._surName
7536 def getSurName( self
):
7537 return self
._surName
7540 @Updates ('MaKaC.conference.ContributionParticipation', 'email')
7541 def setEmail( self
, newMail
):
7543 if tmp
==self
._email
:
7546 self
._email
=newMail
.strip()
7548 self
._notifyModification
()
7550 def getEmail( self
):
7553 @Updates ('MaKaC.conference.ContributionParticipation', 'affiliation')
7554 def setAffiliation( self
, newAffil
):
7555 self
._affiliation
= newAffil
.strip()
7556 self
._notifyModification
()
7558 def getAffiliation( self
):
7559 if self
._affiliation
.lower() == "unknown":
7561 return self
._affiliation
7563 @Updates ('MaKaC.conference.ContributionParticipation', 'address')
7564 def setAddress( self
, newAddr
):
7565 self
._address
= newAddr
.strip()
7566 self
._notifyModification
()
7568 def getAddress( self
):
7569 return self
._address
7571 @Updates ('MaKaC.conference.ContributionParticipation', 'telephone')
7572 def setPhone( self
, newPhone
):
7573 self
._phone
= newPhone
.strip()
7574 self
._notifyModification
()
7576 def getPhone( self
):
7579 @Updates ('MaKaC.conference.ContributionParticipation', 'title')
7580 def setTitle( self
, newTitle
):
7581 self
._title
= newTitle
.strip()
7582 self
._notifyModification
()
7584 def getTitle( self
):
7587 @Updates ('MaKaC.conference.ContributionParticipation', 'fax')
7588 def setFax( self
, newFax
):
7589 self
._fax
= newFax
.strip()
7590 self
._notifyModification
()
7596 except AttributeError:
7600 def getDirectFullName( self
):
7601 res
= self
.getDirectFullNameNoTitle()
7602 if self
.getTitle() != "":
7603 res
= "%s %s"%( self
.getTitle(), res
)
7606 def getDirectFullNameNoTitle( self
, upper
= True ):
7607 return ("%s %s"%(self
.getFirstName(), self
.getFamilyName().upper() if upper
else self
.getFamilyName())).strip()
7609 def getFullName( self
):
7610 res
= self
.getFullNameNoTitle()
7611 if self
.getTitle() != "":
7612 res
= "%s %s"%( self
.getTitle(), res
)
7615 def getFullNameNoTitle( self
):
7616 res
= self
.getFamilyName().decode('utf-8').upper().encode('utf-8')
7617 if self
.getFirstName() != "":
7618 if res
.strip() != "":
7619 res
= "%s, %s"%( res
, self
.getFirstName() )
7621 res
= self
.getFirstName()
7624 def getAbrName(self
):
7625 res
= self
.getFamilyName()
7626 if self
.getFirstName() != "":
7629 res
= "%s%s."%(res
, self
.getFirstName()[0].upper())
7632 def isSubmitter(self
):
7633 if self
.getContribution() is None:
7635 return self
.getContribution().canUserSubmit(self
)
7637 def isPendingSubmitter(self
):
7638 if self
.getContribution() is None:
7640 if self
.getContribution().getConference() is None:
7642 return self
.getContribution().getConference().getPendingQueuesMgr().isPendingSubmitter(self
)
7644 def _cmpFamilyName( cp1
, cp2
):
7645 o1
= "%s %s"%(cp1
.getFamilyName(), cp1
.getFirstName())
7646 o2
= "%s %s"%(cp2
.getFamilyName(), cp2
.getFirstName())
7647 o1
=o1
.lower().strip()
7648 o2
=o2
.lower().strip()
7649 return cmp( o1
, o2
)
7650 _cmpFamilyName
=staticmethod(_cmpFamilyName
)
7653 class AuthorIndex(Persistent
):
7658 def _getKey(self
,author
):
7659 k
= "%s %s %s"%(author
.getFamilyName().lower(),author
.getFirstName().lower(),author
.getEmail().lower())
7662 def index(self
,author
):
7663 key
=self
._getKey
(author
)
7664 if not self
._idx
.has_key(key
):
7669 self
.notifyModification()
7671 def unindex(self
,author
):
7672 key
=self
._getKey
(author
)
7673 if self
._idx
.has_key(key
):
7674 if author
in self
._idx
[key
]:
7678 if len(self
._idx
[key
])<=0:
7680 self
.notifyModification()
7682 def getParticipations(self
):
7683 return self
._idx
.values()
7685 def getById(self
, id):
7686 return self
._idx
.get(id,None)
7688 def getByAuthorObj(self
, auth
):
7689 return self
.getById(self
._getKey
(auth
))
7691 def getParticipationKeys(self
):
7692 return self
._idx
.keys()
7694 def notifyModification(self
):
7695 self
._idx
._p
_changed
= 1
7698 def iteritems(self
):
7699 return self
._idx
.iteritems()
7701 def match(self
, criteria
, exact
=0):
7702 self
._options
= ['organisation', 'surName', 'name', 'email']
7704 for item
in self
.getParticipations():
7707 for f
,v
in criteria
.items():
7708 if f
== 'organisation' and v
!= '':
7709 if (exact
== 0 and item
[0].getAffiliation().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getAffiliation().lower() != v
.lower()):
7713 if f
== 'surName' and v
!= '':
7714 if (exact
== 0 and item
[0].getSurName().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getSurName().lower() != v
.lower()):
7718 if f
== 'name' and v
!= '':
7719 if (exact
== 0 and item
[0].getName().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getName().lower() != v
.lower()):
7723 if f
== 'email' and v
!= '':
7724 if (exact
== 0 and item
[0].getEmail().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getEmail().lower() != v
.lower()):
7728 if len(ok
) > 0 and not False in ok
:
7732 class _AuthIdx(Persistent
):
7734 def __init__(self
,conf
):
7738 def _getKey(self
,auth
):
7739 return "%s %s"%(auth
.getFamilyName().lower(),auth
.getFirstName().lower())
7741 def index(self
,auth
):
7742 if auth
.getContribution() is None:
7743 raise MaKaCError( _("Cannot index an author of a contribution which has not been included in a Conference"), _("Author Index"))
7744 if auth
.getContribution().getConference()!=self
._conf
:
7745 raise MaKaCError( _("cannot index an author of a contribution which does not belong to this Conference"), _("Author Index"))
7746 key
=self
._getKey
(auth
)
7747 contribId
=str(auth
.getContribution().getId())
7748 if not self
._idx
.has_key(key
):
7749 self
._idx
[key
]=OIBTree()
7750 if not self
._idx
[key
].has_key(contribId
):
7751 self
._idx
[key
][contribId
]=0
7752 self
._idx
[key
][contribId
]+=1
7754 def unindex(self
,auth
):
7755 if auth
.getContribution() is None:
7756 raise MaKaCError( _("Cannot unindex an author of a contribution which is not included in a conference"), _("Author Index"))
7757 if auth
.getContribution().getConference()!=self
._conf
:
7758 raise MaKaCError( _("Cannot unindex an author of a contribution which does not belong to this conference"), _("Author Index"))
7759 key
=self
._getKey
(auth
)
7760 if not self
._idx
.has_key(key
):
7762 contribId
=str(auth
.getContribution().getId())
7763 self
._idx
[key
][contribId
]-=1
7764 if self
._idx
[key
][contribId
]<=0:
7765 del self
._idx
[key
][contribId
]
7766 if len(self
._idx
[key
])<=0:
7769 def match(self
,query
):
7770 query
=query
.lower().strip()
7772 for k
in self
._idx
.keys():
7773 if k
.find(query
)!=-1:
7774 res
=union(res
,self
._idx
[k
])
7778 class _PrimAuthIdx(_AuthIdx
):
7780 def __init__(self
,conf
):
7781 _AuthIdx
.__init
__(self
,conf
)
7782 for contrib
in self
._conf
.getContributionList():
7783 for auth
in contrib
.getPrimaryAuthorList():
7786 class Contribution(CommonObjectBase
, Locatable
):
7787 """This class implements a conference contribution, being the concrete
7788 contributes of the conference participants. The class contains
7789 necessary attributes to store contribution basic meta data and provides
7790 the useful operations to access and manage them. A contribution can be
7791 attached either to a session or to a conference.
7794 fossilizes(IContributionFossil
, IContributionWithSpeakersFossil
,\
7795 IContributionWithSubContribsFossil
)
7797 def __init__(self
,**contribData
):
7803 self
.description
= ""
7805 self
.duration
= timedelta(0)
7807 self
.speakerText
= ""
7810 self
._boardNumber
=""
7811 self
._resetSchEntry
()
7812 self
.__ac
= AccessController(self
)
7814 self
.__materialGenerator
= Counter()
7816 self
.__subContGenerator
= Counter()
7822 self
.reviewing
= None
7823 self
._authorGen
= Counter()
7824 self
._authors
= OOBTree()
7825 self
._primaryAuthors
= []
7826 self
._coAuthors
= []
7830 self
._status
=ContribStatusNotSch(self
)
7831 #List of allowed users to submit material
7833 self
._submittersEmail
=[]
7834 self
._modificationDS
= nowutc()
7836 self
._reviewManager
= ReviewManager(self
)
7838 def __cmp__(self
, other
):
7839 if type(self
) is not type(other
):
7840 # This is actually dangerous and the ZODB manual says not to do this
7841 # because it relies on memory order. However, this branch should never
7842 # be taken anyway since we do not store different types in the same set
7843 # or use them as keys.
7844 return cmp(hash(self
), hash(other
))
7845 if self
.getConference() == other
.getConference():
7846 return cmp(self
.getId(), other
.getId())
7847 return cmp(self
.getConference(), other
.getConference())
7851 parentId
= self
.parent
.getId()
7854 return "<Contribution %s:%s@%s>" % (parentId
, self
.getId(), hex(id(self
)))
7856 def getTimezone( self
):
7857 return self
.getConference().getTimezone()
7859 def getReviewManager(self
):
7860 if not hasattr(self
, "_reviewManager"):
7861 self
._reviewManager
= ReviewManager(self
)
7862 return self
._reviewManager
7864 def updateNonInheritingChildren(self
, elem
, delete
=False):
7865 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
7866 self
.notify_protection_to_owner(elem
, delete
)
7868 def notify_protection_to_owner(self
, elem
, delete
=False):
7869 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
7871 def getKeywords(self
):
7873 return self
._keywords
7878 def setKeywords(self
, keywords
):
7879 if type(keywords
) is list:
7880 self
._keywords
= keywords
[0]
7882 self
._keywords
= keywords
7883 self
.notifyModification(cleanCache
= False)
7885 def getFields( self
):
7891 if self
.summary
!= "":
7892 self
._fields
["summary"] = self
.summary
7898 def removeField( self
, field
):
7899 if self
.getFields().has_key(field
):
7900 del self
.getFields()[field
]
7901 self
.notifyModification()
7903 def setField( self
, field
, value
):
7905 self
.getFields()[field
] = value
7906 self
.notifyModification()
7910 def getField( self
, field
):
7911 if self
.getFields().has_key(field
):
7912 value
= self
.getFields()[field
]
7913 if type(value
) is list:
7914 return "".join(value
)
7922 def getLogInfo(self
):
7924 data
["subject"] = self
.getTitle()
7925 data
["id"] = self
.id
7926 data
["title"] = self
.title
7927 data
["parent title"] = self
.parent
.getTitle()
7928 if self
._session
is not None :
7929 data
["session title"] = self
._session
.getTitle()
7930 data
["description"] = self
.description
7931 if self
.getConference():
7932 afm
= self
.getConference().getAbstractMgr().getAbstractFieldsMgr()
7933 for f
in afm
.getFields():
7935 data
[id] = self
.getField(id)
7936 data
["start date"] = "%s"%self
.startDate
7937 data
["duration"] = "%s"%self
.duration
7938 if self
._track
is not None :
7939 data
["track"] = self
._track
.getTitle()
7940 if self
._type
is not None :
7941 data
["type"] = self
._type
7942 data
["speaker text"] = self
.speakerText
7943 if self
.place
is not None :
7944 data
["place"] = self
.place
.getName()
7945 if self
.room
is not None :
7946 data
["room"] = self
.room
.getName()
7947 data
["board number"] = self
._boardNumber
7948 for sc
in self
.getSubContributionList() :
7949 data
["subcontribution %s"%sc.getId()] = sc
.getTitle()
7950 for pa
in self
._primaryAuthors
:
7951 data
["primary author %s"%pa
.getId()] = pa
.getFullName()
7952 for ca
in self
._coAuthors
:
7953 data
["co-author %s"%ca
.getId()] = ca
.getFullName()
7954 for sp
in self
._speakers
:
7955 data
["speaker %s"%sp
.getId()] = sp
.getFullName()
7956 for s
in self
.getSubmitterList():
7957 if isinstance(s
, MaKaC
.user
.Avatar
):
7958 data
["submitter"] = s
.getFullName()
7960 data
["submitter"] = s
.getName()
7964 def setValues( self
, data
, check
=2, moveEntriesBelow
=0):
7965 """Sets all the values of the current contribution object from a
7966 dictionary containing the following key-value pairs:
7969 locationName-(str) => name of the location, if not specified
7970 it will be set to the parent location name.
7971 locationAddress-(str)
7972 roomName-(str) => name of the room, if not specified it will
7973 be set to the parent room name.
7974 year, month, day, sHour, sMinute - (str) => components of the
7975 starting date of the session, if not specified it will
7977 durationHours, durationMinutes - (str)
7981 1: check and raise error in case of problem
7982 2: check and adapt the owner dates
7985 1: moveEntries below the contribution
7986 Please, note that this method sets ALL values which means that if
7987 the given dictionary doesn't contain any of the keys the value
7988 will set to a default value.
7991 # In order to move the entries below, it is needed to know the diff (we have to move them)
7992 # and the list of entries to move. It's is needed to take those datas in advance because they
7993 # are going to be modified before the moving.
7994 if moveEntriesBelow
== 1:
7995 oldStartDate
=copy
.copy(self
.getStartDate())
7996 oldDuration
=copy
.copy(self
.getDuration())
7997 i
=self
.getSchEntry().getSchedule().getEntries().index(self
.getSchEntry())+1
7998 entriesList
= self
.getSchEntry().getSchedule().getEntries()[i
:]
7999 if data
.has_key("title"):
8000 self
.setTitle(data
["title"])
8001 if data
.has_key("keywords"):
8002 self
.setKeywords(data
["keywords"])
8003 if data
.has_key("description"):
8004 self
.setDescription(data
["description"])
8005 if data
.has_key("type") and self
.getConference():
8006 self
.setType(self
.getConference().getContribTypeById(data
["type"]))
8007 if self
.getConference():
8008 afm
= self
.getConference().getAbstractMgr().getAbstractFieldsMgr()
8009 for f
in afm
.getFields():
8011 if data
.has_key("f_%s"%id):
8012 self
.setField(id, data
["f_%s"%id])
8014 if "locationName" in data
:
8015 loc
=self
.getOwnLocation()
8017 loc
=CustomLocation()
8018 self
.setLocation(loc
)
8019 loc
.setName(data
["locationName"])
8020 loc
.setAddress(data
.get("locationAddress", ""))
8022 self
.setLocation(None)
8024 #same as for the location
8025 if "roomName" in data
:
8026 room
=self
.getOwnRoom()
8030 room
.setName(data
["roomName"])
8031 room
.retrieveFullName(data
.get("locationName", ""))
8036 if self
.getConference():
8037 tz
= self
.getConference().getTimezone()
8038 if data
.get("targetDay","")!="" and data
.get("sHour","")!="" and data
.get("sMinute","")!="" and check
==2:
8039 ############################################
8040 # Fermi timezone awareness #
8041 ############################################
8042 me
= timezone(tz
).localize(datetime(int(data
["targetDay"][0:4]), \
8043 int(data
["targetDay"][5:7]),int(data
["targetDay"][8:])))
8044 sdate
= timezone(tz
).localize(datetime(me
.year
,me
.month
, \
8045 me
.day
,int(data
["sHour"]),int(data
["sMinute"])))
8046 self
.setStartDate(sdate
.astimezone(timezone('UTC')),check
=2)
8047 if data
.get("sYear","")!="" and data
.get("sMonth","")!="" and \
8048 data
.get("sDay","")!="" and data
.get("sHour","")!="" and \
8049 data
.get("sMinute","")!="":
8050 self
.setStartDate(timezone(tz
).localize(datetime(int(data
["sYear"]),
8051 int(data
["sMonth"]), int(data
["sDay"]),
8052 int(data
["sHour"]), int(data
["sMinute"]))).astimezone(timezone('UTC')),
8054 ############################################
8055 # Fermi timezone awareness(end) #
8056 ############################################
8057 if data
.get("durTimedelta", "") != "":
8058 self
.setDuration(check
=check
, dur
=data
["durTimedelta"])
8059 elif data
.get("durHours","")!="" and data
.get("durMins","")!="":
8060 self
.setDuration(data
["durHours"],data
["durMins"],check
)
8062 h
=data
.get("durHours","").strip()
8063 m
=data
.get("durMins","").strip()
8067 if h
!="0" or m
!="0":
8068 self
.setDuration(int(h
), int(m
),check
)
8069 if data
.has_key("boardNumber"):
8070 self
.setBoardNumber(data
.get("boardNumber",""))
8071 if moveEntriesBelow
== 1:
8072 diff
= (self
.getStartDate() - oldStartDate
) + (self
.getDuration() - oldDuration
)
8073 self
.getConference().getSchedule().moveEntriesBelow(diff
, entriesList
)
8074 self
.notifyModification()
8076 def clone(self
, parent
, options
, deltaTime
= 0):
8077 cont
= Contribution()
8078 parent
.addContribution(cont
)
8079 cont
.setTitle( self
.getTitle() )
8080 cont
.setDescription( self
.getDescription() )
8081 for k
in self
.getFields().keys():
8082 cont
.setField(k
, self
.getField(k
))
8083 cont
.setKeywords( self
.getKeywords() )
8085 deltaTime
= parent
.getStartDate() - self
.getOwner().getStartDate()
8088 if self
.startDate
is not None :
8089 startDate
= self
.getStartDate() + deltaTime
8090 cont
.setStartDate( startDate
)
8092 cont
.setDuration( dur
=self
.getDuration() )
8094 if self
.getOwnLocation() is not None:
8095 cont
.setLocation(self
.getOwnLocation().clone())
8096 if self
.getOwnRoom() is not None:
8097 cont
.setRoom(self
.getOwnRoom().clone())
8098 cont
.setBoardNumber(self
.getBoardNumber())
8099 cont
.setReportNumberHolder(self
.getReportNumberHolder().clone(self
))
8101 cont
.setStatus(self
.getCurrentStatus())
8103 if self
.getType() is not None :
8104 for ct
in cont
.getConference().getContribTypeList() :
8105 if ct
.getName() == self
.getType().getName() :
8109 if options
.get("tracks", False) :
8110 if self
.getTrack() is not None :
8111 for tr
in cont
.getConference().getTrackList() :
8112 if tr
.getTitle() == self
.getTrack().getTitle() :
8118 if options
.get("access", False) :
8119 cont
.setProtection(self
.getAccessController()._getAccessProtection
())
8120 for u
in self
.getAllowedToAccessList() :
8122 for mgr
in self
.getManagerList() :
8123 cont
.grantModification(mgr
)
8124 for sub
in self
.getSubmitterList() :
8125 cont
.grantSubmission(sub
)
8126 for domain
in self
.getDomainList():
8127 cont
.requireDomain(domain
)
8129 if options
.get("authors", False) :
8130 for a
in self
.getPrimaryAuthorList() :
8131 cont
.addPrimaryAuthor(a
.clone())
8132 for ca
in self
.getCoAuthorList() :
8133 cont
.addCoAuthor(ca
.clone())
8134 for sp
in self
.getSpeakerList():
8135 cont
.newSpeaker(sp
.clone())
8136 cont
.setSpeakerText(self
.getSpeakerText())
8138 if options
.get("materials", False) :
8139 for m
in self
.getMaterialList() :
8140 cont
.addMaterial(m
.clone(cont
))
8141 if self
.getPaper() is not None:
8142 cont
.setPaper(self
.getPaper().clone(cont
))
8143 if self
.getSlides() is not None:
8144 cont
.setSlides(self
.getSlides().clone(cont
))
8145 if self
.getVideo() is not None:
8146 cont
.setVideo(self
.getVideo().clone(cont
))
8147 if self
.getPoster() is not None:
8148 cont
.setPoster(self
.getPoster().clone(cont
))
8149 if self
.getMinutes() is not None:
8150 cont
.setMinutes(self
.getMinutes().clone(cont
))
8151 if self
.getReviewing() is not None:
8152 cont
.setReviewing(self
.getReviewing().clone(cont
))
8154 if options
.get("subcontribs", False) :
8155 for sc
in self
.getSubContributionList() :
8156 cont
.addSubContribution(sc
.clone(cont
, self
, options
))
8159 def notifyModification( self
, date
= None, raiseEvent
= True, cleanCache
= True):
8160 self
.setModificationDate(date
)
8163 self
._notify
('infoChanged')
8169 parent
= self
.getParent()
8171 parent
.setModificationDate()
8174 def cleanCache(self
, cleanConference
= True):
8175 # Do not clean cache if already cleaned
8176 if not ContextManager
.get('clean%s'%self
.getUniqueId(), False):
8177 ScheduleToJson
.cleanCache(self
)
8178 ContextManager
.set('clean%s'%self
.getUniqueId(), cleanConference
)
8180 def getCategoriesPath(self
):
8181 return self
.getConference().getCategoriesPath()
8183 def getModifKey( self
):
8184 return self
.getConference().getModifKey()
8186 def getAccessKey( self
):
8187 return self
.getConference().getAccessKey()
8189 def getLocator( self
):
8190 """Gives back a globaly unique identification encapsulated in a Locator
8191 object for the contribution instance
8193 if self
.getConference() == None:
8195 lconf
= self
.getConference().getLocator()
8196 if self
.getSession() is not None:
8197 lconf
["sessionId"] = self
.getSession().getId()
8198 lconf
["contribId"] = self
.getId()
8201 def _setConference( self
, conf
):
8204 def _setId( self
, id ):
8207 def includeInConference( self
, conf
, id ):
8208 """sets the conference of a contribution
8210 if self
.getConference() is not None:
8211 #raise MaKaCError("the contribution is already included in a conference")
8214 self
._setConference
( conf
)
8218 """deletes a contribution and all of its subitems
8221 oldParent
= self
.getConference()
8223 if oldParent
!= None:
8224 self
._notify
('deleted', oldParent
)
8227 for mat
in self
.getMaterialList():
8228 self
.removeMaterial(mat
)
8233 self
.removeMinutes()
8234 self
.removeReviewing()
8236 self
.notify_protection_to_owner(self
, delete
=True)
8238 self
.setSession(None)
8240 while len(self
.getSubContributionList()) > 0:
8242 sc
= self
.getSubContributionList()[0]
8244 self
.removeSubContribution(sc
)
8247 # delete it from parent session (if it exists)
8248 if self
.getOwner() != self
.getConference():
8250 self
.getOwner().removeContribution( self
)
8252 # (always) delete it from the parent conference
8253 self
.getConference().removeContribution( self
, callDelete
=False )
8255 self
._setConference
( None )
8257 self
.setStatus(ContribStatusNone(self
))
8259 TrashCanManager().add(self
)
8262 TrashCanManager().remove(self
)
8264 def setId( self
, newId
):
8270 def getUniqueId( self
):
8271 """returns (string) the unique identifier of the item"""
8272 """used mainly in the web session access key table"""
8273 return "%st%s" % (self
.getConference().getUniqueId(),self
.id)
8275 def setTitle( self
, newTitle
, notify
= True ):
8276 oldTitle
= self
.title
8277 self
.title
= newTitle
.strip()
8280 self
._notify
('contributionTitleChanged', oldTitle
, newTitle
)
8281 self
.notifyModification()
8283 def getTitle( self
):
8284 if self
.title
.strip() == "":
8288 #def setDescription( self, newDesc ):
8289 # self.description = newDesc.strip()
8290 # self.notifyModification()
8292 #def getDescription( self ):
8293 # return self.description
8295 def getDescription(self
):
8296 return self
.getField("content")
8298 def setDescription(self
, desc
):
8299 self
.setField("content", desc
)
8301 def setParent(self
,parent
):
8303 self
.notifyModification(cleanCache
= False)
8304 if self
.parent
==None:
8307 def getParent( self
):
8308 if self
.getSession() is not None:
8309 return self
.getSession()
8310 return self
.getConference()
8312 def getOwner( self
):
8313 return self
.getParent()
8315 def setOwner(self
, owner
):
8316 self
.setParent(owner
)
8318 def getConference( self
):
8321 def getSession( self
):
8325 except AttributeError:
8327 return self
._session
8329 def setSession(self
,session
):
8330 if self
.getSession()==session
:
8332 if self
.isScheduled():
8333 schEntry
=self
.getSchEntry()
8334 schEntry
.getSchedule().removeEntry(schEntry
)
8335 oldSession
=self
.getSession()
8336 if oldSession
is not None:
8337 oldSession
.removeContribution(self
)
8338 self
._session
=session
8339 if session
is not None:
8340 session
.addContribution(self
)
8342 def getContribution(self
):
8345 def _resetSchEntry(self
):
8346 self
.__schEntry
=ContribSchEntry(self
)
8348 def getSchEntry(self
):
8349 if self
.__schEntry
is None or \
8350 not isinstance(self
.__schEntry
,ContribSchEntry
):
8351 self
._resetSchEntry
()
8352 return self
.__schEntry
8354 def isScheduled(self
):
8355 #For the moment we do it like this
8356 return self
.getSchEntry().getSchedule() is not None
8358 def isWithdrawn(self
):
8359 return isinstance(self
.getCurrentStatus(), ContribStatusWithdrawn
)
8361 def getLocationParent( self
):
8363 Returns the object from which the room/location
8364 information should be inherited
8366 if not self
.getConference().getEnableSessionSlots() and self
.getSession():
8367 return self
.getSession()
8368 if self
.isScheduled():
8369 return self
.getSchEntry().getSchedule().getOwner()
8370 return self
.getOwner()
8372 def getOwnLocation( self
):
8375 def setLocation( self
, newLocation
):
8376 oldLocation
= self
.place
8377 self
.place
= newLocation
8378 self
._notify
('locationChanged', oldLocation
, newLocation
)
8379 self
.notifyModification()
8381 def getOwnRoom( self
):
8384 def setRoom( self
, newRoom
):
8387 self
._notify
('roomChanged', oldRoom
, newRoom
)
8388 self
.notifyModification()
8390 def setBoardNumber(self
,newBoardNum
):
8391 self
._boardNumber
=str(newBoardNum
).strip()
8393 def getBoardNumber(self
):
8395 if self
._boardNumber
:
8397 except AttributeError:
8398 self
._boardNumber
=""
8399 return self
._boardNumber
8401 def verifyStartDate(self
, sDate
, check
=2):
8404 1: check and raise error in case of problem
8405 2: check and adapt the owner dates"""
8407 tz
= timezone(self
.getConference().getTimezone())
8408 if self
.getSchEntry().getSchedule():
8409 owner
= self
.getSchEntry().getSchedule().getOwner()
8411 owner
= self
.getOwner()
8412 if sDate
< owner
.getStartDate():
8414 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start before (%s) its parent (%s)") %\
8415 (self
.getTitle(), sDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8416 owner
.getStartDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
8419 ContextManager
.get('autoOps').append((self
, "OWNER_START_DATE_EXTENDED",
8420 owner
, sDate
.astimezone(tz
)))
8421 owner
.setDates(sDate
,owner
.getEndDate(), check
)
8422 if sDate
> owner
.getEndDate():
8424 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start after (%s) its parent end date(%s)") %\
8425 (self
.getTitle(), sDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8426 owner
.getEndDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
8429 owner
.setEndDate(sDate
+self
.getDuration(),check
)
8430 # Check that after modifying the start date, the end date is still within the limits of the slot
8431 if self
.getDuration() and sDate
+ self
.getDuration() > owner
.getEndDate():
8433 raise ParentTimingError("The contribution cannot end after (%s) its parent ends (%s)"%\
8434 ((sDate
+ self
.getDuration()).astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8435 owner
.getAdjustedEndDate().strftime('%Y-%m-%d %H:%M')),\
8438 # update the schedule
8439 owner
.setEndDate(sDate
+ self
.getDuration(),check
)
8440 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
8441 owner
, owner
.getAdjustedEndDate()))
8443 def setStartDate(self
, newDate
, check
=2, moveEntries
=0):
8446 1: check and raise error in case of problem
8447 2: check and adapt the owner dates"""
8451 if not newDate
.tzname():
8452 raise MaKaCError("date should be timezone aware")
8454 if newDate
!= None and check
!= 0:
8455 self
.verifyStartDate(newDate
, check
)
8456 self
._notify
("contributionUnscheduled")
8457 self
.startDate
=copy
.copy(newDate
)
8458 self
._notify
("contributionScheduled")
8459 self
.getSchEntry().synchro()
8460 self
.notifyModification()
8462 def getStartDate( self
):
8463 return self
.startDate
8465 def getAdjustedStartDate(self
,tz
=None):
8466 if self
.getStartDate() is None:
8469 tz
= self
.getConference().getTimezone()
8470 if tz
not in all_timezones
:
8472 return self
.getStartDate().astimezone(timezone(tz
))
8474 def getEndDate( self
):
8475 if self
.getStartDate() is None:
8477 return self
.getStartDate()+self
.getDuration()
8479 def getAdjustedEndDate(self
,tz
=None):
8481 tz
= self
.getConference().getTimezone()
8482 if tz
not in all_timezones
:
8484 if self
.getEndDate():
8485 return self
.getEndDate().astimezone(timezone(tz
))
8488 def getDuration( self
):
8489 return self
.duration
8491 def verifyDuration(self
, check
=2):
8494 1: check and raise error in case of problem
8495 2: check and adapt the owner dates"""
8497 tz
= timezone(self
.getConference().getTimezone())
8499 endDate
= self
.getEndDate()
8501 if self
.getSchEntry().getSchedule() is not None:
8502 owner
= self
.getSchEntry().getSchedule().getOwner()
8503 if endDate
> owner
.getEndDate():
8505 raise ParentTimingError(_("The contribution \"%s\" ending date (%s) has to fit between its parent's dates (%s - %s)") %\
8506 (self
.getTitle(), endDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8507 owner
.getStartDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8508 owner
.getEndDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
8511 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
8512 owner
, self
.getAdjustedEndDate()))
8513 owner
.setEndDate(endDate
, check
)
8515 def setDuration(self
,hours
=0,minutes
=15,check
=2,dur
=0):
8518 1: check and raise error in case of problem
8519 2: check and adapt the owner dates"""
8524 self
.duration
=timedelta(hours
=int(hours
),minutes
=int(minutes
))
8526 self
.verifyDuration(check
)
8527 self
.getSchEntry().synchro()
8528 self
.notifyModification()
8530 def _addAuthor( self
, part
):
8536 except AttributeError:
8537 self
._authors
= OOBTree()
8541 except AttributeError:
8542 self
._authorGen
=Counter()
8543 newId
= part
.getId()
8545 newId
= str( self
._authorGen
.newCount() )
8546 self
._authors
[newId
] = part
8547 part
.includeInContribution( self
, newId
)
8549 def _removeAuthor( self
, part
):
8555 except AttributeError:
8556 self
._authors
= OOBTree()
8557 if not self
._authors
.has_key( part
.getId() ):
8559 del self
._authors
[ part
.getId() ]
8562 def addPrimaryAuthor( self
, part
, index
= None ):
8566 if self
._primaryAuthors
:
8568 except AttributeError:
8569 self
._primaryAuthors
= []
8570 self
._addAuthor
( part
)
8571 if index
is not None:
8572 self
._primaryAuthors
.insert(index
, part
)
8574 self
._primaryAuthors
.append( part
)
8575 if self
.getConference() is not None:
8576 self
.getConference().indexAuthor(part
)
8577 self
.notifyModification(cleanCache
= False)
8579 def removePrimaryAuthor( self
, part
, removeSpeaker
=1, removePendingSubm
=True):
8583 if self
._primaryAuthors
:
8585 except AttributeError:
8586 self
._primaryAuthors
= []
8587 if part
not in self
._primaryAuthors
:
8589 if self
.getConference() is not None:
8590 self
.getConference().unindexAuthor(part
)
8591 self
._primaryAuthors
.remove( part
)
8593 self
.removeSpeaker( part
)
8594 self
._removeAuthor
( part
)
8595 if removePendingSubm
:
8596 #--Pending queue: remove pending participant waiting to became submitter if anything
8597 self
.getConference().getPendingQueuesMgr().removePendingSubmitter(part
)
8599 self
.notifyModification(cleanCache
= False)
8601 def recoverPrimaryAuthor(self
, pa
, isPendingSubmitter
):
8602 self
.addPrimaryAuthor(pa
)
8604 if isPendingSubmitter
:
8605 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(pa
, False)
8607 def isPrimaryAuthor( self
, part
):
8611 if self
._primaryAuthors
:
8613 except AttributeError:
8614 self
._primaryAuthors
= []
8615 return part
in self
._primaryAuthors
8617 def isCoAuthor(self
, part
):
8621 except AttributeError:
8622 self
._coAuthors
= []
8623 return part
in self
._coAuthors
8625 def isPrimaryAuthorByEmail(self
, email
):
8626 for prAuthor
in self
.getPrimaryAuthorList():
8627 if prAuthor
.getEmail() == email
:
8631 def isCoAuthorByEmail(self
, email
):
8632 for coAuthor
in self
.getCoAuthorList():
8633 if coAuthor
.getEmail() == email
:
8637 def isSpeakerByEmail(self
, email
):
8638 for speaker
in self
.getSpeakerList():
8639 if speaker
.getEmail() == email
:
8643 def changePosPrimaryAuthor(self
,part
,index
):
8647 if self
._primaryAuthors
:
8649 except AttributeError:
8650 self
._primaryAuthors
=[]
8651 if not part
in self
._primaryAuthors
:
8653 self
._primaryAuthors
.remove(part
)
8654 self
._primaryAuthors
.insert(index
,part
)
8655 self
.notifyModification(cleanCache
= False)
8657 def upPrimaryAuthor(self
,part
):
8661 if self
._primaryAuthors
:
8663 except AttributeError:
8664 self
._primaryAuthors
=[]
8666 idx
=self
._primaryAuthors
.index(part
)
8671 self
._primaryAuthors
.remove(part
)
8672 self
._primaryAuthors
.insert(idx
-1,part
)
8673 self
.notifyModification(cleanCache
= False)
8675 def downPrimaryAuthor(self
,part
):
8679 if self
._primaryAuthors
:
8681 except AttributeError:
8682 self
._primaryAuthors
=[]
8684 idx
=self
._primaryAuthors
.index(part
)
8687 if idx
>len(self
._primaryAuthors
):
8689 self
._primaryAuthors
.remove(part
)
8690 self
._primaryAuthors
.insert(idx
+1,part
)
8691 self
.notifyModification(cleanCache
= False)
8693 def newAuthorsList(self
, prAuthors
, coAuthors
):
8694 ''' calculate new lists of both kind of authors, because something has
8695 been changed the position by drag and drop '''
8696 newPrList
= self
.calculateNewAuthorList(prAuthors
, "prAuthor")
8697 newCoList
= self
.calculateNewAuthorList(coAuthors
, "coAuthor")
8698 self
.setPrimaryAuthorList(newPrList
)
8699 self
.setCoAuthorList(newCoList
)
8701 def calculateNewAuthorList(self
, list, kind
):
8703 if kind
== "prAuthor":
8705 author
= self
.getPrimaryAuthorById(auth
['id'])
8707 result
.append(author
)
8709 author
= self
.getCoAuthorById(auth
['id'])
8711 result
.append(author
)
8713 elif kind
== "coAuthor":
8715 author
= self
.getCoAuthorById(auth
['id'])
8717 result
.append(author
)
8719 author
= self
.getPrimaryAuthorById(auth
['id'])
8721 result
.append(author
)
8725 def getPrimaryAuthorById(self
, authorId
):
8726 for author
in self
.getPrimaryAuthorList():
8727 if authorId
== author
.getId():
8731 def getCoAuthorById(self
, authorId
):
8732 for author
in self
.getCoAuthorList():
8733 if authorId
== author
.getId():
8737 def setPrimaryAuthorList(self
, l
):
8738 self
._primaryAuthors
= l
8739 self
.notifyModification(cleanCache
= False)
8741 def setCoAuthorList(self
, l
):
8743 self
.notifyModification(cleanCache
= False)
8745 def changePosCoAuthor(self
, part
, index
):
8751 except AttributeError:
8753 if not part
in self
._coAuthors
:
8755 self
._coAuthors
.remove(part
)
8756 self
._coAuthors
.insert(index
,part
)
8757 self
.notifyModification(cleanCache
= False)
8760 def upCoAuthor(self
,part
):
8766 except AttributeError:
8769 idx
=self
._coAuthors
.index(part
)
8774 self
._coAuthors
.remove(part
)
8775 self
._coAuthors
.insert(idx
-1,part
)
8776 self
.notifyModification(cleanCache
= False)
8778 def downCoAuthor(self
,part
):
8784 except AttributeError:
8787 idx
=self
._coAuthors
.index(part
)
8790 if idx
>len(self
._coAuthors
):
8792 self
._coAuthors
.remove(part
)
8793 self
._coAuthors
.insert(idx
+1,part
)
8794 self
.notifyModification(cleanCache
= False)
8796 def getPrimaryAuthorList( self
):
8800 if self
._primaryAuthors
:
8802 except AttributeError:
8803 self
._primaryAuthors
= []
8804 return self
._primaryAuthors
8806 getPrimaryAuthorsList
= getPrimaryAuthorList
8808 def getAuthorList( self
):
8814 except AttributeError:
8815 self
._authors
= OOBTree()
8816 return self
._authors
.values()
8818 def getAllAuthors(self
):
8819 """ This method returns a list composed by the primary authors
8820 and co-authors. The different with getAuthorList() is the type
8823 return self
.getPrimaryAuthorList() + self
.getCoAuthorList()
8825 def addCoAuthor( self
, part
, index
=None ):
8831 except AttributeError:
8832 self
._coAuthors
= []
8833 self
._addAuthor
( part
)
8834 if index
is not None:
8835 self
._coAuthors
.insert(index
, part
)
8837 self
._coAuthors
.append( part
)
8838 if self
.getConference() is not None:
8839 self
.getConference().indexAuthor(part
)
8840 self
.notifyModification(cleanCache
= False)
8842 def removeCoAuthor( self
, part
, removeSpeaker
=1, removePendingSubm
=True):
8848 except AttributeError:
8849 self
._coAuthors
= []
8850 if part
not in self
._coAuthors
:
8852 if self
.getConference() is not None:
8853 self
.getConference().unindexAuthor(part
)
8854 self
._coAuthors
.remove( part
)
8856 self
.removeSpeaker( part
)
8857 self
._removeAuthor
( part
)
8858 if removePendingSubm
:
8859 #--Pending queue: remove pending participant waiting to became submitter if anything
8860 self
.getConference().getPendingQueuesMgr().removePendingSubmitter(part
)
8862 self
.notifyModification(cleanCache
= False)
8864 def recoverCoAuthor(self
, ca
, isPendingSubmitter
):
8865 self
.addCoAuthor(ca
)
8867 if isPendingSubmitter
:
8868 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(ca
, False)
8870 def getCoAuthorList( self
):
8876 except AttributeError:
8877 self
._coAuthors
= []
8878 return self
._coAuthors
8880 def getAuthorById( self
, authorId
):
8886 except AttributeError:
8887 self
._authors
= OOBTree()
8888 return self
._authors
.get( authorId
.strip(), None )
8890 def isAuthor( self
, part
):
8896 except AttributeError:
8897 self
._authors
= OOBTree()
8898 return self
._authors
.has_key( part
.getId() )
8900 def getSpeakerById( self
, authorId
):
8906 except AttributeError:
8908 for spk
in self
._speakers
:
8909 if spk
.getId() == authorId
:
8913 def changePosSpeaker(self
,part
,index
):
8919 except AttributeError:
8921 if not part
in self
._speakers
:
8923 self
._speakers
.remove(part
)
8924 self
._speakers
.insert(index
,part
)
8925 self
.notifyModification()
8927 def addSpeaker( self
, part
, index
=None ):
8929 Adds a speaker (ContributionParticipation object) to the contribution
8930 forcing it to be one of the authors of the contribution
8935 except AttributeError:
8937 if not self
.isAuthor( part
):
8938 raise MaKaCError( _("The Specified speaker is not the Author"), _("Contribution"))
8939 if index
is not None:
8940 self
._speakers
.insert(index
, part
)
8942 self
._speakers
.append( part
)
8943 if self
.getConference() is not None:
8944 self
.getConference().indexSpeaker(part
)
8945 self
.notifyModification()
8947 def newSpeaker( self
, part
):
8949 Adds a new speaker (ContributionParticipation object) to the contribution
8950 setting the speakers ID and the fact it belongs to that contribution
8955 except AttributeError:
8960 except AttributeError:
8961 self
._authorGen
=Counter()
8962 self
._speakers
.append( part
)
8963 newId
= part
.getId()
8965 newId
= str( self
._authorGen
.newCount() )
8966 part
.includeInContribution(self
, newId
)
8967 if self
.getConference() is not None:
8968 self
.getConference().indexSpeaker(part
)
8969 self
.notifyModification()
8971 def removeSpeaker( self
, part
):
8977 except AttributeError:
8979 if part
not in self
._speakers
:
8981 self
._speakers
.remove( part
)
8982 if self
.getConference() is not None:
8983 self
.getConference().unindexSpeaker(part
)
8984 if part
not in self
.getAuthorList():
8986 #--Pending queue: remove pending participant waiting to became submitter if anything
8987 self
.getConference().getPendingQueuesMgr().removePendingSubmitter(part
)
8989 self
.notifyModification()
8991 def recoverSpeaker(self
, spk
, isPendingSubmitter
):
8992 self
.newSpeaker(spk
)
8994 if isPendingSubmitter
:
8995 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(spk
, False)
8997 def isSpeaker( self
, part
):
9003 except AttributeError:
9005 return part
in self
._speakers
9007 def getSpeakerList ( self
):
9013 except AttributeError:
9015 return self
._speakers
9017 def getSpeakerText( self
):
9020 if self
.speakerText
:
9022 except AttributeError, e
:
9023 self
.speakerText
= ""
9024 return self
.speakerText
9026 def setSpeakerText( self
, newText
):
9027 self
.speakerText
= newText
.strip()
9029 def appendSpeakerText( self
, newText
):
9030 self
.setSpeakerText( "%s, %s"%(self
.getSpeakerText(), newText
.strip()) )
9032 def canIPAccess( self
, ip
):
9033 if not self
.__ac
.canIPAccess( ip
):
9035 if self
.getOwner() != None:
9036 return self
.getOwner().canIPAccess(ip
)
9039 def isProtected( self
):
9040 # tells if a contribution is protected or not
9041 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
9043 def getAccessProtectionLevel( self
):
9044 return self
.__ac
.getAccessProtectionLevel()
9046 def isItselfProtected( self
):
9047 return self
.__ac
.isItselfProtected()
9049 def hasAnyProtection( self
):
9050 """Tells whether a contribution has any kind of protection over it:
9051 access or domain protection.
9053 if self
.__ac
.isProtected():
9055 if self
.getDomainList():
9057 if self
.getAccessProtectionLevel() == -1:
9060 return self
.getOwner().hasAnyProtection()
9064 def hasProtectedOwner( self
):
9065 if self
.getOwner() != None:
9066 return self
.getOwner().isProtected()
9069 def setProtection( self
, private
):
9071 oldValue
= 1 if self
.isProtected() else -1
9073 self
.__ac
.setProtection( private
)
9074 self
.notify_protection_to_owner(self
)
9076 if oldValue
!= private
:
9078 self
._notify
('protectionChanged', oldValue
, private
)
9080 def grantAccess( self
, prin
):
9081 self
.__ac
.grantAccess( prin
)
9082 if isinstance(prin
, MaKaC
.user
.Avatar
):
9083 prin
.linkTo(self
, "access")
9084 self
.notifyModification(raiseEvent
= False)
9086 def revokeAccess( self
, prin
):
9087 self
.__ac
.revokeAccess( prin
)
9088 if isinstance(prin
, MaKaC
.user
.Avatar
):
9089 prin
.unlinkTo(self
, "access")
9090 self
.notifyModification(raiseEvent
= False)
9092 def canView( self
, aw
):
9093 """tells whether the specified user has access to the current object
9094 or any of its sub-objects
9096 if self
.canAccess( aw
):
9098 ### TODO: Replace this code when plugins allow extension points+notifications ##################
9099 from MaKaC
.webinterface
.rh
.collaboration
import RCCollaborationAdmin
, RCCollaborationPluginAdmin
9100 if RCCollaborationAdmin
.hasRights(user
=aw
.getUser()) or \
9101 RCCollaborationPluginAdmin
.hasRights(user
=aw
.getUser(), plugins
='any'):
9103 ################################################################################################
9104 for sc
in self
.getSubContributionList():
9105 if sc
.canView( aw
):
9109 def isAllowedToAccess( self
, user
):
9112 return (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess( user
)) or\
9113 self
.__ac
.canUserAccess( user
) or\
9114 self
.canUserModify( user
) or \
9115 self
.canUserSubmit(user
)
9117 def canAccess( self
, aw
):
9118 # Allow harvesters (Invenio, offline cache) to access
9120 if self
.__ac
.isHarvesterIP(aw
.getIP()):
9122 #####################################################
9124 if self
.canModify(aw
):
9127 if not self
.canIPAccess(aw
.getIP()) and not self
.isAllowedToAccess( aw
.getUser() ):
9129 if not self
.isProtected():
9131 flag
= self
.isAllowedToAccess( aw
.getUser() )
9132 return flag
or self
.getConference().canKeyAccess(aw
)
9134 def grantModification( self
, prin
):
9135 self
.__ac
.grantModification( prin
)
9136 if isinstance(prin
, MaKaC
.user
.Avatar
):
9137 prin
.linkTo(self
, "manager")
9138 self
.notifyModification(raiseEvent
= False)
9140 def revokeModification( self
, prin
):
9141 self
.__ac
.revokeModification( prin
)
9142 if isinstance(prin
, MaKaC
.user
.Avatar
):
9143 prin
.unlinkTo(self
, "manager")
9144 self
.notifyModification(raiseEvent
= False)
9146 def canModify( self
, aw
):
9147 return self
.canUserModify( aw
.getUser() ) or self
.getConference().canKeyModify( aw
)
9149 def canUserModify( self
, av
):
9150 """Tells whether a user is allowed to modify the current contribution:
9151 only if the user is granted to modify the contribution or the user
9152 can modify any of its upper objects (i.e. conference or session).
9154 return self
.getParent().canUserModify( av
) or self
.__ac
.canModify( av
)
9156 def getManagerList( self
):
9157 return self
.__ac
.getModifierList()
9159 def getAllowedToAccessList( self
):
9160 return self
.__ac
.getAccessList()
9162 def addMaterial( self
, newMat
):
9163 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
9164 newMat
.setOwner( self
)
9165 self
.materials
[ newMat
.getId() ] = newMat
9166 self
.notifyModification()
9168 def removeMaterial( self
, mat
):
9169 if mat
.getId() in self
.materials
.keys():
9171 self
.materials
[mat
.getId()].setOwner(None)
9172 del self
.materials
[ mat
.getId() ]
9173 self
.notifyModification()
9174 elif mat
.getId().lower() == 'paper':
9176 elif mat
.getId().lower() == 'slides':
9178 elif mat
.getId().lower() == 'minutes':
9179 self
.removeMinutes()
9180 elif mat
.getId().lower() == 'video':
9182 elif mat
.getId().lower() == 'poster':
9185 def recoverMaterial(self
, recMat
):
9186 # Id must already be set in recMat.
9187 recMat
.setOwner( self
)
9188 self
.materials
[ recMat
.getId() ] = recMat
9190 self
.notifyModification()
9192 def getMaterialRegistry(self
):
9194 Return the correct material registry for this type
9196 from MaKaC
.webinterface
.materialFactories
import ContribMFRegistry
9197 return ContribMFRegistry
9199 def getMaterialById( self
, matId
):
9200 if matId
.lower() == 'paper':
9201 return self
.getPaper()
9202 elif matId
.lower() == 'slides':
9203 return self
.getSlides()
9204 elif matId
.lower() == 'video':
9205 return self
.getVideo()
9206 elif matId
.lower() == 'poster':
9207 return self
.getPoster()
9208 elif matId
.lower() == 'minutes':
9209 return self
.getMinutes()
9210 elif self
.materials
.has_key(matId
):
9211 return self
.materials
[ matId
]
9214 def getMaterialList( self
):
9215 return self
.materials
.values()
9217 def getAllMaterialList(self
, sort
=True):
9218 l
= self
.getMaterialList()
9220 l
.append( self
.getPaper() )
9221 if self
.getSlides():
9222 l
.append( self
.getSlides() )
9224 l
.append( self
.getVideo() )
9225 if self
.getPoster():
9226 l
.append( self
.getPoster() )
9227 if self
.getMinutes():
9228 l
.append( self
.getMinutes() )
9230 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
9233 def getAllViewableMaterialList( self
, aw
=None ):
9235 aw
= ContextManager
.get("currentRH").getAW()
9236 return [mat
for mat
in self
.getAllMaterialList() if mat
.canView(aw
)]
9239 def newSubContribution(self
):
9240 newSub
= SubContribution()
9241 self
.addSubContribution(newSub
)
9242 newSub
._notify
('created', self
)
9245 def addSubContribution( self
, newSubCont
):
9246 newSubCont
.setId(str( self
.__subContGenerator
.newCount()) )
9247 newSubCont
.setOwner( self
)
9248 self
._subConts
.append( newSubCont
)
9249 self
.notifyModification(cleanCache
= False)
9251 def removeSubContribution( self
, subCont
):
9252 if subCont
in self
._subConts
:
9254 subCont
.setOwner(None)
9255 self
._subConts
.remove(subCont
)
9256 self
.notifyModification(cleanCache
= False)
9258 def recoverSubContribution( self
, recSubCont
):
9259 # Id must already be set in recSubCont.
9260 recSubCont
.setOwner( self
)
9261 self
._subConts
.append( recSubCont
)
9262 recSubCont
.recover()
9263 self
.notifyModification(cleanCache
= False)
9265 def getSubContributionById(self
, SCId
):
9266 for sb
in self
._subConts
:
9267 if sb
.getId() == SCId
:
9270 def getSubContributionList(self
):
9271 return self
._subConts
9273 def iterSubContributions(self
):
9274 return iter(self
._subConts
)
9276 def getNumberOfSubcontributions(self
):
9277 return len(self
._subConts
)
9279 def upSubContribution(self
, subcont
):
9280 if subcont
in self
._subConts
:
9281 if self
._subConts
.index(subcont
) != 0:
9282 index
= self
._subConts
.index(subcont
)
9283 sb
= self
._subConts
.pop(index
)
9284 self
._subConts
.insert(index
-1, sb
)
9285 self
.notifyModification(cleanCache
= False)
9287 def downSubContribution(self
, subCont
):
9288 if subCont
in self
._subConts
:
9289 if self
._subConts
.index(subCont
) < len(self
._subConts
)-1:
9290 index
= self
._subConts
.index(subCont
)
9291 sb
= self
._subConts
.pop(index
)
9292 self
._subConts
.insert(index
+1, sb
)
9293 self
.notifyModification(cleanCache
= False)
9295 def setPaper( self
, newPaper
):
9296 if self
.getPaper() != None:
9297 raise MaKaCError( _("The paper for this contribution has already been set"), _("Contribution"))
9299 self
.paper
.setOwner( self
)
9300 self
.notifyModification()
9302 def removePaper( self
):
9303 if self
.paper
is None:
9306 self
.paper
.setOwner(None)
9308 self
.notifyModification()
9310 def recoverPaper(self
, p
):
9314 def getPaper( self
):
9317 def setSlides( self
, newSlides
):
9318 if self
.getSlides() != None:
9319 raise MaKaCError( _("The slides for this contribution have already been set"), _("contribution"))
9320 self
.slides
=newSlides
9321 self
.slides
.setOwner( self
)
9322 self
.notifyModification()
9324 def removeSlides( self
):
9325 if self
.slides
is None:
9327 self
.slides
.delete()
9328 self
.slides
.setOwner( None )
9330 self
.notifyModification()
9332 def recoverSlides(self
, s
):
9336 def getSlides( self
):
9339 def setVideo( self
, newVideo
):
9340 if self
.getVideo() != None:
9341 raise MaKaCError( _("the video for this contribution has already been set"))
9343 self
.video
.setOwner( self
)
9344 self
.notifyModification()
9346 def removeVideo( self
):
9347 if self
.getVideo() is None:
9350 self
.video
.setOwner(None)
9352 self
.notifyModification()
9354 def recoverVideo(self
, v
):
9358 def getVideo( self
):
9362 except AttributeError:
9366 def setPoster( self
, newPoster
):
9367 if self
.getPoster() != None:
9368 raise MaKaCError( _("the poster for this contribution has already been set"))
9369 self
.poster
=newPoster
9370 self
.poster
.setOwner( self
)
9371 self
.notifyModification()
9373 def removePoster( self
):
9374 if self
.getPoster() is None:
9376 self
.poster
.delete()
9377 self
.poster
.setOwner(None)
9379 self
.notifyModification()
9381 def recoverPoster(self
, p
):
9385 def getPoster( self
):
9389 except AttributeError:
9393 def setMinutes( self
, newMinutes
):
9394 if self
.getMinutes() != None:
9395 raise MaKaCError( _("the Minutes for this contribution has already been set"))
9396 self
.minutes
=newMinutes
9397 self
.minutes
.setOwner( self
)
9398 self
.notifyModification()
9400 def createMinutes( self
):
9401 if self
.getMinutes() != None:
9402 raise MaKaCError( _("The minutes for this contribution have already been created"), _("Contribution"))
9403 self
.minutes
= Minutes()
9404 self
.minutes
.setOwner( self
)
9405 self
.notifyModification()
9408 def removeMinutes( self
):
9409 if self
.getMinutes() is None:
9411 self
.minutes
.delete()
9412 self
.minutes
.setOwner( None )
9414 self
.notifyModification()
9416 def recoverMinutes(self
, min):
9417 self
.removeMinutes() # To ensure that the current minutes are put in
9420 self
.minutes
.setOwner( self
)
9422 self
.notifyModification()
9425 def getMinutes( self
):
9430 except AttributeError, e
:
9434 def setReviewing( self
, newReviewing
):
9435 if self
.getReviewing() != None:
9436 raise MaKaCError( _("The reviewing maretial for this contribution has already been set"), _("Contribution"))
9437 self
.reviewing
=newReviewing
9438 self
.reviewing
.setOwner( self
)
9439 self
.notifyModification()
9441 def removeReviewing( self
):
9442 if self
.getReviewing() is None:
9444 self
.reviewing
.delete()
9445 self
.reviewing
.setOwner(None)
9446 self
.reviewing
= None
9447 self
.notifyModification()
9449 def recoverReviewing(self
, p
):
9450 self
.setReviewing(p
)
9453 def getReviewing( self
):
9457 except AttributeError, e
:
9458 self
.reviewing
= None
9459 return self
.reviewing
9461 def getMasterSchedule( self
):
9462 return self
.getOwner().getSchedule()
9464 def requireDomain( self
, dom
):
9465 self
.__ac
.requireDomain( dom
)
9466 self
._notify
('domainAdded', dom
)
9468 def freeDomain( self
, dom
):
9469 self
.__ac
.freeDomain( dom
)
9470 self
._notify
('domainRemoved', dom
)
9472 def getDomainList( self
):
9473 return self
.__ac
.getRequiredDomainList()
9475 def getTrack( self
):
9479 except AttributeError:
9483 def setTrack( self
, newTrack
):
9484 currentTrack
= self
.getTrack()
9485 if newTrack
== currentTrack
:
9488 currentTrack
.removeContribution( self
)
9489 self
._track
= newTrack
9491 self
._track
.addContribution( self
)
9493 def removeTrack(self
, track
):
9494 if track
== self
._track
:
9497 def setType( self
, newType
):
9498 self
._type
= newType
9500 def getType( self
):
9504 except AttributeError:
9508 def getModificationDate( self
):
9509 """Returns the date in which the contribution was last modified"""
9511 return self
._modificationDS
9513 if self
.getConference():
9514 self
._modificationDS
= self
.getConference().getModificationDate()
9516 self
._modificationDS
= nowutc()
9517 return self
._modificationDS
9519 def getCurrentStatus(self
):
9523 except AttributeError:
9524 self
._status
=ContribStatusNotSch(self
)
9526 getStatus
= getCurrentStatus
9528 def setStatus(self
,newStatus
):
9531 self
._status
=newStatus
9533 def withdraw(self
,resp
,comment
):
9534 """ Remove or put a contribution in a conference
9537 if self
.isWithdrawn():
9538 #put back the authors in the author index
9539 for auth
in self
.getAuthorList():
9540 self
.getConference().getAuthorIndex().index(auth
)
9541 for spk
in self
.getSpeakerList():
9542 self
.getConference().getSpeakerIndex().index(spk
)
9543 #change the status of the contribution
9544 self
._status
=ContribStatusNotSch(self
)
9547 #remove the authors from the author index
9548 if self
.getConference() is not None:
9549 for auth
in self
.getAuthorList():
9550 self
.getConference().getAuthorIndex().unindex(auth
)
9551 for spk
in self
.getSpeakerList():
9552 self
.getConference().unindexSpeaker(spk
)
9553 #remove the contribution from any schedule it is included
9554 if self
.isScheduled():
9555 self
.getSchEntry().getSchedule().removeEntry(self
.getSchEntry())
9556 self
.getCurrentStatus().withdraw(resp
,comment
)
9559 def getSubmitterList(self
, no_groups
=False):
9561 if self
._submitters
:
9563 except AttributeError:
9564 self
._submitters
=[] #create the attribute
9565 self
.notifyModification(raiseEvent
= False)
9567 return filter(lambda s
: not isinstance(s
, MaKaC
.user
.Group
), self
._submitters
)
9569 return self
._submitters
9571 def _grantSubmission(self
,av
):
9572 if av
not in self
.getSubmitterList():
9573 self
.getSubmitterList().append(av
)
9574 if self
.getConference() is not None:
9575 self
.getConference().addContribSubmitter(self
,av
)
9576 if isinstance(av
, MaKaC
.user
.Avatar
):
9577 av
.linkTo(self
, "submission")
9578 self
.notifyModification(raiseEvent
= False)
9580 def _grantSubmissionEmail(self
, email
):
9581 """Returns True if submission email was granted. False if email was already in the list.
9583 if not email
.lower() in map(lambda x
: x
.lower(), self
.getSubmitterEmailList()):
9584 self
.getSubmitterEmailList().append(email
.lower().strip())
9588 def revokeSubmissionEmail(self
, email
):
9589 if email
in self
.getSubmitterEmailList():
9590 self
.getSubmitterEmailList().remove(email
)
9593 def grantSubmission(self
, sb
, sendEmail
=True):
9594 """Grants a user with submission privileges for the contribution
9595 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9597 if isinstance(sb
, ContributionParticipation
) or isinstance(sb
, SubContribParticipation
):
9599 results
=ah
.match({"email":sb
.getEmail()}, exact
=1, forceWithoutExtAuth
=True)
9601 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
9604 if i
.hasEmail(sb
.getEmail()):
9607 if r
and r
.isActivated():
9608 self
._grantSubmission
(r
)
9610 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(sb
, False)
9611 submissionEmailGranted
= self
._grantSubmissionEmail
(sb
.getEmail())
9612 if submissionEmailGranted
and sendEmail
:
9613 notif
= pendingQueues
._PendingSubmitterNotification
( [sb
] )
9614 mail
.GenericMailer
.sendAndLog( notif
, self
.getConference() )
9615 if self
.getConference():
9616 self
.getConference().addContribSubmitter(self
,sb
)
9618 self
._grantSubmission
(sb
)
9620 def _revokeSubmission(self
, av
):
9621 if av
in self
.getSubmitterList():
9622 self
.getSubmitterList().remove(av
)
9623 if self
.getConference():
9624 self
.getConference().removeContribSubmitter(self
, av
)
9625 if isinstance(av
, MaKaC
.user
.Avatar
):
9626 av
.unlinkTo(self
, "submission")
9627 self
.notifyModification(raiseEvent
= False)
9629 def revokeSubmission(self
, sb
):
9630 """Removes submission privileges for the specified user
9631 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9633 if isinstance(sb
, ContributionParticipation
) or isinstance(sb
, SubContribParticipation
):
9635 results
= ah
.match({"email":sb
.getEmail()}, exact
=1, forceWithoutExtAuth
=True)
9638 if i
.hasEmail(sb
.getEmail()):
9642 self
._revokeSubmission
(r
)
9644 self
.revokeSubmissionEmail(sb
.getEmail())
9646 self
._revokeSubmission
(sb
)
9648 def revokeAllSubmitters(self
):
9649 self
._submitters
= []
9650 self
.notifyModification(raiseEvent
= False)
9652 def getSubmitterEmailList(self
):
9654 return self
._submittersEmail
9656 self
._submittersEmail
= []
9657 return self
._submittersEmail
9659 def canUserSubmit(self
, sb
):
9660 """Tells whether a user can submit material for the current contribution
9661 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9666 if isinstance(sb
, ContributionParticipation
) or isinstance(sb
, SubContribParticipation
):
9667 sbEmail
= sb
.getEmail()
9669 # Normally, we shouldn't get here unless we're adding someone as a Speaker or similar.
9670 # `no_groups` is used so that we do not consider group membership, as to not confuse the
9671 # user (since there will be speakers with "implicit" privileges) and avoid that hasEmail breaks
9672 return any(submitter
.hasEmail(sbEmail
) for submitter
in self
.getSubmitterList(no_groups
=True)) or \
9673 any(submitterEmail
== sbEmail
for submitterEmail
in self
.getSubmitterEmailList())
9675 for principal
in self
.getSubmitterList():
9676 if principal
!= None and principal
.containsUser(sb
):
9681 def getAccessController(self
):
9684 def getReportNumberHolder(self
):
9686 if self
._reportNumberHolder
:
9688 except AttributeError, e
:
9689 self
._reportNumberHolder
=ReportNumberHolder(self
)
9690 return self
._reportNumberHolder
9692 def setReportNumberHolder(self
, rnh
):
9693 self
._reportNumberHolder
=rnh
9696 def contributionStartDateForSort(cls
, contribution
):
9697 """ Function that can be used as "key" argument to sort a list of contributions by start date
9698 The contributions with no start date will be at the end with this sort
9700 if contribution
.getStartDate():
9701 return contribution
.getStartDate()
9703 return maxDatetime()
9707 if self
.getSession() is not None:
9708 res
=self
.getSession().getColor()
9711 def getTextColor(self
):
9713 if self
.getSession() is not None:
9714 res
=self
.getSession().getTextColor()
9717 def getCSBookingManager(self
):
9718 return self
.getConference().getCSBookingManager()
9720 class AcceptedContribution( Contribution
):
9721 """This class represents a contribution which has been created from an
9725 def __init__(self
,abstract
):
9726 Contribution
.__init
__(self
)
9727 abstract
.getConference().addContribution(self
,abstract
.getId())
9728 self
._abstract
= abstract
9729 self
.setTitle( abstract
.getTitle() )
9730 #self.setDescription(abstract.getField("content"))
9731 for key
in abstract
.getFields().keys():
9732 #if key != "content":
9733 self
.setField(key
, abstract
.getField(key
))
9734 if isinstance( abstract
.getCurrentStatus(),review
.AbstractStatusAccepted
):
9735 self
.setTrack( abstract
.getCurrentStatus().getTrack() )
9736 self
.setType( abstract
.getCurrentStatus().getType() )
9737 for auth
in abstract
.getAuthorList():
9738 c_auth
= ContributionParticipation()
9739 self
._setAuthorValuesFromAbstract
( c_auth
, auth
)
9740 if abstract
.isPrimaryAuthor( auth
):
9741 self
.addPrimaryAuthor( c_auth
)
9743 self
.addCoAuthor( c_auth
)
9744 if abstract
.isSpeaker( auth
):
9745 self
.addSpeaker( c_auth
)
9746 self
._grantSubmission
(self
.getAbstract().getSubmitter().getUser())
9748 def _setAuthorValuesFromAbstract( self
, cAuth
, aAuth
):
9749 cAuth
.setTitle( aAuth
.getTitle() )
9750 cAuth
.setFirstName( aAuth
.getFirstName() )
9751 cAuth
.setFamilyName( aAuth
.getSurName() )
9752 cAuth
.setEmail( aAuth
.getEmail() )
9753 cAuth
.setAffiliation( aAuth
.getAffiliation() )
9754 cAuth
.setAddress( aAuth
.getAddress() )
9755 cAuth
.setPhone( aAuth
.getTelephone() )
9757 def getAbstract( self
):
9758 return self
._abstract
9760 def setAbstract(self
, abs):
9761 self
._abstract
= abs
9763 def getSubmitterList(self
, no_groups
=False):
9765 if self
._submitters
:
9767 except AttributeError:
9768 self
._submitters
=[]#create the attribute
9769 self
._grantSubmission
(self
.getAbstract().getSubmitter().getUser())
9771 return filter(lambda s
: not isinstance(s
, MaKaC
.user
.Group
), self
._submitters
)
9773 return self
._submitters
9776 """deletes a contribution and all of their subitems
9778 abs = self
.getAbstract()
9780 cs
=abs.getCurrentStatus()
9781 if isinstance(cs
, review
.AbstractStatusAccepted
):
9782 if cs
.getTrack() is not None:
9783 abs.addTrack(cs
.getTrack())
9784 abs.setCurrentStatus(review
.AbstractStatusSubmitted(abs))
9785 abs._setContribution
(None)
9786 self
.setAbstract(None)
9787 Contribution
.delete(self
)
9791 class ContribStatus(Persistent
):
9795 def __init__(self
,contribution
,responsible
):
9796 self
._setContrib
(contribution
)
9797 self
._setResponsible
(responsible
)
9800 def clone(self
, contribution
, responsible
):
9801 cs
= ContribStatus(contribution
, responsible
)
9802 cs
.setDate(self
.getDate())
9805 def _setContrib(self
,newContrib
):
9806 self
._contrib
=newContrib
9808 def getContrib(self
):
9809 return self
._contrib
9811 def _setResponsible(self
,newResp
):
9812 self
._responsible
=newResp
9814 def getResponsible(self
):
9815 return self
._responsible
9820 def setDate(self
, date
):
9826 def withdraw(self
,resp
,comments
=""):
9827 self
._contrib
.setStatus(ContribStatusWithdrawn(self
.getContrib(),resp
,comments
))
9829 class ContribStatusNotSch(ContribStatus
):
9832 def __init__(self
,contrib
):
9833 ContribStatus
.__init
__(self
,contrib
,None)
9835 def clone(self
, contribution
):
9836 csns
= ContribStatusNotSch(contribution
)
9837 csns
.setDate(self
.getDate())
9840 ContribStatusSubmitted
=ContribStatusNotSch
9842 class ContribStatusSch(ContribStatus
):
9845 def __init__(self
,contrib
):
9846 ContribStatus
.__init
__(self
,contrib
,None)
9848 def clone(self
, contribution
):
9849 css
= ContribStatusSch(contribution
)
9850 css
.setDate(self
.getDate())
9853 class ContribStatusWithdrawn(ContribStatus
):
9856 def __init__(self
,contrib
,resp
,comments
):
9857 ContribStatus
.__init
__(self
,contrib
,resp
)
9858 self
._setComment
(comments
)
9860 def clone(self
, contribution
):
9861 csw
= ContribStatusWithdrawn(contribution
)
9862 csw
.setDate(self
.getDate())
9863 csw
.setComment(self
.getComment())
9866 def _setComment(self
,text
):
9867 self
._comment
=text
.strip()
9869 def getComment(self
):
9870 return self
._comment
9872 class ContribStatusNone(ContribStatus
):
9873 # This is a special status we assign to contributions that are put in the trash can.
9875 def __init__(self
,contrib
):
9876 ContribStatus
.__init
__(self
,contrib
,None)
9878 def clone(self
, contribution
):
9879 csn
= ContribStatusNone(contribution
)
9880 csn
.setDate(self
.getDate())
9883 class SubContribParticipation(Persistent
, Fossilizable
):
9885 fossilizes(ISubContribParticipationFossil
, ISubContribParticipationFullFossil
)
9887 def __init__( self
):
9888 self
._subContrib
= None
9890 self
._firstName
= ""
9893 self
._affiliation
= ""
9899 def getConference(self
):
9900 if self
._subContrib
is not None:
9901 return self
._subContrib
.getConference()
9904 def _notifyModification( self
):
9905 if self
._subContrib
!= None:
9906 self
._subContrib
.notifyModification()
9908 def setValues(self
, data
):
9909 self
.setFirstName(data
.get("firstName", ""))
9910 self
.setFamilyName(data
.get("familyName",""))
9911 self
.setAffiliation(data
.get("affilation",""))
9912 self
.setAddress(data
.get("address",""))
9913 self
.setEmail(data
.get("email",""))
9914 self
.setFax(data
.get("fax",""))
9915 self
.setTitle(data
.get("title",""))
9916 self
.setPhone(data
.get("phone",""))
9917 self
._notifyModification
()
9919 def getValues(self
):
9921 data
["firstName"]=self
.getFirstName()
9922 data
["familyName"]=self
.getFamilyName()
9923 data
["affilation"]=self
.getAffiliation()
9924 data
["address"]=self
.getAddress()
9925 data
["email"]=self
.getEmail()
9926 data
["fax"]=self
.getFax()
9927 data
["title"]=self
.getTitle()
9928 data
["phone"]=self
.getPhone()
9932 part
= SubContribParticipation()
9933 part
.setValues(self
.getValues())
9936 def setDataFromAvatar(self
,av
):
9937 # av is an Avatar object.
9940 self
.setFirstName(av
.getName())
9941 self
.setFamilyName(av
.getSurName())
9942 self
.setEmail(av
.getEmail())
9943 self
.setAffiliation(av
.getOrganisation())
9944 self
.setAddress(av
.getAddress())
9945 self
.setPhone(av
.getTelephone())
9946 self
.setTitle(av
.getTitle())
9947 self
.setFax(av
.getFax())
9948 self
._notifyModification
()
9950 def setDataFromAuthor(self
,au
):
9951 # au is a ContributionParticipation object.
9954 self
.setFirstName(au
.getFirstName())
9955 self
.setFamilyName(au
.getFamilyName())
9956 self
.setEmail(au
.getEmail())
9957 self
.setAffiliation(au
.getAffiliation())
9958 self
.setAddress(au
.getAddress())
9959 self
.setPhone(au
.getPhone())
9960 self
.setTitle(au
.getTitle())
9961 self
.setFax(au
.getFax())
9962 self
._notifyModification
()
9964 def setDataFromSpeaker(self
,spk
):
9965 # spk is a SubContribParticipation object.
9968 self
.setFirstName(spk
.getFirstName())
9969 self
.setFamilyName(spk
.getFamilyName())
9970 self
.setEmail(spk
.getEmail())
9971 self
.setAffiliation(spk
.getAffiliation())
9972 self
.setAddress(spk
.getAddress())
9973 self
.setPhone(spk
.getPhone())
9974 self
.setTitle(spk
.getTitle())
9975 self
.setFax(spk
.getFax())
9976 self
._notifyModification
()
9978 def includeInSubContrib( self
, subcontrib
, id ):
9979 if self
.getSubContrib() == subcontrib
and self
.getId()==id.strip():
9981 self
._subContrib
= subcontrib
9985 self
._subContrib
= None
9986 TrashCanManager().add(self
)
9989 TrashCanManager().remove(self
)
9991 @Updates ('MaKaC.conference.SubContribParticipation', 'id')
9992 def setId(self
, newId
):
9998 def getSubContrib( self
):
9999 return self
._subContrib
10001 def getContribution( self
):
10002 if self
._subContrib
is not None:
10003 return self
._subContrib
.getContribution()
10006 # def getLocator(self):
10007 # if self.getSubContrib() is None:
10009 # loc=self.getSubContrib().getLocator()
10010 # loc["authId"]=self.getId()
10013 def _unindex(self
):
10014 contrib
=self
.getContribution()
10015 if contrib
is not None:
10016 conf
=contrib
.getConference()
10017 if conf
is not None:
10018 conf
.unindexAuthor(self
)
10019 conf
.unindexSpeaker(self
)
10022 contrib
=self
.getContribution()
10023 if contrib
is not None:
10024 conf
=contrib
.getConference()
10025 if conf
is not None:
10026 conf
.indexAuthor(self
)
10027 conf
.indexSpeaker(self
)
10029 @Updates ('MaKaC.conference.SubContribParticipation', 'firstName')
10030 def setFirstName( self
, newName
):
10031 tmp
=newName
.strip()
10032 if tmp
==self
._firstName
:
10035 self
._firstName
=tmp
10037 self
._notifyModification
()
10039 def getFirstName( self
):
10040 return self
._firstName
10042 def getName( self
):
10043 return self
._firstName
10045 @Updates ('MaKaC.conference.SubContribParticipation', 'familyName')
10046 def setFamilyName( self
, newName
):
10047 tmp
=newName
.strip()
10048 if tmp
==self
._surName
:
10053 self
._notifyModification
()
10055 def getFamilyName( self
):
10056 return self
._surName
10058 def getSurName( self
):
10059 return self
._surName
10061 @Updates ('MaKaC.conference.SubContribParticipation', 'email')
10062 def setEmail( self
, newMail
):
10063 tmp
=newMail
.strip()
10064 if tmp
==self
._email
:
10067 self
._email
=newMail
.strip()
10069 self
._notifyModification
()
10071 def getEmail( self
):
10074 @Updates ('MaKaC.conference.SubContribParticipation', 'affiliation')
10075 def setAffiliation( self
, newAffil
):
10076 self
._affiliation
= newAffil
.strip()
10077 self
._notifyModification
()
10079 def getAffiliation( self
):
10080 return self
._affiliation
10082 @Updates ('MaKaC.conference.SubContribParticipation', 'address')
10083 def setAddress( self
, newAddr
):
10084 self
._address
= newAddr
.strip()
10085 self
._notifyModification
()
10087 def getAddress( self
):
10088 return self
._address
10090 @Updates ('MaKaC.conference.SubContribParticipation', 'phone')
10091 def setPhone( self
, newPhone
):
10092 self
._phone
= newPhone
.strip()
10093 self
._notifyModification
()
10095 def getPhone( self
):
10098 @Updates ('MaKaC.conference.SubContribParticipation', 'title')
10099 def setTitle( self
, newTitle
):
10100 self
._title
= newTitle
.strip()
10101 self
._notifyModification
()
10103 def getTitle( self
):
10106 def setFax( self
, newFax
):
10107 self
._fax
= newFax
.strip()
10108 self
._notifyModification
()
10110 def getFax( self
):
10114 except AttributeError:
10118 def getFullName( self
):
10119 res
= self
.getFullNameNoTitle()
10120 if self
.getTitle() != "":
10121 res
= "%s %s"%( self
.getTitle(), res
)
10124 def getFullNameNoTitle( self
):
10125 res
= self
.getFamilyName().decode('utf-8').upper().encode('utf-8')
10126 if self
.getFirstName() != "":
10127 if res
.strip() != "":
10128 res
= "%s, %s"%( res
, self
.getFirstName() )
10130 res
= self
.getFirstName()
10133 def getAbrName(self
):
10134 res
= self
.getFamilyName()
10135 if self
.getFirstName() != "":
10138 res
= "%s%s."%(res
, self
.getFirstName()[0].upper())
10141 def getDirectFullName( self
):
10142 res
= self
.getDirectFullNameNoTitle()
10143 if self
.getTitle() != "":
10144 res
= "%s %s"%( self
.getTitle(), res
)
10147 def getDirectFullNameNoTitle( self
, upper
= True ):
10148 return ("%s %s"%(self
.getFirstName(), self
.getFamilyName().upper() if upper
else self
.getFamilyName())).strip()
10150 class SubContribution(CommonObjectBase
, Locatable
):
10154 fossilizes(ISubContributionFossil
, ISubContributionWithSpeakersFossil
)
10156 def __init__( self
, **subContData
):
10160 self
.description
= ""
10161 self
.__schEntry
= None
10162 self
.duration
= timedelta( minutes
=15 )
10164 self
.speakerText
= ""
10166 self
.materials
= {}
10167 self
.__materialGenerator
= Counter() # Provides material unique
10168 # identifiers whithin the current
10169 self
.poster
= None # contribution
10174 self
.minutes
= None
10175 self
._authorGen
= Counter()
10176 self
._keywords
= ""
10180 parentId
= self
.parent
.getId()
10181 if self
.getConference():
10182 grandpaId
= self
.getConference().getId()
10188 return "<SubCont %s:%s:%s@%s>" % (grandpaId
, parentId
, self
.getId(), hex(id(self
)))
10190 def updateNonInheritingChildren(self
, elem
, delete
=False):
10191 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
10193 def getAccessController(self
):
10194 return self
.getOwner().getAccessController()
10196 def getKeywords(self
):
10198 return self
._keywords
10200 self
._keywords
= ""
10203 def setKeywords(self
, keywords
):
10204 self
._keywords
= keywords
10206 def getLogInfo(self
):
10209 data
["subject"] = self
.getTitle()
10210 data
["id"] = self
.id
10211 data
["title"] = self
.title
10212 data
["parent title"] = self
.getParent().getTitle()
10213 data
["description"] = self
.description
10214 data
["duration"] = "%s"%self
.duration
10215 data
["minutes"] = self
.minutes
10217 for sp
in self
.speakers
:
10218 data
["speaker %s"%sp
.getId()] = sp
.getFullName()
10223 def clone(self
, deltaTime
, parent
, options
):
10224 sCont
= SubContribution()
10225 sCont
.setParent(parent
)
10226 sCont
.setTitle(self
.getTitle())
10227 sCont
.setDescription(self
.getDescription())
10228 sCont
.setKeywords(self
.getKeywords())
10229 dur
= self
.getDuration()
10230 hours
= dur
.seconds
/ 3600
10231 minutes
= (dur
.seconds
% 3600) / 60
10232 sCont
.setDuration(hours
, minutes
)
10233 sCont
.setReportNumberHolder(self
.getReportNumberHolder().clone(self
))
10235 # There is no _order attribute in this class
10237 if options
.get("authors", False) :
10238 for s
in self
.getSpeakerList() :
10239 sCont
.newSpeaker(s
.clone())
10240 sCont
.setSpeakerText(self
.getSpeakerText())
10242 if options
.get("materials", False) :
10243 for m
in self
.getMaterialList() :
10244 sCont
.addMaterial(m
.clone(sCont
))
10245 if self
.getPaper() is not None:
10246 sCont
.setPaper(self
.getPaper().clone(sCont
))
10247 if self
.getSlides() is not None:
10248 sCont
.setSlides(self
.getSlides().clone(sCont
))
10249 if self
.getVideo() is not None:
10250 sCont
.setVideo(self
.getVideo().clone(sCont
))
10251 if self
.getPoster() is not None:
10252 sCont
.setPoster(self
.getPoster().clone(sCont
))
10253 if self
.getMinutes() is not None:
10254 sCont
.setMinutes(self
.getMinutes().clone(sCont
))
10257 sCont
.notifyModification()
10260 def notifyModification(self
, raiseEvent
= True):
10261 parent
= self
.getParent()
10263 parent
.setModificationDate()
10265 self
._notify
('infoChanged')
10266 self
._p
_changed
= 1
10268 def getCategoriesPath(self
):
10269 return self
.getConference().getCategoriesPath()
10271 def getLocator( self
):
10272 """Gives back a globaly unique identification encapsulated in a Locator
10273 object for the contribution instance
10276 lconf
= self
.getOwner().getLocator()
10277 lconf
["subContId"] = self
.getId()
10281 def setId( self
, newId
):
10287 def getUniqueId( self
):
10288 """returns (string) the unique identifier of the item"""
10289 """used mainly in the web session access key table"""
10290 return "%ssc%s" % (self
.getParent().getUniqueId(),self
.id)
10292 def setTitle( self
, newTitle
):
10293 self
.title
= newTitle
.strip()
10294 self
.notifyModification()
10296 def getTitle( self
):
10297 if self
.title
.strip() == "":
10298 return "(no title)"
10301 def setDescription( self
, newDesc
):
10302 self
.description
= newDesc
.strip()
10303 self
.notifyModification()
10305 def getDescription( self
):
10306 return self
.description
10308 def setParent(self
,parent
):
10309 self
.parent
= parent
10310 if self
.parent
== None:
10313 def getParent( self
):
10316 def setOwner(self
, owner
):
10317 self
.setParent(owner
)
10319 def getOwner( self
):
10320 return self
.getParent()
10322 def getConference( self
):
10323 return self
.parent
.getConference()
10325 def getSession( self
):
10326 return self
.parent
.getSession()
10328 def getContribution(self
):
10331 def getDuration( self
):
10332 return self
.duration
10334 def setDuration( self
, hours
, minutes
=0, dur
=0 ):
10338 hours
= int( hours
)
10339 minutes
= int( minutes
)
10340 self
.duration
= timedelta(hours
=hours
,minutes
=minutes
)
10341 self
.notifyModification()
10343 def getLocation( self
):
10344 return self
.getOwner().getLocation()
10346 def getRoom( self
):
10347 return self
.getOwner().getRoom()
10349 def getSpeakerById( self
, id ):
10352 for spk
in self
.speakers
:
10353 if spk
.getId() == id:
10357 def newSpeaker( self
, spk
):
10360 self
.speakers
.append( spk
)
10362 if self
._authorGen
:
10364 except AttributeError:
10365 self
._authorGen
=Counter()
10366 newId
= spk
.getId()
10368 newId
= str( self
._authorGen
.newCount() )
10369 spk
.includeInSubContrib(self
, newId
)
10370 if self
.getConference() is not None:
10371 self
.getConference().indexSpeaker(spk
)
10372 self
.notifyModification()
10374 def removeSpeaker( self
, spk
):
10377 if spk
not in self
.speakers
:
10379 self
.speakers
.remove( spk
)
10380 if self
.getConference() is not None:
10381 self
.getConference().unindexSpeaker(spk
)
10383 self
.notifyModification()
10385 def recoverSpeaker(self
, spk
):
10386 self
.newSpeaker(spk
)
10389 def isSpeaker( self
, spk
):
10392 return spk
in self
._speakers
10394 def getSpeakerList ( self
):
10397 return self
.speakers
10399 def getSpeakerText( self
):
10402 if self
.speakerText
:
10404 except AttributeError, e
:
10405 self
.speakerText
= ""
10406 return self
.speakerText
10408 def setSpeakerText( self
, newText
):
10409 self
.speakerText
= newText
.strip()
10411 def appendSpeakerText( self
, newText
):
10412 self
.setSpeakerText( "%s, %s"%(self
.getSpeakerText(), newText
.strip()) )
10415 # There is no _order attribute in this class -
10416 # the methods below are either obsolate or the feature has not been implemented
10418 # def setOrder( self, order ):
10419 # self._order = order
10420 # self.notifyModification()
10422 # def getOrder(self):
10423 # return self._order
10425 def canIPAccess( self
, ip
):
10426 return self
.getOwner().canIPAccess(ip
)
10428 def isProtected( self
):
10429 return self
.hasProtectedOwner()
10431 def getAccessProtectionLevel( self
):
10432 return self
.getOwner().getAccessProtectionLevel()
10434 def hasAnyProtection( self
):
10435 """Tells whether a subContribution has any kind of protection over it:
10436 access or domain protection.
10438 return self
.getOwner().hasAnyProtection()
10440 def getManagerList( self
):
10441 return self
.parent
.getManagerList()
10443 def hasProtectedOwner( self
):
10444 if self
.getOwner() != None:
10445 return self
.getOwner().isProtected()
10448 def getAccessKey( self
):
10449 return self
.getOwner().getAccessKey()
10451 def getModifKey( self
):
10452 return self
.getConference().getModifKey()
10454 def canView( self
, aw
):
10455 """tells whether the specified user has access to the current object
10456 or any of its sub-objects
10458 if self
.canAccess( aw
):
10462 def isAllowedToAccess( self
, user
):
10463 return self
.parent
.isAllowedToAccess( user
)
10465 def canAccess( self
, aw
):
10466 return self
.getOwner().canAccess(aw
)
10468 def canModify( self
, aw
):
10469 return self
.canUserModify( aw
.getUser() ) or self
.getConference().canKeyModify( aw
)
10471 def canUserModify( self
, av
):
10472 """Tells whether a user is allowed to modify the current contribution:
10473 only if the user is granted to modify the contribution or the user
10474 can modify any of its upper objects (i.e. conference or session).
10476 return self
.getParent().canUserModify( av
)
10478 def canUserSubmit( self
, av
):
10479 return self
.getOwner().canUserSubmit( av
)
10481 def getAllowedToAccessList( self
):
10482 """Currently the SubContribution class has no access list.
10483 But instead of returning the owner Contribution's access list,
10484 I am returning an empty list. Methods such as getRecursiveAllowedToAccess()
10485 will call the owner Contribution anyway.
10489 def addMaterial( self
, newMat
):
10490 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
10491 newMat
.setOwner( self
)
10492 self
.materials
[ newMat
.getId() ] = newMat
10493 self
.notifyModification()
10495 def removeMaterial( self
, mat
):
10496 if mat
.getId() in self
.materials
.keys():
10498 self
.materials
[mat
.getId()].setOwner(None)
10499 del self
.materials
[ mat
.getId() ]
10500 self
.notifyModification()
10501 elif mat
.getId().lower() == 'paper':
10503 self
.notifyModification()
10504 elif mat
.getId().lower() == 'slides':
10505 self
.removeSlides()
10506 self
.notifyModification()
10507 elif mat
.getId().lower() == 'minutes':
10508 self
.removeMinutes()
10509 self
.notifyModification()
10510 elif mat
.getId().lower() == 'video':
10512 self
.notifyModification()
10513 elif mat
.getId().lower() == 'poster':
10514 self
.removePoster()
10515 self
.notifyModification()
10517 def recoverMaterial(self
, recMat
):
10518 # Id must already be set in recMat.
10519 recMat
.setOwner( self
)
10520 self
.materials
[ recMat
.getId() ] = recMat
10522 self
.notifyModification()
10524 def getMaterialRegistry(self
):
10526 Return the correct material registry for this type
10528 from MaKaC
.webinterface
.materialFactories
import SubContributionMFRegistry
10529 return SubContributionMFRegistry
10531 def getMaterialById( self
, matId
):
10532 if matId
.lower() == 'paper':
10533 return self
.getPaper()
10534 elif matId
.lower() == 'slides':
10535 return self
.getSlides()
10536 elif matId
.lower() == 'video':
10537 return self
.getVideo()
10538 elif matId
.lower() == 'poster':
10539 return self
.getPoster()
10540 elif matId
.lower() == 'minutes':
10541 return self
.getMinutes()
10542 elif self
.materials
.has_key(matId
):
10543 return self
.materials
[ matId
]
10546 def getMaterialList( self
):
10547 return self
.materials
.values()
10549 def getAllMaterialList(self
, sort
=True):
10550 l
= self
.getMaterialList()
10551 if self
.getPaper():
10552 l
.append( self
.getPaper() )
10553 if self
.getSlides():
10554 l
.append( self
.getSlides() )
10555 if self
.getVideo():
10556 l
.append( self
.getVideo() )
10557 if self
.getMinutes():
10558 l
.append( self
.getMinutes() )
10559 if self
.getPoster():
10560 l
.append( self
.getPoster() )
10562 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
10565 def setPaper( self
, newPaper
):
10566 if self
.getPaper() != None:
10567 raise MaKaCError( _("The paper for this subcontribution has already been set"), _("Contribution"))
10568 self
.paper
=newPaper
10569 self
.paper
.setOwner( self
)
10570 self
.notifyModification()
10572 def removePaper( self
):
10573 if self
.getPaper() is None:
10575 self
.paper
.delete()
10576 self
.paper
.setOwner(None)
10578 self
.notifyModification()
10580 def recoverPaper(self
, p
):
10584 def getPaper( self
):
10587 def setSlides( self
, newSlides
):
10588 if self
.getSlides() != None:
10589 raise MaKaCError( _("The slides for this subcontribution have already been set"), _("Contribution"))
10590 self
.slides
=newSlides
10591 self
.slides
.setOwner( self
)
10592 self
.notifyModification()
10594 def removeSlides( self
):
10595 if self
.getSlides() is None:
10597 self
.slides
.delete()
10598 self
.slides
.setOwner( None )
10600 self
.notifyModification()
10602 def recoverSlides(self
, s
):
10606 def getSlides( self
):
10609 def setVideo( self
, newVideo
):
10610 if self
.getVideo() != None:
10611 raise MaKaCError( _("the video for this subcontribution has already been set"))
10612 self
.video
=newVideo
10613 self
.video
.setOwner( self
)
10614 self
.notifyModification()
10616 def removeVideo( self
):
10617 if self
.getVideo() is None:
10619 self
.video
.delete()
10620 self
.video
.setOwner(None)
10622 self
.notifyModification()
10624 def recoverVideo(self
, v
):
10628 def getVideo( self
):
10632 except AttributeError:
10636 def setPoster( self
, newPoster
):
10637 if self
.getPoster() != None:
10638 raise MaKaCError( _("the poster for this subcontribution has already been set"))
10639 self
.poster
=newPoster
10640 self
.poster
.setOwner( self
)
10641 self
.notifyModification()
10643 def removePoster( self
):
10644 if self
.getPoster() is None:
10646 self
.poster
.delete()
10647 self
.poster
.setOwner(None)
10649 self
.notifyModification()
10651 def recoverPoster(self
, p
):
10655 def getPoster( self
):
10659 except AttributeError:
10663 def setMinutes( self
, newMinutes
):
10664 if self
.getMinutes() != None:
10665 raise MaKaCError( _("the Minutes for this subcontribution has already been set"))
10666 self
.minutes
=newMinutes
10667 self
.minutes
.setOwner( self
)
10668 self
.notifyModification()
10670 def createMinutes( self
):
10671 if self
.getMinutes() != None:
10672 raise MaKaCError( _("The minutes for this subcontribution have already been created"), _("Sub Contribution"))
10673 self
.minutes
= Minutes()
10674 self
.minutes
.setOwner( self
)
10675 self
.notifyModification()
10676 return self
.minutes
10678 def removeMinutes( self
):
10679 if self
.getMinutes() is None:
10681 self
.minutes
.delete()
10682 self
.minutes
.setOwner( None )
10683 self
.minutes
= None
10684 self
.notifyModification()
10686 def recoverMinutes(self
, min):
10687 self
.removeMinutes() # To ensure that the current minutes are put in
10690 self
.minutes
.setOwner( self
)
10692 self
.notifyModification()
10693 return self
.minutes
10695 def getMinutes( self
):
10700 except AttributeError, e
:
10701 self
.minutes
= None
10702 return self
.minutes
10704 def getMasterSchedule( self
):
10705 return self
.getOwner().getSchedule()
10709 self
._notify
('deleted', self
.getOwner())
10711 while len(self
.getSpeakerList()) > 0:
10712 self
.removeSpeaker(self
.getSpeakerList()[0])
10713 for mat
in self
.getMaterialList():
10714 self
.removeMaterial(mat
)
10716 self
.removeSlides()
10718 self
.removePoster()
10719 self
.removeMinutes()
10720 TrashCanManager().add(self
)
10725 TrashCanManager().remove(self
)
10727 def getReportNumberHolder(self
):
10729 if self
._reportNumberHolder
:
10731 except AttributeError, e
:
10732 self
._reportNumberHolder
=ReportNumberHolder(self
)
10733 return self
._reportNumberHolder
10735 def setReportNumberHolder(self
, rnh
):
10736 self
._reportNumberHolder
=rnh
10738 class Material(CommonObjectBase
):
10739 """This class represents a set of electronic documents (resources) which can
10740 be attached to a conference, a session or a contribution.
10741 A material can be of several types (achieved by specialising this class)
10742 and is like a container of files which have some relation among them.
10743 It contains the minimal set of attributes to store basic meta data and
10744 provides useful operations to access and manage it.
10746 owner -- (Conference, Session or Contribution) Object to which the
10747 material is attached to
10748 id -- (string) Material unique identifier. Normally used to uniquely
10749 identify a material within a conference, session or contribution
10750 title -- (string) Material denomination
10751 description -- (string) Longer text describing in more detail material
10753 type -- (string) String identifying the material classification
10754 resources -- (PMapping) Collection of resouces grouped within the
10755 material. Dictionary of references to Resource objects indexed
10756 by their unique relative id.
10759 fossilizes(IMaterialMinimalFossil
, IMaterialFossil
)
10761 def __init__( self
, materialData
=None ):
10762 self
.id = "not assigned"
10763 self
.__resources
= {}
10764 self
.__resourcesIdGen
= Counter()
10766 self
.description
= ""
10769 self
.__ac
= AccessController(self
)
10770 self
._mainResource
= None
10772 def __cmp__(self
, other
):
10773 if type(self
) is not type(other
):
10774 # This is actually dangerous and the ZODB manual says not to do this
10775 # because it relies on memory order. However, this branch should never
10776 # be taken anyway since we do not store different types in the same set
10777 # or use them as keys.
10778 return cmp(hash(self
), hash(other
))
10779 if self
.getConference() == other
.getConference():
10780 return cmp(self
.getId(), other
.getId())
10781 return cmp(self
.getConference(), other
.getConference())
10783 def updateNonInheritingChildren(self
, elem
, delete
=False):
10784 # We do not want to store the inherited children in a Category because the funcionallity is not used
10785 if not isinstance(self
.getOwner(), Category
):
10786 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
10787 self
.notify_protection_to_owner(elem
, delete
)
10789 def notify_protection_to_owner(self
, elem
, delete
=False):
10790 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
10792 def setValues( self
, params
):
10793 """Sets all the values of the current material object from a diccionary
10794 containing the following key-value pairs:
10797 Please, note that this method sets ALL values which means that if
10798 the given dictionary doesn't contain any of the keys the value
10799 will set to a default value.
10801 self
.setTitle(params
.get("title", "NO TITLE ASSIGNED"))
10802 self
.setDescription( params
.get( "description", "" ) )
10803 self
.notifyModification()
10805 def clone ( self
, owner
):
10807 mat
.setTitle(self
.getTitle())
10808 mat
.setDescription(self
.getDescription())
10809 mat
.notifyModification()
10811 mat
.setId(self
.getId())
10812 mat
.setOwner(owner
)
10813 mat
.setType(self
.getType())
10815 mat
.setProtection(self
.getAccessController()._getAccessProtection
())
10816 mat
.setAccessKey(self
.getAccessKey())
10817 rlist
= self
.getResourceList()
10819 newres
= r
.clone(mat
)
10820 mat
.addResource(newres
)
10822 mat
.setMainResource(self
.getMainResource())
10826 def notifyModification( self
):
10827 parent
= self
.getOwner()
10829 parent
.notifyModification(raiseEvent
= False)
10830 self
._p
_changed
= 1
10832 def getLocator( self
):
10833 if self
.owner
== None:
10835 lconf
= self
.owner
.getLocator()
10836 lconf
["materialId"] = self
.getId()
10839 def setId( self
, newId
):
10840 self
.id = str(newId
).strip()
10845 def getUniqueId( self
):
10846 """returns (string) the unique identifier of the item"""
10847 """used mainly in the web session access key table"""
10848 return "%sm%s" % (self
.getOwner().getUniqueId(),self
.id)
10850 def setOwner(self
, newOwner
):
10851 self
.owner
= newOwner
10853 def getOwner( self
):
10856 def getCategory( self
):
10857 if isinstance(self
.getOwner(), Category
):
10858 return self
.getOwner()
10861 def getConference( self
):
10862 owner
= self
.getOwner()
10863 if owner
is None or isinstance(owner
, Category
):
10865 elif isinstance(owner
, Conference
):
10868 return owner
.getConference()
10870 def getSession( self
):
10871 if self
.getContribution():
10872 return self
.getContribution().getSession()
10873 if isinstance(self
.getOwner(), Session
):
10874 return self
.getOwner()
10875 if isinstance(self
.getOwner(), SubContribution
):
10876 return self
.getOwner().getSession()
10879 def getContribution( self
):
10880 if self
.getSubContribution():
10881 return self
.getSubContribution().getContribution()
10882 if isinstance(self
.getOwner(), Contribution
):
10883 return self
.getOwner()
10886 def getSubContribution( self
):
10887 if isinstance(self
.getOwner(), SubContribution
):
10888 return self
.getOwner()
10891 @Updates (['MaKaC.conference.Material',
10892 'MaKaC.conference.Minutes',
10893 'MaKaC.conference.Paper',
10894 'MaKaC.conference.Slides',
10895 'MaKaC.conference.Video',
10896 'MaKaC.conference.Poster',
10897 'MaKaC.conference.Reviewing'],'title')
10898 def setTitle( self
, newTitle
):
10899 self
.title
= newTitle
.strip()
10900 self
.notifyModification()
10902 def getTitle( self
):
10905 @Updates (['MaKaC.conference.Material',
10906 'MaKaC.conference.Minutes',
10907 'MaKaC.conference.Paper',
10908 'MaKaC.conference.Slides',
10909 'MaKaC.conference.Video',
10910 'MaKaC.conference.Poster',
10911 'MaKaC.conference.Reviewing'], 'description')
10912 def setDescription( self
, newDescription
):
10913 self
.description
= newDescription
.strip()
10914 self
.notifyModification()
10916 def getDescription( self
):
10917 return self
.description
10919 def setType( self
, newType
):
10920 self
.type = newType
.strip()
10921 self
.notifyModification()
10923 def getType( self
):
10926 def getReviewingState(self
):
10927 """ Returns the reviewing state of a material.
10928 The state is represented by an integer:
10929 0 : there's no reviewing state because the material does not belong to a contribution, or the conference
10930 has not reviewing module enabled, or the module is enabled but the mode is "no reviewing"
10931 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
10932 2 : the material is subject to reviewing, but has not been submitted yet by the author
10933 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
10934 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
10935 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
10937 if isinstance(self
.owner
, Contribution
):
10938 conference
= self
.owner
.getConference()
10939 if conference
.getConfPaperReview().getChoice() == ConferencePaperReview
.NO_REVIEWING
: #conference has no reviewing process
10941 else: #conference has reviewing
10942 #if self.id in reviewableMaterials: #material is reviewable
10943 if isinstance(self
, Reviewing
): #material is reviewable
10944 lastReview
= self
.owner
.getReviewManager().getLastReview()
10945 if lastReview
.isAuthorSubmitted(): #author has submitted
10946 refereeJudgement
= lastReview
.getRefereeJudgement()
10947 if refereeJudgement
.isSubmitted(): #referee has submitted judgement
10948 if refereeJudgement
.getJudgement() == "Accept":
10950 elif refereeJudgement
.getJudgement() == "Reject":
10953 #we should never arrive here because referee judgements that are 'To be corrected'
10954 #or a custom state should imply a new review being created, so the state is back to 2
10955 raise MaKaCError("RefereeJudgement should be 'Accept' or 'Reject' in this method")
10956 else: #referee has not submitted judgement
10958 else: #author has not submitted
10960 else: #material is not reviewable
10962 else: #material does not belong to a contribution
10965 def _getRepository( self
):
10966 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
10968 fr
= dbRoot
["local_repositories"]["main"]
10969 except KeyError, e
:
10970 fr
= fileRepository
.MaterialLocalRepository()
10971 dbRoot
["local_repositories"] = OOBTree()
10972 dbRoot
["local_repositories"]["main"] = fr
10975 def hasFile( self
, name
):
10976 for f
in self
.getResourceList():
10977 if f
.getName() == name
:
10981 def addResource( self
, newRes
, forcedFileId
= None ):
10982 newRes
.setOwner( self
)
10983 newRes
.setId( str( self
.__resourcesIdGen
.newCount() ) )
10984 newRes
.archive( self
._getRepository
(), forcedFileId
= forcedFileId
)
10985 self
.__resources
[newRes
.getId()] = newRes
10986 self
.notifyModification()
10987 Logger
.get('storage').debug("Finished storing resource %s for material %s" % (newRes
.getId(), self
.getLocator()))
10989 def getResourceList(self
, sort
=True):
10990 list = self
.__resources
.values()
10992 list.sort(utils
.sortFilesByName
)
10995 def getNbResources(self
):
10996 return len(self
.__resources
)
10998 def getResourceById( self
, id ):
10999 return self
.__resources
[id]
11001 def removeResource( self
, res
):
11002 if res
.getId() in self
.__resources
.keys():
11003 del self
.__resources
[ res
.getId() ]
11005 self
.notifyModification()
11006 if self
.getMainResource() is not None and \
11007 self
._mainResource
.getId() == res
.getId():
11008 self
._mainResource
= None
11010 def recoverResource(self
, recRes
):
11011 recRes
.setOwner(self
)
11012 self
.__resources
[recRes
.getId()] = recRes
11014 self
.notifyModification()
11016 def getMainResource(self
):
11018 if self
._mainResource
:
11020 except AttributeError:
11021 self
._mainResource
= None
11022 return self
._mainResource
11024 def setMainResource(self
, mr
):
11025 self
._mainResource
= mr
11028 self
.__ac
.unlinkAvatars('access')
11029 for res
in self
.getResourceList():
11030 self
.removeResource( res
)
11031 self
.notify_protection_to_owner(self
, delete
=True)
11032 TrashCanManager().add(self
)
11035 TrashCanManager().remove(self
)
11037 def canIPAccess( self
, ip
):
11038 if not self
.__ac
.canIPAccess( ip
):
11040 if self
.getOwner() != None:
11041 return self
.getOwner().canIPAccess(ip
)
11044 def isProtected( self
):
11045 # tells if a material is protected or not
11046 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
11048 def getAccessProtectionLevel( self
):
11049 return self
.__ac
.getAccessProtectionLevel()
11051 def isItselfProtected( self
):
11052 return self
.__ac
.isItselfProtected()
11055 def hasProtectedOwner( self
):
11056 if self
.getOwner() != None:
11057 return self
.getOwner().isProtected()
11061 @Updates (['MaKaC.conference.Material',
11062 'MaKaC.conference.Minutes',
11063 'MaKaC.conference.Paper',
11064 'MaKaC.conference.Slides',
11065 'MaKaC.conference.Video',
11066 'MaKaC.conference.Poster',
11067 'MaKaC.conference.Reviewing'], 'protection', lambda(x
): int(x
))
11069 def setProtection( self
, private
):
11070 self
.__ac
.setProtection( private
)
11071 self
.notify_protection_to_owner(self
)
11072 self
._p
_changed
= 1
11074 def isHidden( self
):
11075 return self
.__ac
.isHidden()
11077 @Updates (['MaKaC.conference.Material',
11078 'MaKaC.conference.Minutes',
11079 'MaKaC.conference.Paper',
11080 'MaKaC.conference.Slides',
11081 'MaKaC.conference.Video',
11082 'MaKaC.conference.Poster',
11083 'MaKaC.conference.Reviewing'], 'hidden')
11084 def setHidden( self
, hidden
):
11085 self
.__ac
.setHidden( hidden
)
11086 self
._p
_changed
= 1
11089 @Updates (['MaKaC.conference.Material',
11090 'MaKaC.conference.Minutes',
11091 'MaKaC.conference.Paper',
11092 'MaKaC.conference.Slides',
11093 'MaKaC.conference.Video',
11094 'MaKaC.conference.Poster',
11095 'MaKaC.conference.Reviewing'], 'accessKey')
11097 def setAccessKey( self
, pwd
="" ):
11098 self
.__ac
.setAccessKey(pwd
)
11099 self
._p
_changed
= 1
11101 def getAccessKey( self
):
11102 return self
.__ac
.getAccessKey()
11104 def grantAccess( self
, prin
):
11105 self
.__ac
.grantAccess( prin
)
11106 if isinstance(prin
, MaKaC
.user
.Avatar
):
11107 prin
.linkTo(self
, "access")
11108 self
._p
_changed
= 1
11110 def revokeAccess( self
, prin
):
11111 self
.__ac
.revokeAccess( prin
)
11112 if isinstance(prin
, MaKaC
.user
.Avatar
):
11113 prin
.unlinkTo(self
, "access")
11114 self
._p
_changed
= 1
11116 def canView( self
, aw
):
11117 """tells whether the specified user has access to the current object
11118 or any of its sub-objects
11120 if self
.isHidden() and not self
.canAccess( aw
):
11125 def isAllowedToAccess( self
, user
):
11126 return (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess( user
)) or self
.__ac
.canUserAccess( user
) or self
.canUserModify(user
)
11128 def canAccess( self
, aw
):
11130 # Allow harvesters (Invenio, offline cache) to access
11132 if self
.__ac
.isHarvesterIP(aw
.getIP()):
11134 #####################################################
11136 from MaKaC
.webinterface
.rh
.collaboration
import RCCollaborationAdmin
, RCCollaborationPluginAdmin
11137 if RCCollaborationAdmin
.hasRights(user
= aw
.getUser()) or \
11138 RCCollaborationPluginAdmin
.hasRights(user
=aw
.getUser(), plugins
='any'):
11141 canUserAccess
= self
.isAllowedToAccess( aw
.getUser() )
11142 canIPAccess
= self
.canIPAccess( aw
.getIP() )
11143 if not self
.isProtected():
11144 return canUserAccess
or canIPAccess
11146 canKeyAccess
= self
.canKeyAccess(aw
)
11147 return canUserAccess
or canKeyAccess
11149 def canKeyAccess( self
, aw
):
11150 sess
= aw
.getSession()
11153 keys
= sess
.getVar("accessKeys")
11155 key
= keys
.get(self
.getUniqueId(),"")
11156 if self
.getAccessKey() != "":
11157 return self
.__ac
.canKeyAccess(key
)
11158 elif self
.getConference() != None:
11159 return self
.getConference().canKeyAccess(aw
, key
)
11162 def grantModification( self
, prin
):
11163 self
.__ac
.grantModification( prin
)
11164 if isinstance(prin
, MaKaC
.user
.Avatar
):
11165 prin
.linkTo(self
, "manager")
11166 self
._p
_changed
= 1
11168 def revokeModification( self
, prin
):
11169 self
.__ac
.revokeModification( prin
)
11170 if isinstance(prin
, MaKaC
.user
.Avatar
):
11171 prin
.unlinkTo(self
, "manager")
11172 self
._p
_changed
= 1
11174 def canModify( self
, aw
):
11175 return self
.canUserModify( aw
.getUser() ) or (self
.getConference() and self
.getConference().canKeyModify( aw
))
11177 def canUserModify( self
, user
):
11178 """Tells whether a user is allowed to modify the current contribution:
11179 only if the user is granted to modify the contribution or the user
11180 can modify any of its upper objects (i.e. conference or session).
11182 return self
.getOwner().canUserModify( user
)
11184 def getModifKey( self
):
11185 return self
.getConference().getModifKey()
11187 def getManagerList( self
):
11188 return self
.__ac
.getModifierList()
11190 def getAllowedToAccessList( self
):
11191 return self
.__ac
.getAccessList()
11193 def requireDomain( self
, dom
):
11194 self
.__ac
.requireDomain( dom
)
11195 self
._p
_changed
= 1
11197 def freeDomain( self
, dom
):
11198 self
.__ac
.freeDomain( dom
)
11199 self
._p
_changed
= 1
11201 def getDomainList( self
):
11202 return self
.__ac
.getRequiredDomainList()
11204 def getAccessController(self
):
11207 def isBuiltin(self
):
11210 class BuiltinMaterial(Material
):
11212 Non-customizable material types
11214 def isBuiltin(self
):
11218 class Reviewing(BuiltinMaterial
):
11220 def __init__( self
, materialData
= None ):
11221 Material
.__init
__( self
, materialData
)
11222 self
.id = "reviewing"
11224 def setId( self
, newId
):
11227 def getContribution(self
):
11228 if isinstance(self
.getOwner(), Review
):
11229 return self
.getOwner().getContribution()
11230 return Material
.getContribution(self
)
11232 class Paper(BuiltinMaterial
):
11234 def __init__( self
, materialData
= None ):
11235 Material
.__init
__( self
, materialData
)
11238 def setId( self
, newId
):
11243 class Slides(BuiltinMaterial
):
11245 def __init__( self
, materialData
= None ):
11246 Material
.__init
__( self
, materialData
)
11249 def setId( self
, newId
):
11254 class Video(BuiltinMaterial
):
11256 def __init__( self
, materialData
= None ):
11257 Material
.__init
__( self
, materialData
)
11260 def setId( self
, newId
):
11263 class Poster(BuiltinMaterial
):
11265 def __init__( self
, materialData
= None ):
11266 Material
.__init
__( self
, materialData
)
11269 def setId( self
, newId
):
11272 class Minutes(BuiltinMaterial
):
11274 def __init__( self
, materialData
= None ):
11275 Material
.__init
__( self
, materialData
)
11276 self
.id = "minutes"
11277 self
.title
= "Minutes"
11280 def clone ( self
, owner
):
11282 mat
.setTitle(self
.getTitle())
11283 mat
.setDescription(self
.getDescription())
11284 mat
.notifyModification()
11286 mat
.setId(self
.getId())
11287 mat
.setOwner(owner
)
11288 mat
.setType(self
.getType())
11290 mat
.setProtection(self
.getAccessController()._getAccessProtection
())
11291 mat
.setAccessKey(self
.getAccessKey())
11292 lrep
= self
._getRepository
()
11293 flist
= lrep
.getFiles()
11294 rlist
= self
.getResourceList()
11296 if r
.getId()=="minutes":
11297 mat
.setText(self
.getText())
11298 elif isinstance(r
,Link
):
11300 newlink
.setOwner(mat
)
11301 newlink
.setName(r
.getName())
11302 newlink
.setDescription(r
.getDescription())
11303 newlink
.setURL(r
.getURL())
11304 mat
.addResource(newlink
)
11305 elif isinstance(r
,LocalFile
):
11306 newfile
= LocalFile()
11307 newfile
.setOwner(mat
)
11308 newfile
.setName(r
.getName())
11309 newfile
.setDescription(r
.getDescription())
11310 newfile
.setFilePath(r
.getFilePath())
11311 newfile
.setFileName(r
.getFileName())
11312 mat
.addResource(newfile
)
11314 raise Exception( _("Unexpected object type in Resource List : ")+str(type(r
)))
11316 mat
.setMainResource(self
.getMainResource())
11320 def setId( self
, newId
):
11323 def setTitle( self
, newTitle
):
11324 self
.title
= newTitle
.strip()
11325 self
.notifyModification()
11327 def _setFile( self
, forcedFileId
= None ):
11328 #XXX: unsafe; it must be changed by mkstemp when migrating to python 2.3
11329 tmpFileName
= tempfile
.mktemp()
11330 fh
= open(tmpFileName
, "w")
11333 self
.file = LocalFile()
11334 self
.file.setId("minutes")
11335 self
.file.setName("minutes")
11336 self
.file.setFilePath(tmpFileName
)
11337 self
.file.setFileName("minutes.txt")
11338 self
.file.setOwner(self
)
11339 self
.file.archive(self
._getRepository
(), forcedFileId
= forcedFileId
)
11341 def setText( self
, text
, forcedFileId
= None ):
11344 self
._setFile
(forcedFileId
= forcedFileId
)
11345 self
.file.replaceContent( text
)
11346 self
.getOwner().notifyModification()
11348 def getText( self
):
11351 return self
.file.readBin()
11353 def getResourceList(self
, sort
=True):
11354 res
= Material
.getResourceList(self
, sort
=sort
)
11356 res
.insert(0, self
.file)
11359 def getResourceById( self
, id ):
11360 if id.strip() == "minutes":
11362 return Material
.getResourceById( self
, id )
11364 def removeResource(self
, res
):
11365 Material
.removeResource(self
, res
)
11366 if self
.file is not None and res
.getId().strip() == "minutes":
11369 self
.notifyModification()
11371 def recoverResource(self
, recRes
):
11372 if recRes
.getId() == "minutes":
11373 recRes
.setOwner(self
)
11376 self
.notifyModification()
11378 Material
.recoverResource(self
, recRes
)
11381 class Resource(CommonObjectBase
):
11382 """This is the base class for representing individual resources which can
11383 be included in material containers for lately being attached to
11384 conference objects (i.e. conferences, sessions or contributions). This
11385 class provides basic data and operations to handle this resources.
11386 Resources can be of serveral types (files, links, ...) which means
11387 different specialisations of this class.
11389 id -- (string) Allows to assign the resource a unique identifier. It
11390 is normally used to uniquely identify the resource among other
11391 resources included in a certain material.
11392 name -- (string) Short description about the purpose or the contents
11394 description - (string) detailed and varied information about the
11396 __owner - (Material) reference to the material object in which the
11397 current resource is included.
11400 fossilizes(IResourceMinimalFossil
, IResourceFossil
)
11402 def __init__( self
, resData
= None ):
11403 self
.id = "not assigned"
11405 self
.description
= ""
11407 self
.__ac
= AccessController(self
)
11408 self
.pdfConversionRequestDate
= None
11410 def __cmp__(self
, other
):
11411 if type(self
) is not type(other
):
11412 # This is actually dangerous and the ZODB manual says not to do this
11413 # because it relies on memory order. However, this branch should never
11414 # be taken anyway since we do not store different types in the same set
11415 # or use them as keys.
11416 return cmp(hash(self
), hash(other
))
11417 if self
.getConference() == other
.getConference():
11418 return cmp(self
.getId(), other
.getId())
11419 return cmp(self
.getConference(), other
.getConference())
11421 def clone( self
, conf
, protection
=True ):
11422 res
= self
.__class
__()
11423 res
.setName(self
.getName())
11424 res
.setDescription(self
.getDescription())
11426 res
.notifyModification()
11427 res
.setId(self
.getId())
11430 res
.setProtection(self
.getAccessController()._getAccessProtection
())
11431 #res.__ac = self.getAccessController()
11435 def notifyModification( self
):
11436 parent
= self
.getOwner()
11438 parent
.setModificationDate()
11439 self
._p
_changed
= 1
11441 def getLocator( self
):
11442 if self
._owner
== None:
11444 lconf
= self
._owner
.getLocator()
11445 lconf
["resId"] = self
.getId()
11448 def setId( self
, newId
):
11449 self
.id = newId
.strip()
11454 def getUniqueId( self
):
11455 """returns (string) the unique identifier of the item
11456 used mainly in the web session access key table
11457 for resources, it is the same as the father material since
11458 only the material can be protected with an access key"""
11459 return self
.getOwner().getUniqueId()
11461 def setOwner(self
, newOwner
):
11462 self
._owner
= newOwner
11464 def getOwner( self
):
11467 def getCategory( self
):
11468 #raise "%s:%s:%s"%(self.getOwner(), Material, isinstance(self.getOwner, Material))
11470 if isinstance(self
.getOwner(), Category
):
11471 return self
.getOwner()
11472 if isinstance(self
.getOwner(), Material
):
11473 return self
.getOwner().getCategory()
11476 def getConference( self
):
11477 # this check owes itself to the fact that some
11478 # protection checking functions call getConference()
11479 # directly on resources, without caring whether they
11480 # are owned by Conferences or Categories
11481 if self
._owner
is None or isinstance(self
._owner
, Category
):
11484 return self
._owner
.getConference()
11486 def getSession( self
):
11487 return self
._owner
.getSession()
11489 def getContribution( self
):
11490 return self
._owner
.getContribution()
11492 def getSubContribution( self
):
11493 return self
._owner
.getSubContribution()
11495 @Updates (['MaKaC.conference.Link',
11496 'MaKaC.conference.LocalFile'], 'name')
11497 def setName( self
, newName
):
11498 self
.name
= newName
.strip()
11499 self
.notifyModification()
11501 def getName( self
):
11504 @Updates (['MaKaC.conference.Link',
11505 'MaKaC.conference.LocalFile'], 'description')
11506 def setDescription( self
, newDesc
):
11507 self
.description
= newDesc
.strip()
11508 self
.notifyModification()
11510 def getDescription( self
):
11511 return self
.description
11513 def archive( self
, repository
= None, forcedFileId
= None ):
11514 """performs necessary operations to ensure the archiving of the
11515 resource. By default is doing nothing as the persistence of the
11516 system already ensures the archiving of the basic resource data"""
11520 if self
._owner
is not None:
11521 self
.notify_protection_to_owner(delete
=True)
11522 self
._owner
.removeResource(self
)
11523 self
.__ac
.unlinkAvatars('access')
11525 TrashCanManager().add(self
)
11528 TrashCanManager().remove(self
)
11530 def canIPAccess( self
, ip
):
11531 if not self
.__ac
.canIPAccess( ip
):
11533 if self
.getOwner() != None:
11534 return self
.getOwner().canIPAccess(ip
)
11537 def isProtected( self
):
11538 # tells if a resource is protected or not
11539 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
11541 def getAccessProtectionLevel( self
):
11542 return self
.__ac
.getAccessProtectionLevel()
11544 def isItselfProtected( self
):
11545 return self
.__ac
.isItselfProtected()
11547 def hasProtectedOwner( self
):
11548 if self
.getOwner() != None:
11549 return self
.getOwner().isProtected()
11552 def notify_protection_to_owner(self
, delete
=False):
11553 # Resources can be attached to other objects (e.g. Registrant),
11554 # but we wish to trigger the notification only when attached to materials (except paper reviewing)
11555 if isinstance(self
.getOwner(), Material
) and not isinstance(self
.getOwner(), Reviewing
):
11556 self
.getOwner().updateNonInheritingChildren(self
, delete
)
11558 @Updates (['MaKaC.conference.Link',
11559 'MaKaC.conference.LocalFile'],'protection', lambda(x
): int(x
))
11561 def setProtection( self
, private
):
11562 self
.__ac
.setProtection( private
)
11563 self
.notify_protection_to_owner()
11565 def grantAccess( self
, prin
):
11566 self
.__ac
.grantAccess( prin
)
11567 if isinstance(prin
, MaKaC
.user
.Avatar
):
11568 prin
.linkTo(self
, "access")
11570 def revokeAccess( self
, prin
):
11571 self
.__ac
.revokeAccess( prin
)
11572 if isinstance(prin
, MaKaC
.user
.Avatar
):
11573 prin
.unlinkTo(self
, "access")
11575 def canView( self
, aw
):
11576 """tells whether the specified user has access to the current object
11577 or any of its sub-objects
11579 return self
.canAccess( aw
)
11581 def isAllowedToAccess( self
, user
):
11582 return self
.__ac
.canUserAccess( user
) or self
.canUserModify( user
) or (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess( user
))
11584 def canAccess( self
, aw
):
11585 # Allow harvesters (Invenio, offline cache) to access
11587 if self
.__ac
.isHarvesterIP(aw
.getIP()):
11589 #####################################################
11591 from MaKaC
.webinterface
.rh
.collaboration
import RCCollaborationAdmin
, RCCollaborationPluginAdmin
11592 if RCCollaborationAdmin
.hasRights(user
= aw
.getUser()) or \
11593 RCCollaborationPluginAdmin
.hasRights(user
=aw
.getUser(), plugins
='any'):
11596 if not self
.canIPAccess(aw
.getIP()) and not self
.canUserModify(aw
.getUser()) and not self
.isAllowedToAccess( aw
.getUser() ):
11598 if not self
.isProtected():
11600 flag
= self
.isAllowedToAccess( aw
.getUser() )
11601 return flag
or self
.canKeyAccess(aw
) or self
.getOwner().canKeyAccess(aw
) or \
11602 (self
.getConference() != None and self
.getConference().canKeyAccess(aw
) and self
.getAccessKey() == "") or \
11603 (self
.getConference() != None and self
.getConference().canKeyAccess(aw
) and self
.getAccessKey() == self
.getConference().getAccessKey())
11605 def grantModification( self
, prin
):
11606 self
.__ac
.grantModification( prin
)
11608 def revokeModification( self
, prin
):
11609 self
.__ac
.revokeModification( prin
)
11611 def canModify( self
, aw
):
11612 return self
.canUserModify( aw
.getUser() ) or (self
.getConference() and self
.getConference().canKeyModify( aw
))
11614 def canUserModify( self
, user
):
11615 """Tells whether a user is allowed to modify the current contribution:
11616 only if the user is granted to modify the contribution or the user
11617 can modify any of its upper objects (i.e. conference or session).
11619 return self
.getOwner().canUserModify( user
)
11621 def getModifKey( self
):
11622 return self
.getConference().getModifKey()
11624 def getManagerList( self
):
11625 return self
.__ac
.getModifierList()
11627 def getAllowedToAccessList( self
):
11628 return self
.__ac
.getAccessList()
11630 def getURL( self
):
11633 def requireDomain( self
, dom
):
11634 self
.__ac
.requireDomain( dom
)
11636 def freeDomain( self
, dom
):
11637 self
.__ac
.freeDomain( dom
)
11639 def getDomainList( self
):
11640 return self
.__ac
.getRequiredDomainList()
11642 def getAccessController(self
):
11645 def getAccessKey(self
):
11646 if self
.getOwner() is not None:
11647 return self
.getOwner().getAccessKey()
11650 def canKeyAccess( self
, aw
):
11651 sess
= aw
.getSession()
11654 accessKey
= self
.getAccessKey()
11655 keys
= sess
.getVar("accessKeys")
11657 if keys
.has_key(self
.getUniqueId()):
11658 if (accessKey
!= "" and keys
[self
.getUniqueId()] == accessKey
) or (accessKey
== "" and self
.getConference().getAccessKey() != "" and keys
[self
.getUniqueId()] == self
.getConference().getAccessKey()):
11662 def getReviewingState(self
):
11663 """ Returns the reviewing state of a resource, which is the reviewing state of the material to which it belongs.
11664 The state is represented by an integer:
11665 0 : there's no reviewing state because the resource doesn't belong to a material,
11666 the material does not belong to a contribution, or the conference does not have reviewing.
11667 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
11668 2 : the material is subject to reviewing, but has not been submitted yet by the author
11669 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
11670 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
11671 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
11673 if isinstance(self
.getOwner(), Material
):
11674 return self
.getOwner().getReviewingState()
11675 else: #ressource does not belong to a material
11678 def setPDFConversionRequestDate( self
, newPdfConversionRequestDate
):
11679 self
.pdfConversionRequestDate
= newPdfConversionRequestDate
11681 def getPDFConversionStatus(self
):
11683 if not hasattr(self
, "pdfConversionRequestDate"):
11684 self
.pdfConversionRequestDate
= None
11686 if self
.pdfConversionRequestDate
is not None and self
.pdfConversionRequestDate
+ timedelta(seconds
=50) > nowutc() :
11687 return 'converting'
11690 class Link(Resource
):
11691 """Specialises Resource class in order to represent web links. Objects of
11692 this class will contain necessary information to include in a conference
11693 object links to internet resources through a URL.
11695 url -- (string) Contains the URL to the internet target resource.
11698 fossilizes(ILinkMinimalFossil
, ILinkFossil
)
11700 def __init__( self
, resData
= None ):
11701 Resource
.__init
__( self
, resData
)
11704 def clone( self
, conf
):
11705 link
= Resource
.clone(self
, conf
)
11706 link
.setURL(self
.getURL())
11709 @Updates ('MaKaC.conference.Link', 'url')
11710 def setURL( self
, newURL
):
11711 self
.url
= newURL
.strip()
11712 self
.notifyModification()
11714 def getURL( self
):
11718 class LocalFile(Resource
):
11719 """Specialises Resource class in order to represent files which can be
11720 stored in the system. The user can choose to use the system as an
11721 archive of electronic files so he may want to attach a file which is
11722 in his computer to a conference so it remains there and must be kept
11723 in the system. This object contains the file basic metadata and provides
11724 the necessary operations to ensure the corresponding file is archived
11725 (it uses one of the file repositories of the system to do so) and keeps
11726 the reference for being able to access it afterwards.
11728 fileName -- (string) Name of the file. Normally the original name of
11729 the user submitted file is kept.
11730 filePath -- (string) If it is set, it contains a local path to the
11731 file submitted by the user and uploaded in the system. This
11732 attribute is only temporary used so it keeps a pointer to a
11733 temporary uploaded file.
11734 __repository -- (FileRep) Once a file is archived, it is kept in a
11735 FileRepository for long term. This attribute contains a pointer
11736 to the file repository where the file is kept.
11737 __archivedId -- (string) It contains a unique identifier for the file
11738 inside the repository where it is archived.
11741 fossilizes(ILocalFileMinimalFossil
, ILocalFileFossil
, ILocalFileExtendedFossil
, ILocalFileAbstractMaterialFossil
)
11743 def __init__( self
, resData
= None ):
11744 Resource
.__init
__( self
, resData
)
11748 self
.__repository
= None
11749 self
.__archivedId
= ""
11751 def clone( self
, conf
, protection
=True ):
11752 localfile
= Resource
.clone(self
, conf
, protection
)
11753 localfile
.setFilePath(self
.getFilePath())
11754 localfile
.setFileName(self
.getFileName())
11757 def setFileName( self
, newFileName
, checkArchive
=True ):
11758 """While the file is not archived sets the file name of the current
11759 object to the one specified (if a full path is specified the
11760 base name is extracted) replacing on it blanks by underscores.
11762 if checkArchive
and self
.isArchived():
11763 raise MaKaCError( _("The file name of an archived file cannot be changed"), _("File Archiving"))
11764 #Using os.path.basename is not enough as it only extract filenames
11765 # correclty depending on the server platform. So we need to convert
11766 # to the server platform and apply the basename extraction. As I
11767 # couldn't find a python function for this this is done manually
11768 # although it can contain errors
11769 #On windows basename function seems to work properly with unix file
11771 if newFileName
.count("/"):
11773 newFileName
= newFileName
.split("/")[-1]
11775 #windows file path: there "/" is not allowed on windows paths
11776 newFileName
= newFileName
.split("\\")[-1]
11777 self
.fileName
= newFileName
.strip().replace(" ", "_")
11779 def getFileName( self
):
11780 return self
.fileName
11782 def getFileType( self
):
11783 fileExtension
= os
.path
.splitext( self
.getFileName() )[1]
11784 if fileExtension
!= "":
11785 fileExtension
= fileExtension
[1:]
11786 cfg
= Config
.getInstance()
11787 if cfg
.getFileType( fileExtension
) != "":
11788 return cfg
.getFileType( fileExtension
)
11790 return fileExtension
11792 def setFilePath( self
, filePath
):
11793 if self
.isArchived():
11794 raise MaKaCError( _("The path of an archived file cannot be changed"), _("File Archiving"))
11795 if not os
.access( filePath
.strip(), os
.F_OK
):
11796 raise Exception( _("File does not exist : %s")%filePath
.strip())
11797 self
.filePath
= filePath
.strip()
11799 def getCreationDate( self
):
11800 return self
.__repository
.getCreationDate(self
.__archivedId
)
11802 def getFilePath( self
):
11803 if not self
.isArchived():
11804 return self
.filePath
11805 return self
.__repository
.getFilePath(self
.__archivedId
)
11807 def getSize( self
):
11808 if not self
.isArchived():
11809 return int(os
.stat(self
.getFilePath())[stat
.ST_SIZE
])
11810 return self
.__repository
.getFileSize( self
.__archivedId
)
11812 def setArchivedId( self
, rep
, id ):
11813 self
.__repository
= rep
11814 self
.__archivedId
= id
11816 def getRepositoryId( self
):
11817 return self
.__archivedId
11819 def setRepositoryId(self
, id):
11820 self
.__archivedId
= id
11822 def isArchived( self
):
11823 return self
.__repository
!= None and self
.__archivedId
!= ""
11825 def readBin( self
):
11826 if not self
.isArchived():
11827 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11828 return self
.__repository
.readFile( self
.__archivedId
)
11830 def replaceContent( self
, newContent
):
11831 if not self
.isArchived():
11832 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11833 self
.__repository
.replaceContent( self
.__archivedId
, newContent
)
11835 def archive( self
, repository
=None, forcedFileId
= None ):
11836 if self
.isArchived():
11837 raise Exception( _("File is already archived"))
11839 raise Exception( _("Destination repository not set"))
11840 if self
.filePath
== "":
11841 return _("Nothing to archive")
11842 repository
.storeFile( self
, forcedFileId
= forcedFileId
)
11844 self
.notifyModification()
11846 def unArchive(self
):
11848 self
.__repository
= None
11849 self
.__archivedId
= ""
11852 if not self
.isArchived():
11853 raise Exception( _("File is not archived, so it cannot be recovered."))
11854 if not self
.__repository
:
11855 raise Exception( _("Destination repository not set."))
11856 self
.__repository
.recoverFile(self
)
11857 Resource
.recover(self
)
11858 self
.notifyModification()
11860 def delete( self
):
11861 if not self
.isArchived():
11862 os
.remove( self
.getFilePath() )
11864 self
.__repository
.retireFile( self
)
11865 except AttributeError, e
:
11867 Resource
.delete( self
)
11869 def getRepository(self
):
11870 return self
.__repository
11872 def __str__( self
):
11873 return self
.getFileName()
11875 #getURL is removed at the moment from the LocalFile and the file access
11876 # is completely delegated to the web interface; the web interface will
11877 # have to access the files locally (using the getFilePath) or the readBin
11879 #However, for the future it could be required to have several file
11880 # repositories so the file access will have to be reviewed.
11881 #def getURL( self ):
11882 # #XXX: Very bad!! We should find a better solution
11883 # c = Config.getInstance()
11884 # return c.getArchivedFileURL( self )
11887 class TCIndex( Persistent
):
11888 """Index for conference track coordinators.
11890 This class allows to index conference track coordinators so the owner
11891 can answer optimally to the query if a user is coordinating
11892 any conference track.
11893 It is implemented by simply using a BTree where the Avatar id is used
11894 as key (because it is unique and non variable) and a list of
11895 coordinated tracks is kept as keys. It is the responsability of the
11896 index owner (conference) to keep it up-to-date i.e. notify track
11897 coordinator additions and removals.
11900 def __init__( self
):
11901 self
._idx
= OOBTree()
11904 def getTracks( self
, av
):
11905 """Gives a list with the tracks a user is coordinating.
11909 return self
._idx
.get( av
.getId(), [] )
11911 def indexCoordinator( self
, av
, track
):
11912 """Registers in the index a coordinator of a track.
11914 if av
== None or track
== None:
11916 if not self
._idx
.has_key( av
.getId() ):
11919 l
= self
._idx
[av
.getId()]
11922 # necessary, otherwise ZODB won't know it needs to update the BTree
11923 self
._idx
[av
.getId()] = l
11924 self
.notifyModification()
11926 def unindexCoordinator( self
, av
, track
):
11927 if av
== None or track
== None:
11929 l
= self
._idx
.get( av
.getId(), [] )
11932 self
._idx
[av
.getId()] = l
11933 self
.notifyModification()
11935 def notifyModification(self
):
11936 self
._p
_changed
= 1
11939 class Track(CoreObject
):
11941 def __init__( self
):
11942 self
.conference
= None
11943 self
.id = "not assigned"
11945 self
.description
= ""
11946 self
.subTracks
= {}
11947 self
.__SubTrackGenerator
= Counter()
11948 self
._abstracts
= OOBTree()
11949 self
._coordinators
= []
11950 self
._contributions
= OOBTree()
11953 def __cmp__(self
, other
):
11954 if type(self
) is not type(other
):
11955 # This is actually dangerous and the ZODB manual says not to do this
11956 # because it relies on memory order. However, this branch should never
11957 # be taken anyway since we do not store different types in the same set
11958 # or use them as keys.
11959 return cmp(hash(self
), hash(other
))
11960 if self
.getConference() == other
.getConference():
11961 return cmp(self
.getId(), other
.getId())
11962 return cmp(self
.getConference(), other
.getConference())
11964 def clone(self
, conference
):
11966 tr
.setConference(conference
)
11967 tr
.setTitle(self
.getTitle())
11968 tr
.setCode(self
.getCode())
11969 tr
.setDescription(self
.getDescription())
11971 for co
in self
.getCoordinatorList() :
11972 tr
.addCoordinator(co
)
11974 for subtr
in self
.getSubTrackList() :
11975 tr
.addSubTrack(subtr
.clone())
11980 def delete( self
):
11981 """Deletes a track from the system. All the associated abstracts will
11982 also be notified so the track is no longer associated to them.
11984 #XXX: Should we allow to delete a track when there are some abstracts
11985 # or contributions submitted for it?!?!?!?!
11987 # we must notify each abstract in the track about the deletion of the
11989 while len(self
._abstracts
)>0:
11990 k
= self
._abstracts
.keys()[0]
11991 abstract
= self
._abstracts
[k
]
11992 del self
._abstracts
[k
]
11993 abstract
.removeTrack( self
)
11995 # we must notify each contribution in the track about the deletion of the
11997 while len(self
._contributions
)>0:
11998 k
= self
._contributions
.keys()[0]
11999 contrib
= self
._contributions
[k
]
12000 del self
._contributions
[k
]
12001 contrib
.removeTrack( self
)
12003 # we must delete and unindex all the possible track coordinators
12004 while len(self
._coordinators
)>0:
12005 self
.removeCoordinator(self
._coordinators
[0])
12007 # we must notify the conference about the track deletion
12008 if self
.conference
:
12009 conf
= self
.conference
12010 self
.conference
= None
12011 conf
.removeTrack( self
)
12013 TrashCanManager().add(self
)
12016 TrashCanManager().remove(self
)
12018 def canModify( self
, aw
):
12019 return self
.conference
.canModify( aw
)
12021 def canUserModify( self
, av
):
12022 return self
.conference
.canUserModify( av
)
12024 def canView( self
, aw
):
12025 return self
.conference
.canView( aw
)
12027 def notifyModification( self
):
12028 parent
= self
.getConference()
12030 parent
.setModificationDate()
12031 self
._p
_changed
= 1
12033 def getLocator( self
):
12034 """Gives back a globaly unique identification encapsulated in a Locator
12035 object for the track instance
12037 if self
.conference
== None:
12039 lconf
= self
.conference
.getLocator()
12040 lconf
["trackId"] = self
.getId()
12043 def setConference(self
, conference
):
12044 self
.conference
= conference
12046 def getConference( self
):
12047 return self
.conference
12049 def getOwner( self
):
12050 return self
.getConference()
12052 def setId( self
, newId
):
12053 self
.id = str(newId
)
12058 def setTitle( self
, newTitle
):
12059 self
.title
= newTitle
12060 self
.notifyModification()
12062 def getTitle( self
):
12065 def setDescription(self
, newDescription
):
12066 self
.description
= newDescription
12067 self
.notifyModification()
12069 def getDescription(self
):
12070 return self
.description
12076 except AttributeError:
12080 def setCode(self
,newCode
):
12081 self
._code
=str(newCode
).strip()
12083 def __generateNewSubTrackId( self
):
12084 return str(self
.__SubTrackGenerator
.newCount())
12086 def addSubTrack( self
, newSubTrack
):
12087 """Registers the contribution passed as parameter within the session
12088 assigning it a unique id.
12090 if newSubTrack
in self
.subTracks
.values():
12092 subTrackId
= newSubTrack
.getId()
12093 if subTrackId
== "not assigned":
12094 subTrackId
= self
.__generateNewSubTrackId
()
12095 self
.subTracks
[subTrackId
] = newSubTrack
12096 newSubTrack
.setTrack( self
)
12097 newSubTrack
.setId( subTrackId
)
12098 self
.notifyModification()
12100 def removeSubTrack( self
, subTrack
):
12101 """Removes the indicated contribution from the session
12103 if subTrack
in self
.subTracks
.values():
12104 del self
.subTracks
[ subTrack
.getId() ]
12105 subTrack
.setTrack( None )
12107 self
.notifyModification()
12109 def recoverSubTrack(self
, subTrack
):
12110 self
.addSubTrack(subTrack
)
12113 def newSubTrack( self
):
12115 self
.addSubTrack( st
)
12118 def getSubTrackById( self
, id ):
12119 if self
.subTracks
.has_key( id ):
12120 return self
.subTracks
[ id ]
12123 def getSubTrackList( self
):
12124 return self
.subTracks
.values()
12126 def getAbstractList( self
):
12130 if self
._abstracts
:
12132 except AttributeError:
12133 self
._abstracts
= OOBTree()
12134 return self
._abstracts
.values()
12136 def getAbstractById( self
, id ):
12138 if self
._abstracts
:
12140 except AttributeError:
12141 self
._abstracts
= OOBTree()
12142 return self
._abstracts
.get(str(id).strip())
12144 def hasAbstract( self
, abstract
):
12148 if self
._abstracts
:
12150 except AttributeError:
12151 self
._abstracts
= OOBTree()
12152 return self
._abstracts
.has_key( abstract
.getId() )
12154 def addAbstract( self
, abstract
):
12155 """Adds an abstract to the track abstract list.
12157 Notice that this method doesn't notify the abstract about the track
12160 if not self
.hasAbstract( abstract
):
12161 self
._abstracts
[ abstract
.getId() ] = abstract
12162 #abstract.addTrack( self )
12164 def removeAbstract( self
, abstract
):
12165 """Removes an abstract from the track abstract list.
12167 Notice that this method doesn't notify the abstract about the track
12170 if self
.hasAbstract( abstract
):
12171 del self
._abstracts
[ abstract
.getId() ]
12172 #abstract.removeTrack( self )
12174 def addCoordinator( self
, av
):
12175 """Grants coordination privileges to user.
12178 av -- (MaKaC.user.Avatar) the user to which
12179 coordination privileges must be granted.
12183 if self
._coordinators
:
12185 except AttributeError, e
:
12186 self
._coordinators
= []
12187 self
.notifyModification()
12189 if not (av
in self
._coordinators
):
12190 self
._coordinators
.append( av
)
12191 self
.getConference().addTrackCoordinator( self
, av
)
12192 av
.linkTo(self
, "coordinator")
12193 self
.notifyModification()
12195 def removeCoordinator( self
, av
):
12196 """Revokes coordination privileges to user.
12199 av -- (MaKaC.user.Avatar) user for which coordination privileges
12203 if self
._coordinators
:
12205 except AttributeError, e
:
12206 self
._coordinators
= []
12207 self
.notifyModification()
12209 if av
in self
._coordinators
:
12210 self
._coordinators
.remove( av
)
12211 self
.getConference().removeTrackCoordinator( self
, av
)
12212 av
.linkTo(self
, "coordinator")
12213 self
.notifyModification()
12215 def isCoordinator( self
, av
):
12216 """Tells whether the specified user is a coordinator of the track.
12219 av -- (MaKaC.user.Avatar) user to be checke
12221 Return value: (boolean)
12224 if self
._coordinators
:
12226 except AttributeError, e
:
12227 self
._coordinators
= []
12229 return av
in self
._coordinators
12231 def getCoordinatorList( self
):
12232 """Return all users which have privileges to coordinate the track.
12234 Return value: (list)
12237 if self
._coordinators
:
12239 except AttributeError, e
:
12240 self
._coordinators
= []
12242 return self
._coordinators
12244 def canCoordinate( self
, aw
):
12245 """Tells if a user has coordination privileges.
12247 Only track coordinators have coordination privileges over a track.
12250 aw -- (MaKaC.accessControl.AccessWrapper) User access
12251 information for which the coordination privileges must be
12254 Return value: (boolean)
12256 return self
.isCoordinator( aw
.getUser() ) or self
.canModify( aw
)
12258 def addContribution( self
, newContrib
):
12262 if self
._contributions
:
12264 except AttributeError:
12265 self
._contributions
= OOBTree()
12266 if self
._contributions
.has_key( newContrib
.getId() ):
12268 self
._contributions
[ newContrib
.getId() ] = newContrib
12269 newContrib
.setTrack( self
)
12271 def getModifKey( self
):
12272 return self
.getConference().getModifKey()
12274 def removeContribution( self
, contrib
):
12278 if self
._contributions
:
12280 except AttributeError:
12281 self
._contributions
= OOBTree()
12282 if not self
._contributions
.has_key( contrib
.getId() ):
12284 del self
._contributions
[ contrib
.getId() ]
12285 contrib
.setTrack( None )
12287 def hasContribution( self
, contrib
):
12289 if self
._contributions
:
12291 except AttributeError:
12292 self
._contributions
= OOBTree()
12293 return self
._contributions
.has_key( contrib
.getId() )
12295 def getContributionList(self
):
12297 if self
._contributions
:
12299 except AttributeError:
12300 self
._contributions
= OOBTree()
12301 return self
._contributions
.values()
12303 def canUserCoordinate( self
, av
):
12304 return self
.isCoordinator( av
) or self
.canUserModify( av
)
12307 class SubTrack(CoreObject
):
12309 def __init__( self
):
12311 self
.id = "not assigned"
12313 self
.description
= ""
12317 sub
.setDescription(self
.getDescription())
12318 sub
.setTitle(self
.getTitle())
12324 TrashCanManager().add(self
)
12327 TrashCanManager().remove(self
)
12329 def canModify( self
, aw
):
12330 return self
.track
.canModify( aw
)
12332 def canView( self
, aw
):
12333 return self
.track
.canView( aw
)
12335 def notifyModification( self
):
12336 parent
= self
.getTrack()
12338 parent
.setModificationDate()
12339 self
._p
_changed
= 1
12341 def getLocator( self
):
12342 """Gives back a globaly unique identification encapsulated in a Locator
12343 object for the session instance
12345 if self
.track
== None:
12347 lconf
= self
.track
.getLocator()
12348 lconf
["subTrackId"] = self
.getId()
12351 def setTrack(self
, track
):
12356 def getTrack( self
):
12359 def getOwner( self
):
12360 return self
.getTrack()
12362 def setId( self
, newId
):
12363 self
.id = str(newId
)
12368 def setTitle( self
, newTitle
):
12369 self
.title
= newTitle
12370 self
.notifyModification()
12372 def getTitle( self
):
12375 def setDescription(self
, newDescription
):
12376 self
.description
= newDescription
12377 self
.notifyModification()
12379 def getDescription(self
):
12380 return self
.description
12383 class ContributionType(Persistent
):
12385 def __init__(self
, name
, description
, conference
):
12388 self
._description
= description
12389 self
._conference
= conference
12394 def setId(self
, id):
12400 def setName(self
, name
):
12403 def getDescription(self
):
12404 return self
._description
12406 def setDescription(self
, desc
):
12407 self
._description
= desc
12409 def getConference(self
):
12410 return self
._conference
12412 def setConference(self
, conf
):
12413 self
._conference
= conf
12415 def getLocator( self
):
12416 if self
._conference
== None:
12418 lconf
= self
._conference
.getLocator()
12419 lconf
["contribTypeId"] = self
.getId()
12422 def canModify(self
, aw
):
12423 return self
._conference
.canModify(aw
)
12426 self
.setConference(None)
12427 TrashCanManager().add(self
)
12430 TrashCanManager().remove(self
)
12432 def clone(self
, conference
):
12433 type = ContributionType(self
.getName(), self
.getDescription(),conference
)
12437 class BOAConfig(Persistent
):
12438 """Contains the configuration of the Book of Abstracts of a conference
12440 sortByTypes
= {"number": L_("ID"),
12441 "name": L_("Title"),
12442 "sessionTitle": L_("Session title"),
12443 "speaker": L_("Presenter"),
12444 "schedule": L_("Schedule")}
12446 correspondingAuthorTypes
= {"none": L_("Nobody"),
12447 "submitter": L_("Submitter"),
12448 "speakers": L_("Speakers")}
12450 def __init__(self
,conf
):
12453 self
._showIds
= False
12454 self
._sortBy
= "number"
12455 self
._correspondingAuthor
= "submitter"
12456 self
._modificationDS
= nowutc()
12457 self
._cache
= False
12462 def setText(self
,newText
):
12463 self
._text
=newText
.strip()
12464 self
._notifyModification
()
12466 def getShowIds(self
):
12467 if not hasattr(self
, "_showIds"):
12468 self
._showIds
=False
12469 return self
._showIds
12471 def setShowIds(self
,showIds
):
12472 self
._showIds
=showIds
12473 self
._notifyModification
()
12475 def getSortBy(self
):
12476 if not hasattr(self
, "_sortBy"):
12477 self
._sortBy
="number"
12478 return self
._sortBy
12480 def setSortBy(self
,sortBy
):
12481 self
._sortBy
=sortBy
12482 self
._notifyModification
()
12485 def getSortByTypes():
12486 return BOAConfig
.sortByTypes
12488 def getCorrespondingAuthor(self
):
12489 if not hasattr(self
, "_correspondingAuthor"):
12490 self
._correspondingAuthor
= "submitter"
12491 return self
._correspondingAuthor
12493 def setCorrespondingAuthor(self
, correspondingAuthor
):
12494 self
._correspondingAuthor
= correspondingAuthor
12495 self
._notifyModification
()
12498 def getCorrespondingAuthorTypes():
12499 return BOAConfig
.correspondingAuthorTypes
12501 def isCacheEnabled(self
):
12502 if not hasattr(self
, '_cache'):
12503 self
._cache
= False
12506 def setCache(self
, value
):
12507 self
._cache
= value
;
12509 def _notifyModification(self
):
12510 self
._modificationDS
= nowutc()
12513 def lastChanged(self
):
12514 if not hasattr(self
, '_modificationDS'):
12515 self
._modificationDS
= nowutc()
12516 return self
._modificationDS