[FIX] Add sessions to download material
[cds-indico.git] / indico / MaKaC / conference.py
blobae773743f375d2fdecb4829f67f67fe6bfc82bf6
1 # -*- coding: utf-8 -*-
2 ##
3 ##
4 ## This file is part of Indico.
5 ## Copyright (C) 2002 - 2012 European Organization for Nuclear Research (CERN).
6 ##
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/>.
20 # fossil classes
21 from MaKaC.plugins import PluginsHolder, Observable
22 from MaKaC.common.utils import formatDateTime
23 from MaKaC.fossils.subcontribution import ISubContribParticipationFossil,\
24 ISubContribParticipationFullFossil, ISubContributionFossil, ISubContributionWithSpeakersFossil
25 from MaKaC.fossils.contribution import IContributionParticipationFossil,\
26 IContributionFossil, IContributionWithSpeakersFossil, IContributionParticipationMinimalFossil, \
27 IContributionWithSubContribsFossil,\
28 IContributionParticipationTTDisplayFossil, \
29 IContributionParticipationTTMgmtFossil
30 from MaKaC.fossils.conference import IConferenceMinimalFossil, \
31 IConferenceEventInfoFossil, IConferenceFossil,\
32 ISessionFossil, ISessionSlotFossil, IMaterialMinimalFossil,\
33 IMaterialFossil, IConferenceParticipationFossil,\
34 IResourceMinimalFossil, ILinkMinimalFossil, ILocalFileMinimalFossil,\
35 IResourceFossil, ILinkFossil, ILocalFileFossil,\
36 ILocalFileExtendedFossil, IConferenceParticipationMinimalFossil,\
37 ICategoryFossil, ILocalFileAbstractMaterialFossil
38 from MaKaC.common.fossilize import fossilizes, Fossilizable
39 from MaKaC.common.url import ShortURLMapper
40 from MaKaC.contributionReviewing import Review
41 from MaKaC.rb_location import CrossLocationQueries, CrossLocationDB
42 from indico.util.i18n import L_
45 import re, os
46 import tempfile
47 import copy
48 import stat
49 from datetime import datetime, timedelta, time
51 from MaKaC.contributionReviewing import ReviewManager
52 from MaKaC.paperReviewing import ConferencePaperReview as ConferencePaperReview
53 from MaKaC.abstractReviewing import ConferenceAbstractReview as ConferenceAbstractReview
55 from pytz import timezone
56 from pytz import all_timezones
58 from persistent import Persistent
59 from BTrees.OOBTree import OOBTree, OOTreeSet, OOSet
60 from BTrees.OIBTree import OIBTree,OISet,union
61 import MaKaC
62 import MaKaC.common.indexes as indexes
63 from MaKaC.common.timezoneUtils import nowutc, maxDatetime
64 import MaKaC.fileRepository as fileRepository
65 from MaKaC.schedule import ConferenceSchedule, SessionSchedule,SlotSchedule,\
66 PosterSlotSchedule, SlotSchTypeFactory, ContribSchEntry, \
67 LinkedTimeSchEntry, BreakTimeSchEntry
68 import MaKaC.review as review
69 from MaKaC.common import Config, DBMgr, utils
70 from MaKaC.common.Counter import Counter
71 from MaKaC.common.ObjectHolders import ObjectHolder
72 from MaKaC.common.Locators import Locator
73 from MaKaC.accessControl import AccessController, AdminList
74 from MaKaC.errors import MaKaCError, TimingError, ParentTimingError, EntryTimingError, NoReportError
75 from MaKaC import registration,epayment
76 from MaKaC.evaluation import Evaluation
77 from MaKaC.trashCan import TrashCanManager
78 from MaKaC.user import AvatarHolder
79 from MaKaC.common import pendingQueues
80 from MaKaC.common.info import HelperMaKaCInfo
81 from MaKaC.participant import Participation
82 from MaKaC.common.log import LogHandler
83 import MaKaC.task as task
84 import MaKaC.common.info as info
85 from MaKaC.badge import BadgeTemplateManager
86 from MaKaC.poster import PosterTemplateManager
87 from MaKaC.common.cache import CategoryCache, EventCache
88 from MaKaC.common import mail
89 from MaKaC.common.utils import getHierarchicalId
90 from MaKaC.i18n import _
91 from MaKaC.common.PickleJar import Updates
92 from MaKaC.common.PickleJar import if_else
94 from MaKaC.webinterface import urlHandlers
96 from MaKaC.common.logger import Logger
97 from MaKaC.common.contextManager import ContextManager
98 import zope.interface
100 from indico.modules.scheduler import Client, tasks
101 from indico.util.date_time import utc_timestamp
102 from indico.core.index import IIndexableByStartDateTime, IUniqueIdProvider, Catalog
103 from MaKaC.webinterface.common.tools import escape_html
106 class CoreObject(Persistent):
108 CoreObjects are Persistent objects that are employed by Indico's core
111 zope.interface.implements(IUniqueIdProvider,
112 IIndexableByStartDateTime)
114 def setModificationDate(self, date = None):
116 Method called to notify the current object has been modified.
118 if not date:
119 date = nowutc()
120 self._modificationDS = date
122 def __conform__(self, proto):
124 if proto == IIndexableByStartDateTime:
125 return utc_timestamp(self.getStartDate())
126 else:
127 return None
130 class Locatable:
132 Inherited by objects that imply a physical location:
133 * Conferences
134 * Sessions
135 * SessionSlots
136 * Contributions
137 * SubContributions
140 def getLocationParent(self):
142 Returns the object the location info should be inherited from
143 (Overridden)
145 raise Exception("Unimplemented method")
147 def getLocation(self):
148 if self.getOwnLocation():
149 return self.getOwnLocation()
150 return self.getInheritedLocation()
152 def getOwnLocation(self):
153 if len(self.places) > 0:
154 return self.places[0]
155 return None
157 def getInheritedLocation(self):
158 return self.getLocationParent().getLocation()
160 def getOwnRoom(self):
161 if len(self.rooms) > 0:
162 return self.rooms[0]
163 return None
165 def getRoom(self):
166 if self.getOwnRoom():
167 return self.getOwnRoom()
168 return self.getInheritedRoom()
170 def getInheritedRoom(self):
171 return self.getLocationParent().getRoom()
173 def setLocation(self, newLocation):
174 oldLocation = self.getOwnLocation()
175 if newLocation == None:
176 if len(self.places) > 0:
177 del self.places[0]
178 elif len(self.places) > 0:
179 self.places[0] = newLocation
180 else:
181 self.places.append( newLocation )
182 self.notifyModification()
184 def setRoom(self, newRoom):
185 oldRoom = self.getOwnRoom()
186 if newRoom == None:
187 if len(self.rooms) > 0:
188 del self.rooms[0]
189 elif len(self.rooms) > 0:
190 self.rooms[0] = newRoom
191 else:
192 self.rooms.append( newRoom )
193 self.notifyModification()
196 class CommonObjectBase(CoreObject, Observable, Fossilizable):
198 This class is for holding commonly used methods that are used by several classes.
199 It is inherited by the following classes:
200 * Category
201 * Conference
202 * Session
203 * Contribution
204 * SubContribution
205 * Material
206 * Resource
209 def getRecursiveManagerList(self):
210 av_set = set()
212 # Get the AccessProtectionLevel for this
213 apl = self.getAccessProtectionLevel()
215 if apl == -1:
216 pass
217 elif apl == 1:
218 for av in self.getManagerList():
219 av_set.add(av)
220 for av in self.getOwner().getRecursiveManagerList():
221 av_set.add(av)
222 else:
223 for av in self.getManagerList():
224 av_set.add(av)
226 if self.getOwner():
227 for av in self.getOwner().getRecursiveManagerList():
228 av_set.add(av)
230 return list(av_set)
232 def getRecursiveAllowedToAccessList(self, onlyManagers=False):
233 """Returns a set of Avatar resp. CERNGroup objects for those people resp.
234 e-groups allowed to access this object as well as all parent objects.
237 # Initialize set of avatars/groups: this will hold those
238 # people/groups explicitly
239 # allowed to access this object
240 av_set = set()
242 # Get the AccessProtectionLevel for this
243 apl = self.getAccessProtectionLevel()
245 # If this object is "absolutely public", then return an empty set
246 if apl == -1:
247 pass
249 # If this object is protected "all by itself", then get the list of
250 # people/groups allowed to access it, plus managers of owner(s)
251 elif apl == 1:
252 al = self.getAllowedToAccessList() + self.getManagerList() + \
253 self.getOwner().getRecursiveManagerList()
254 if al is not None:
255 for av in al:
256 av_set.add(av)
258 # If access settings are inherited (and PRIVATE) from its owners, look at those.
259 elif apl == 0 and self.isProtected():
260 # If event is protected, then get list of people/groups allowed
261 # to access, and add that to the set of avatars.
262 al = self.getAllowedToAccessList() + self.getManagerList()
263 if al is not None:
264 for av in al:
265 av_set.add(av)
267 # Add list of avatars/groups allowed to access parents objects.
268 owner = self.getOwner()
269 if owner is not None:
270 owner_al = owner.getRecursiveAllowedToAccessList(onlyManagers=True)
271 if owner_al is not None:
272 for av in owner_al:
273 av_set.add(av)
275 # return set containing whatever avatars/groups we may have collected
276 return av_set
279 class CategoryManager( ObjectHolder ):
280 idxName = "categories"
281 counterName = "CATEGORY"
283 def add(self, category):
284 ObjectHolder.add(self, category)
285 # Add category to the name index
286 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
287 nameIdx.index(category.getId(), category.getTitle().decode('utf-8'))
289 def remove(self, category):
290 ObjectHolder.remove(self, category)
291 # remove category from the name index
292 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
293 nameIdx.unindex(category.getId())
294 Catalog.getIdx('categ_conf_sd').remove_category(category.getId())
296 def _newId( self ):
298 returns a new id for the category
299 the id must not already exist in the collection
301 id = ObjectHolder._newId( self )
302 while self.hasKey(id):
303 id = ObjectHolder._newId( self )
304 return id
306 def getRoot( self ):
307 root = DBMgr.getInstance().getDBConnection().root()
308 if not root.has_key("rootCategory"):
309 r = Category()
310 r.setName("Home")
311 self.add( r )
312 root["rootCategory"] = r
313 return root["rootCategory"]
315 def getDefaultConference( self ):
316 dconf = HelperMaKaCInfo.getMaKaCInfoInstance().getDefaultConference()
317 if dconf == None:
318 return HelperMaKaCInfo.getMaKaCInfoInstance().setDefaultConference(DefaultConference())
319 else:
320 return dconf
324 class Category(CommonObjectBase):
326 fossilizes(ICategoryFossil)
328 def __init__( self ):
330 self.id = ""
331 self.name = ""
332 self.description = ""
333 self.subcategories = {}
334 self.materials = {}
335 self.conferences = OOTreeSet()
336 self._numConferences = 0
337 self.owner = None
338 self._defaultStyle = { "simple_event":"","meeting":"" }
339 self._order = 0
340 self.__ac = AccessController(self)
341 self.__confCreationRestricted = 1
342 self.__confCreators = []
343 self._visibility = 999
344 self._statistics = {"events":None,"contributions":None,"resources":None,\
345 "updated":None}
346 self._icon=None
347 self.materials = {}
348 #self._materials = {}
349 #self.material ={}
350 self._tasksAllowed = False
351 self._tasks = {}
352 self._taskIdGenerator = 0
353 self._tasksPublic = True
354 self._tasksCommentPublic = True
355 self._tasksManagers = []
356 self._tasksCommentators = []
357 self._taskAccessList = []
358 self._timezone = ""
359 self.__materialGenerator = Counter()
360 self._notifyCreationList = ""
362 def __str__(self):
363 return "<Category %s@%s>" % (self.getId(), hex(id(self)))
365 def getAccessController(self):
366 return self.__ac
368 def updateFullyPublic( self ):
369 pass
371 def getNotifyCreationList( self ):
372 """ self._notifyCreationList is a string containing the list of
373 email addresses to send an email to when a new event is created"""
374 try:
375 return self._notifyCreationList
376 except:
377 self._notifyCreationList = ""
378 return self._notifyCreationList
380 def setNotifyCreationList( self, value ):
381 self._notifyCreationList = value
383 def getUniqueId( self ):
384 return "cat%s" % self.getId()
386 def setPaper( self, newPaper ):
387 if self.getPaper() != None:
388 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
389 self.paper=newPaper
390 self.paper.setOwner( self )
391 self.notifyModification()
393 def cleanCache( self ):
394 """ delete cache files of this category and its fathers
395 usually used when an object in the category has changed """
396 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
397 if minfo.isCacheActive():
398 for id in self.getCategoryPath():
399 cache = CategoryCache({"categId":id})
400 cache.cleanCache()
402 def clearCache( self ):
403 """ delete cache file of this category. usually used for
404 admin purposes """
405 cache = CategoryCache({"categId":self.getId()})
406 cache.cleanCache()
408 def clearConferenceCaches( self ):
409 """ delete cache files of all conferences in the category
410 usually used for admin purposes """
411 for conf in self.getConferenceList():
412 conf.cleanCache()
414 def removePaper( self ):
415 if self.paper is None:
416 return
417 self.paper.delete()
418 self.paper.setOwner(None)
419 self.paper = None
420 self.notifyModification()
422 def recoverPaper(self, p):
423 self.setPaper(p)
424 p.recover()
426 def getPaper( self ):
427 try:
428 if self.paper:
429 pass
430 except AttributeError:
431 self.paper = None
432 return self.paper
434 def setSlides( self, newSlides ):
435 if self.getSlides() != None:
436 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
437 self.slides=newSlides
438 self.slides.setOwner( self )
439 self.notifyModification()
441 def removeSlides( self ):
442 if self.slides is None:
443 return
444 self.slides.delete()
445 self.slides.setOwner( None )
446 self.slides= None
447 self.notifyModification()
449 def recoverSlides(self, s):
450 self.setSlides(s)
451 s.recover()
453 def getSlides( self ):
454 try:
455 if self.slides:
456 pass
457 except AttributeError:
458 self.slides = None
459 return self.slides
461 def setVideo( self, newVideo ):
462 if self.getVideo() != None:
463 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
464 self.video=newVideo
465 self.video.setOwner( self )
466 self.notifyModification()
468 def removeVideo( self ):
469 if self.getVideo() is None:
470 return
471 self.video.delete()
472 self.video.setOwner(None)
473 self.video = None
474 self.notifyModification()
476 def recoverVideo(self, v):
477 self.setVideo(v)
478 v.recover()
480 def getVideo( self ):
481 try:
482 if self.video:
483 pass
484 except AttributeError:
485 self.video = None
486 return self.video
488 def setPoster( self, newPoster ):
489 if self.getPoster() != None:
490 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
491 self.poster=newPoster
492 self.poster.setOwner( self )
493 self.notifyModification()
495 def removePoster( self ):
496 if self.getPoster() is None:
497 return
498 self.poster.delete()
499 self.poster.setOwner(None)
500 self.poster = None
501 self.notifyModification()
503 def recoverPoster(self, p):
504 self.setPoster(p)
505 p.recover()
507 def getPoster( self ):
508 try:
509 if self.poster:
510 pass
511 except AttributeError:
512 self.poster = None
513 return self.poster
515 def setMinutes( self, newMinutes ):
516 if self.getMinutes() != None:
517 raise MaKaCError( _("The Minutes for this conference has already been set"))
518 self.minutes=newMinutes
519 self.minutes.setOwner( self )
520 self.notifyModification()
522 def createMinutes( self ):
523 if self.getMinutes() != None:
524 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
525 self.minutes = Minutes()
526 self.minutes.setOwner( self )
527 self.notifyModification()
528 return self.minutes
530 def removeMinutes( self ):
531 if self.getMinutes() is None:
532 return
533 self.minutes.delete()
534 self.minutes.setOwner( None )
535 self.minutes = None
536 self.notifyModification()
538 def recoverMinutes(self, min):
539 self.removeMinutes() # To ensure that the current minutes are put in
540 # the trash can.
541 self.minutes = min
542 self.minutes.setOwner( self )
543 min.recover()
544 self.notifyModification()
545 return self.minutes
547 def getMinutes( self ):
548 #To be removed
549 try:
550 if self.minutes:
551 pass
552 except AttributeError, e:
553 self.minutes = None
554 return self.minutes
556 def addMaterial( self, newMat ):
557 try:
558 newMat.setId( str(self.__materialGenerator.newCount()) )
559 except:
560 self.__materialGenerator = Counter()
561 newMat.setId(self.__materialGenerator.newCount() )
562 newMat.setOwner( self )
563 self.materials[ newMat.getId() ] = newMat
564 self.notifyModification()
566 def removeMaterial( self, mat ):
567 if mat.getId() in self.materials.keys():
568 self.materials[mat.getId()].setOwner(None)
569 del self.materials[ mat.getId() ]
570 mat.delete()
571 self.notifyModification()
572 return "done: %s"%mat.getId()
573 elif mat.getId().lower() == 'minutes':
574 self.removeMinutes()
575 return "done: %s"%mat.getId()
576 elif mat.getId().lower() == 'paper':
577 self.removePaper()
578 return "done: %s"%mat.getId()
579 elif mat.getId().lower() == 'slides':
580 self.removeSlides()
581 return "done: %s"%mat.getId()
582 elif mat.getId().lower() == 'video':
583 self.removeVideo()
584 return "done: %s"%mat.getId()
585 elif mat.getId().lower() == 'poster':
586 self.removePoster()
587 return "done: %s"%mat.getId()
588 return "not done: %s"%mat.getId()
590 def recoverMaterial(self, recMat):
591 # Id must already be set in recMat.
592 recMat.setOwner( self )
593 self.materials[ recMat.getId() ] = recMat
594 recMat.recover()
595 self.notifyModification()
597 def getMaterialRegistry(self):
599 Return the correct material registry for this type
601 from MaKaC.webinterface.materialFactories import CategoryMFRegistry
602 return CategoryMFRegistry
604 def getMaterialById( self, matId ):
605 if matId.lower() == 'paper':
606 return self.getPaper()
607 elif matId.lower() == 'slides':
608 return self.getSlides()
609 elif matId.lower() == 'video':
610 return self.getVideo()
611 elif matId.lower() == 'poster':
612 return self.getPoster()
613 elif matId.lower() == 'minutes':
614 return self.getMinutes()
615 elif self.materials.has_key(matId):
616 return self.materials[ matId ]
617 return None
619 def getMaterialList( self ):
620 try:
621 return self.materials.values()
622 except:
623 self.materials={}
624 return self.materials.values()
626 def getAllMaterialList( self ):
627 l = self.getMaterialList()
628 if self.getPaper():
629 l.append( self.getPaper() )
630 if self.getSlides():
631 l.append( self.getSlides() )
632 if self.getVideo():
633 l.append( self.getVideo() )
634 if self.getPoster():
635 l.append( self.getPoster() )
636 if self.getMinutes():
637 l.append( self.getMinutes() )
638 return l
640 def getTaskList(self):
641 try :
642 return self._tasks.values()
643 except :
644 self._tasks = {}
645 return self._tasks.values()
647 def getTitle(self):
648 return self.name
650 def getTasks(self):
651 try :
652 return self._tasks
653 except :
654 self._tasks = {}
655 return self._tasks
657 def getTask(self, taskId):
658 return self.getTasks().get(taskId,None)
660 def _getTasksAllowed(self):
661 try :
662 return self._tasksAllowed
663 except :
664 self._tasksAllowed = False
665 return self._tasksAllowed
667 def tasksAllowed(self):
668 if self.hasSubcategories():
669 return False
670 return self._getTasksAllowed()
672 def setTasksAllowed(self):
673 if self.hasSubcategories() :
674 return False
675 self._getTasksAllowed()
676 self._tasksAllowed = True
677 self.notifyModification()
678 return True
680 def setTasksForbidden(self):
681 if len(self.getTaskList()) > 0 :
682 return False
683 self._getTasksAllowed()
684 self._tasksAllowed = False
685 self.notifyModification()
686 return False
688 def _getNewTaskId(self):
689 try :
690 if self._taskIdGenerator :
691 pass
692 except :
693 self._taskIdGenerator = 0
694 self._taskIdGenerator = self._taskIdGenerator + 1
695 return self._taskIdGenerator
697 def newTask(self, user):
698 if user is None :
699 return None
700 newTask = task.Task(self, self._getNewTaskId(), user)
701 self.getTasks()["%s"%newTask.getId()] = newTask
702 self.notifyModification()
703 return newTask
705 def tasksPublic(self):
706 try :
707 return self._tasksPublic
708 except :
709 self._tasksPublic = True
710 return self._tasksPublic
712 def setTasksPublic(self):
713 self.tasksPublic()
714 self._tasksPublic = True
716 def setTasksPrivate(self):
717 self.tasksPublic()
718 self._tasksPublic = False
720 def tasksCommentPublic(self):
721 try :
722 return self._tasksCommentPublic
723 except :
724 self._tasksCommentPublic = True
725 return self._tasksCommentPublic
727 def setTasksCommentPublic(self):
728 self.tasksCommentPublic()
729 self._tasksCommentPublic = True
731 def setTasksCommentPrivate(self):
732 self.tasksCommentPublic()
733 self._tasksCommentPublic = False
735 def getTasksManagerList(self):
736 try :
737 return self._tasksManagers
738 except :
739 self._tasksManagers = []
740 self._p_changed = 1
741 return self._tasksManagers
743 def getTasksManager(self, index):
744 length = len(self.getTasksManagerList())
745 if index < 0 or index >= length :
746 return None
747 return self._tasksManagers[index]
749 def addTasksManager(self,user):
750 if user is None :
751 return False
752 self.getTasksManagerList().append(user)
753 self._p_changed = 1
754 return True
756 def removeTasksManager(self, index):
757 length = len(self.getTasksManagerList())
758 if index < 0 or index >= length :
759 return False
760 del self.getTasksManagerList()[index]
761 self._p_changed = 1
762 return True
764 def getTasksCommentatorList(self):
765 try :
766 return self._tasksCommentators
767 except :
768 self._tasksCommentators = []
769 self._p_changed = 1
770 return self._tasksCommentators
772 def getTasksCommentator(self, index):
773 length = len(self.getTasksCommentatorList())
774 if index < 0 or index >= length :
775 return None
776 return self._tasksCommentators[index]
778 def addTasksCommentator(self,user):
779 if user is None :
780 return False
781 self.getTasksCommentatorList().append(user)
782 self._p_changed = 1
783 return True
785 def removeTasksCommentator(self, index):
786 length = len(self.getTasksCommentatorList())
787 if index < 0 or index >= length :
788 return False
789 del self._tasksCommentators[index]
790 self._p_changed = 1
791 return True
794 def getTasksAccessList(self):
795 try :
796 return self._tasksAccessList
797 except :
798 self._tasksAccessList = []
799 self._p_changed = 1
800 return self._tasksAccessList
802 def getTasksAccessPerson(self, index):
803 length = len(self.getTasksAccessList())
804 if index < 0 or index >= length :
805 return None
806 return self._tasksAccessList[index]
808 def addTasksAccessPerson(self,user):
809 if user is None :
810 return False
811 self.getTasksAccessList().append(user)
812 self._p_changed = 1
813 return True
815 def removeTasksAccessPerson(self, index):
816 length = len(self.getTasksAccessList())
817 if index < 0 or index >= length :
818 return False
819 del self.getTasksAccessList()[index]
820 self._p_changed = 1
821 return True
823 def hasSubcategories(self):
824 return len(self.subcategories.values()) > 0
826 def getVisibility ( self ):
828 Returns category visibility, considering that it can be
829 restricted by parent categories
831 owner = self.getOwner()
832 visibility = int(self._visibility)
834 # visibility can be restricted by parent categories
835 if owner:
836 return max(0, min(visibility, owner.getVisibility() + 1))
837 else:
838 return visibility
840 def setVisibility( self, visibility=999 ):
841 self._visibility = int(visibility)
842 self._reindex()
844 def _reindex( self ):
845 catIdx = indexes.IndexesHolder().getIndex('category')
846 catIdx.reindexCateg(self)
847 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
848 catDateIdx.reindexCateg(self)
849 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
850 catDateAllIdx.reindexCateg(self)
852 def isRoot( self ):
853 #to be improved
854 return self.owner == None
856 def getDefaultStyle( self, type ):
857 try:
858 return self._defaultStyle[type]
859 except:
860 return ""
862 def setDefaultStyle( self, type, style, subcatsStyle=False ):
863 try:
864 self._defaultStyle[type] = style
865 except:
866 self._defaultStyle = { "simple_event":"","meeting":"" }
867 self._defaultStyle[type] = style
868 self.notifyModification()
869 #raise str(subcatsStyle)
870 if subcatsStyle:
872 categ=self.getSubCategoryList()
874 for cat in categ:
875 cat.setDefaultStyle(type, style, subcatsStyle )
877 ##################################
878 # Fermi timezone awareness #
879 ##################################
880 def getTimezone(self):
881 try:
882 if self._timezone not in all_timezones:
883 self.setTimezone('UTC')
884 return self._timezone
885 except:
886 self.setTimezone('UTC')
887 return 'UTC'
889 def setTimezone(self,tz):
890 self._timezone = tz
893 def changeConfTimezones(self, tz):
894 for conference in self.getConferenceList():
895 conference.moveToTimezone(tz)
897 ##################################
898 # Fermi timezone awareness(end) #
899 ##################################
901 def getOrder( self ):
902 try:
903 return self._order
904 except:
905 self._order = 0
906 return 0
908 def setOrder( self, order ):
909 self._order = order
911 def getId( self ):
912 return self.id
914 def setId( self, newId ):
915 self.id = str( newId.strip() )
917 def getLocator( self ):
918 """Gives back (Locator) a globaly unique identification encapsulated
919 in a Locator object for the category instance """
920 d = Locator()
921 d["categId"] = self.getId()
922 return d
924 def getCategory(self):
925 return self
927 def getOwner( self ):
928 return self.owner
930 def setOwner( self, newOwner ):
931 if self.getOwner() != None and newOwner != None and self.getOwner() != newOwner:
932 self.move( newOwner )
933 else:
934 self.owner = newOwner
936 def getCategoryPath(self):
937 if self.isRoot():
938 return [self.getId()]
939 else:
940 l = self.getOwner().getCategoryPath()
941 l.append(self.getId())
942 return l
944 def getCategoryPathTitles(self):
945 # Breadcrumbs
946 breadcrumbs = []
947 cat = self
948 while cat:
949 breadcrumbs.insert(0, cat.getTitle())
950 cat = cat.getOwner()
951 return breadcrumbs
953 def delete( self, deleteConferences=0 ):
954 """removes completely a category (and all its sub-items) from the
955 system"""
957 oldOwner = self.getOwner()
959 if self.isRoot():
960 raise MaKaCError( _("Root category cannot be deleted"), _("Category"))
961 if not deleteConferences:
962 if self.getNumConferences()>0:
963 raise MaKaCError( _("This category still contains some conferences, please remove them first"), _("Category"))
964 self.cleanCache()
965 for subcateg in self.getSubCategoryList():
966 subcateg.delete( deleteConferences )
967 for conference in self.getConferenceList():
968 self.removeConference( conference, delete = True )
969 self.getOwner()._removeSubCategory( self )
970 CategoryManager().remove( self )
971 TrashCanManager().add(self)
973 self._notify('deleted', oldOwner)
975 return
977 def move( self, newOwner ):
978 oldOwner = self.getOwner()
979 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
980 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
982 catDateIdx.unindexCateg(self)
983 catDateAllIdx.unindexCateg(self)
985 self.getOwner()._removeSubCategory( self )
986 newOwner._addSubCategory( self )
987 self._reindex()
988 catDateIdx.indexCateg(self)
989 catDateAllIdx.indexCateg(self)
991 self._notify('moved', oldOwner, newOwner)
993 def getName( self ):
994 return self.name
996 def setName( self, newName ):
997 oldName = self.name
998 self.name = newName.strip()
1000 # Reindex when name changes
1001 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
1002 nameIdx.unindex(self.getId())
1003 nameIdx.index(self.getId(), self.getTitle().decode('utf-8'))
1005 self._notify('categoryTitleChanged', oldName, newName)
1007 self.cleanCache()
1009 def getDescription( self ):
1010 return self.description
1012 def setDescription( self, newDesc ):
1013 self.description = newDesc.strip()
1014 self.cleanCache()
1016 def moveConference(self, conf, toCateg):
1018 Moves a conference from this category to another one
1020 self.removeConference( conf )
1021 toCateg._addConference( conf )
1022 conf._notify('moved', self, toCateg)
1024 def _addSubCategory( self, newSc ):
1025 #categories can only contain either conferences either other categories
1026 # but can never contain both. For the moment an exception is raised
1027 # but this could be replaced by the following policy: if a
1028 # sub-category is to be added to a category already containing
1029 # conferences then the conferes are moved into the new sub-category
1030 # and it is added to target category.
1031 #first, check that the category is registered if not raise an exception
1032 if len(self.conferences)>0:
1033 for conf in self.getConferenceList():
1034 self.moveConference(conf, newSc)
1036 if len(self.conferences)>0:
1037 raise MaKaCError( _("Cannot add subcategory: the current category already contains events"), _("Category"))
1038 newSc.setOwner( self )
1039 self.subcategories[ newSc.getId() ] = newSc
1040 self._incNumConfs(newSc.getNumConferences())
1041 self.cleanCache()
1043 def _removeSubCategory( self, sc ):
1044 """if the given subcategory belongs to the current category it removes
1045 it from the subcategories list (don't use this method, use delete
1046 instead)
1048 if sc in self.getSubCategoryList():
1049 self._decNumConfs(sc.getNumConferences())
1050 del self.subcategories[ sc.getId() ]
1051 sc.setOwner( None )
1052 self.cleanCache()
1054 def newSubCategory(self, protection):
1055 cm = CategoryManager()
1056 sc = Category()
1057 cm.add( sc )
1059 # set the protection
1060 sc.setProtection(protection)
1062 Catalog.getIdx('categ_conf_sd').add_category(sc.getId())
1063 sc._notify('created', self)
1065 self._addSubCategory( sc )
1066 self.cleanCache()
1068 return sc
1070 def _incNumConfs(self, num=1):
1071 """Increases the number of conferences for the current category in a given number.
1072 WARNING: Only Categories must use this method!!!"""
1073 self._numConferences = self.getNumConferences()
1074 self._numConferences+=num
1075 if self.getOwner() is not None:
1076 self.getOwner()._incNumConfs(num)
1078 def _decNumConfs(self, num=1):
1079 """Decreases the number of conferences for the current category in a given number.
1080 WARNING: Only Categories must use this method!!!"""
1081 self._numConferences = self.getNumConferences()
1082 self._numConferences-=num
1083 if self.getOwner() is not None:
1084 self.getOwner()._decNumConfs(num)
1086 def _addConference( self, newConf ):
1087 if len(self.subcategories)>0:
1088 raise MaKaCError( _("Cannot add event: the current category already contains some sub-categories"), _("Category"))
1089 if newConf.getId() == "":
1090 raise MaKaCError( _("Cannot add to a category an event which is not registered"), _("Category"))
1091 self.conferences.insert(newConf)
1092 newConf.addOwner(self)
1093 self._incNumConfs(1)
1094 self.indexConf(newConf)
1095 self.cleanCache()
1097 def getAccessKey(self):
1098 return ""
1100 def getModifKey(self):
1101 return ""
1103 def indexConf( self, conf ):
1104 # Specific for category changes, calls Conference.indexConf()
1105 # (date-related indexes)
1106 catIdx = indexes.IndexesHolder().getIndex('category')
1107 catIdx.indexConf(conf)
1108 conf.indexConf()
1110 def unindexConf( self, conf ):
1111 catIdx = indexes.IndexesHolder().getIndex('category')
1112 catIdx.unindexConf(conf)
1113 conf.unindexConf()
1115 def newConference( self, creator, id="", creationDate=None, modificationDate=None ):
1116 conf = Conference( creator, id, creationDate, modificationDate )
1117 ConferenceHolder().add( conf )
1118 self._addConference( conf )
1120 conf._notify('created', self)
1122 return conf
1124 def removeConference( self, conf, notify=True, delete = False ):
1125 if not (conf in self.conferences):
1126 return
1128 self.unindexConf( conf )
1130 self.conferences.remove(conf)
1131 if delete:
1132 conf.delete()
1133 conf.removeOwner( self, notify )
1134 self._decNumConfs(1)
1135 self.cleanCache()
1137 def getSubCategoryList( self ):
1138 subcategs = self.subcategories.values()
1139 cl = []
1140 for categ in subcategs:
1141 cl.append("%04s%s-%s" % (categ.getOrder(),categ.getName().replace("-",""),categ.getId()))
1142 cl.sort()
1143 res = []
1144 for c in cl:
1145 id = c.split("-")[1]
1146 res.append(self.subcategories[id])
1147 return res
1149 def iteritems(self, *args):
1150 return self.conferences.iteritems(*args)
1152 def itervalues(self, *args):
1153 return self.conferences.itervalues(*args)
1155 def getConferenceList( self, sortType=1 ):
1156 """returns the list of conferences included in the current category.
1157 Thanks to the used structure the list is sorted by date.
1158 We can choose other sorting types:
1160 sortType=1--> By date
1161 sortType=2--> Alphabetically
1162 sortType=3--> Alphabetically - Reversed
1165 res = sorted(self.conferences, cmp=Conference._cmpByDate)
1167 if sortType==2:
1168 res.sort(Conference._cmpTitle)
1169 elif sortType==3:
1170 res.sort(Conference._cmpTitle)
1171 res = reversed(res)
1172 return res
1174 def iterConferences( self):
1175 """returns the iterator for conferences.
1177 return self.conferences
1179 def iterAllConferences( self):
1180 """returns the iterator for conferences in all subcategories.
1182 for conf in self.conferences:
1183 yield conf
1185 for subcateg in self.subcategories.itervalues():
1186 for conf in subcateg.iterAllConferences():
1187 yield conf
1189 def getAllConferenceList( self ):
1190 """returns the list of all conferences included in the current category
1191 and in all its subcategories"""
1192 res = self.getConferenceList()
1193 subcategs = self.getSubCategoryList()
1194 if subcategs != []:
1195 for subcateg in subcategs:
1196 res.extend(subcateg.getAllConferenceList())
1197 return res
1199 def getRelativeEvent(self, which, conf=None):
1200 index = Catalog.getIdx('categ_conf_sd').getCategory(self.getId())
1201 if which == 'first':
1202 return list(index[index.minKey()])[0]
1203 elif which == 'last':
1204 return list(index[index.maxKey()])[-1]
1205 elif which in ('next', 'prev'):
1206 categIter = index.itervalues()
1207 if conf:
1208 prev = None
1209 for c in categIter:
1210 if c == conf:
1211 break
1212 prev = c
1213 nextEvt = next(categIter, None)
1214 if which == 'next':
1215 return nextEvt
1216 else:
1217 return prev
1218 else:
1219 raise AttributeError("'conf' parameter missing")
1220 else:
1221 raise AttributeError("Unknown argument value: '%s'" % which)
1223 def _setNumConferences(self):
1224 self._numConferences = 0
1225 if self.conferences:
1226 self._incNumConfs(len(self.conferences))
1227 else:
1228 for sc in self.getSubCategoryList():
1229 self._incNumConfs(sc.getNumConferences())
1231 def getNumConferences( self ):
1232 """returns the total number of conferences contained in the current
1233 category and all its sub-categories (if any)"""
1234 #this new approach will speed up considerably the counting of category
1235 # conferences. However, it will give non accurate results for
1236 # conferences within many categories (a conference will be counted
1237 # twice in parent categories).
1238 # Besides this approach will generate much more conflict errors. This
1239 # can be reduced by simply isolating the counter in a separate object.
1240 try:
1241 if self._numConferences:
1242 pass
1243 except AttributeError:
1244 self._setNumConferences()
1245 return self._numConferences
1247 def _getRepository( self ):
1248 dbRoot = DBMgr.getInstance().getDBConnection().root()
1249 try:
1250 fr = dbRoot["local_repositories"]["main"]
1251 except KeyError, e:
1252 fr = fileRepository.MaterialLocalRepository()
1253 dbRoot["local_repositories"] = OOBTree()
1254 dbRoot["local_repositories"]["main"] = fr
1255 return fr
1257 def removeResource( self, res ):
1258 pass
1260 def setIcon( self, iconFile ):
1261 iconFile.setOwner( self )
1262 iconFile.setId( "icon" )
1263 iconFile.archive( self._getRepository() )
1264 iconFile.setProtection( -1 )
1265 if self.getIcon() != None:
1266 self._icon.delete()
1267 self._icon = iconFile
1268 self.notifyModification()
1270 def getIcon( self ):
1271 try:
1272 if self._icon:
1273 pass
1274 except AttributeError, e:
1275 self._icon=None
1276 return self._icon
1278 def getIconURL( self ):
1279 if self.getIcon() is None:
1280 return ""
1281 return self._icon.getURL()
1283 def removeIcon(self):
1284 if self.getIcon() is None:
1285 return
1286 self._icon.delete()
1287 self._icon = None
1288 self.notifyModification()
1290 def recoverIcon(self, icon):
1291 icon.setOwner(self)
1292 if self.getIcon() != None:
1293 self._icon.delete()
1294 self._icon = icon
1295 icon.recover()
1296 self.notifyModification()
1298 def getManagerList( self ):
1299 return self.__ac.getModifierList()
1301 def grantModification( self, prin ):
1302 self.__ac.grantModification( prin )
1303 if isinstance(prin, MaKaC.user.Avatar):
1304 prin.linkTo(self, "manager")
1305 self.cleanCache()
1307 def revokeModification( self, prin ):
1308 self.__ac.revokeModification( prin )
1309 if isinstance(prin, MaKaC.user.Avatar):
1310 prin.unlinkTo(self, "manager")
1311 self.cleanCache()
1313 def canModify( self, aw ):
1314 return self.canUserModify( aw.getUser() )
1316 def canUserModify( self, av ):
1317 inherited = 0
1318 if self.getOwner() != None:
1319 inherited = self.getOwner().canUserModify( av )
1320 return inherited or self.__ac.canModify( av )
1323 def getAllowedToAccessList( self ):
1324 return self.__ac.getAccessList()
1326 def canKeyAccess( self, aw ):
1327 # Categories don't allow access keys
1328 return False
1330 def canIPAccess( self, ip ):
1331 if not self.__ac.canIPAccess( ip ):
1332 return False
1333 if self.getOwner():
1334 return self.getOwner().canIPAccess(ip)
1335 return True
1337 def isProtected( self ):
1338 return self.__ac.isProtected()
1340 def getAccessProtectionLevel( self ):
1341 return self.__ac.getAccessProtectionLevel()
1343 def isItselfProtected( self ):
1344 return self.__ac.isItselfProtected()
1346 def hasAnyProtection( self ):
1347 if self.__ac.isProtected() or len(self.getDomainList())>0:
1348 return True
1349 if self.getAccessProtectionLevel() == -1: #PUBLIC
1350 return False
1351 if self.getOwner() is not None:
1352 return self.getOwner().hasAnyProtection()
1353 return False
1355 def setProtection( self, private ):
1357 Allows to change the category's access protection
1360 oldProtection = 1 if self.isProtected() else -1
1362 self.__ac.setProtection( private )
1363 self._notify('protectionChanged', oldProtection, private)
1364 self.cleanCache()
1366 def hasProtectedOwner( self ):
1367 return self.__ac._getFatherProtection()
1369 def isAllowedToAccess( self, av ):
1370 """Says whether an avatar can access a category independently of it is
1371 or not protected or domain filtered
1373 if self.__ac.canUserAccess( av ) or self.canUserModify( av ):
1374 return True
1375 if not self.isItselfProtected() and self.getOwner():
1376 return self.getOwner().isAllowedToAccess( av )
1378 def canView(self,aw):
1379 if self.canAccess( aw ):
1380 return True
1381 for conf in self.getConferenceList():
1382 if conf.canView( aw ):
1383 return True
1384 for subcateg in self.getSubCategoryList():
1385 if subcateg.canView( aw ):
1386 return True
1387 return False
1389 def canAccess( self, aw ):
1390 if not self.hasAnyProtection():
1391 return True
1392 if not self.isProtected():
1393 #domain checking only triggered if the category is PUBLIC
1394 return self.canIPAccess( aw.getIP() ) or \
1395 self.isAllowedToCreateConference(aw.getUser()) or \
1396 self.isAllowedToAccess(aw.getUser())
1397 return self.isAllowedToCreateConference(aw.getUser()) or \
1398 self.isAllowedToAccess(aw.getUser())
1400 def grantAccess( self, prin ):
1401 self.__ac.grantAccess( prin )
1402 if isinstance(prin, MaKaC.user.Avatar):
1403 prin.linkTo(self, "access")
1405 def revokeAccess( self, prin ):
1406 self.__ac.revokeAccess( prin )
1407 if isinstance(prin, MaKaC.user.Avatar):
1408 prin.unlinkTo(self, "access")
1410 def isConferenceCreationRestricted( self ):
1411 return self.__confCreationRestricted
1413 def restrictConferenceCreation( self ):
1414 self.__confCreationRestricted = 1
1416 def allowConferenceCreation( self ):
1417 self.__confCreationRestricted = 0
1419 def grantConferenceCreation( self, prin ):
1420 if prin not in self.__confCreators:
1421 self.__confCreators.append( prin )
1422 if isinstance(prin, MaKaC.user.Avatar):
1423 prin.linkTo(self, "creator")
1424 self._p_changed = 1
1426 def revokeConferenceCreation( self, prin ):
1427 if prin in self.__confCreators:
1428 self.__confCreators.remove( prin )
1429 if isinstance(prin, MaKaC.user.Avatar):
1430 prin.unlinkTo(self, "creator")
1431 self._p_changed = 1
1433 def getConferenceCreatorList( self ):
1434 return self.__confCreators
1436 def isAllowedToCreateConference( self, av ):
1438 if self.canUserModify( av ):
1439 return 1
1441 # Avatar is directly in the list
1442 if av in self.__confCreators:
1443 return 1
1445 # Otherwise, if it is a member of one of the groups in the list...
1446 for group in self.__confCreators:
1447 if isinstance(group, MaKaC.user.Group):
1448 if group.containsUser(av):
1449 return 1
1450 else:
1451 pass
1452 return 0
1454 def canCreateConference( self, av ):
1455 if not self.isConferenceCreationRestricted():
1456 return 1
1457 return self.isAllowedToCreateConference( av )
1459 def requireDomain( self, dom ):
1460 self.__ac.requireDomain( dom )
1461 self._notify('accessDomainAdded', dom)
1463 def freeDomain( self, dom ):
1464 self.__ac.freeDomain( dom )
1465 self._notify('accessDomainRemoved', dom)
1467 def getDomainList( self ):
1468 return self.__ac.getRequiredDomainList()
1470 def getStatistics( self ):
1471 try:
1472 if self._statistics:
1473 pass
1474 except AttributeError, e:
1475 self._statistics = {}
1476 return self._statistics
1478 def notifyModification( self ):
1479 """Method called to notify the current category has been modified.
1481 self._notify('infoChanged')
1482 self.cleanCache()
1483 self._p_changed=1
1486 class CustomLocation(Persistent):
1488 def __init__(self, **locationData):
1489 self.name = ""
1490 self.address = ""
1491 self.room = ""
1493 def setValues(self, data):
1494 self.setName(data.get("name",""))
1495 self.setAddress(data.get("address",""))
1496 self.setRoom(data.get("room",""))
1498 def getValues(self):
1499 d={}
1500 d["name"]=self.getName()
1501 d["address"]=self.getAddress()
1502 d["room"]=self.getRoom()
1503 return d
1505 def clone(self):
1506 newCL=CustomLocation()
1507 newCL.setValues(self.getValues())
1508 return newCL
1510 def setName(self, newName):
1511 self.name = newName
1513 def getName(self):
1514 return self.name
1516 def setAddress(self, newAddress):
1517 self.address = newAddress
1519 def getAddress(self):
1520 return self.address
1522 def setRoom(self, newRoom):
1523 self.room = newRoom
1525 def getRoom(self):
1526 return self.room
1529 class CustomRoom(Persistent):
1531 def __init__( self ):
1532 self.name = ""
1534 def setValues(self, data):
1535 self.setName(data.get("name",""))
1536 self.setFullName(data.get("fullName"))
1538 def getValues(self):
1539 d={}
1540 d["name"]=self.getName()
1541 d["fullName"]=self.getFullName()
1542 return d
1544 def getId(self):
1545 return "Custom"
1547 def clone(self):
1548 newCR=CustomRoom()
1549 newCR.setValues(self.getValues())
1550 return newCR
1552 def setName( self, newName ):
1553 self.name = newName.strip()
1555 def getName( self ):
1556 return self.name
1558 def retrieveFullName(self, location):
1559 if not location:
1560 return
1561 room = CrossLocationQueries.getRooms(roomName=self.name, location=location)
1562 self.fullName = room.getFullName() if room else None
1564 def setFullName(self, newFullName):
1565 self.fullName = newFullName
1567 def getFullName(self):
1568 if not hasattr(self, 'fullName'):
1569 self.fullName = None
1570 return self.fullName
1573 class ConferenceParticipation(Persistent, Fossilizable, Observable):
1575 fossilizes(IConferenceParticipationFossil, IConferenceParticipationMinimalFossil)
1577 def __init__(self):
1578 self._firstName=""
1579 self._surName=""
1580 self._email=""
1581 self._affiliation=""
1582 self._address=""
1583 self._phone=""
1584 self._title=""
1585 self._fax=""
1587 def _notifyModification( self ):
1588 pass
1590 def setValues(self, data):
1591 self.setFirstName(data.get("firstName", ""))
1592 self.setFamilyName(data.get("familyName",""))
1593 self.setAffiliation(data.get("affilation",""))
1594 self.setAddress(data.get("address",""))
1595 self.setEmail(data.get("email",""))
1596 self.setFax(data.get("fax",""))
1597 self.setTitle(data.get("title",""))
1598 self.setPhone(data.get("phone",""))
1599 self._notifyModification()
1601 def getValues(self):
1602 data={}
1603 data["firstName"]=self.getFirstName()
1604 data["familyName"]=self.getFamilyName()
1605 data["affilation"]=self.getAffiliation()
1606 data["address"]=self.getAddress()
1607 data["email"]=self.getEmail()
1608 data["fax"]=self.getFax()
1609 data["title"]=self.getTitle()
1610 data["phone"]=self.getPhone()
1611 return data
1613 def setId(self, newId):
1614 self._id = newId
1616 def getId( self ):
1617 return self._id
1619 def setDataFromAvatar(self,av):
1620 # av is an Avatar object.
1621 if av is None:
1622 return
1623 self.setFirstName(av.getName())
1624 self.setFamilyName(av.getSurName())
1625 self.setEmail(av.getEmail())
1626 self.setAffiliation(av.getOrganisation())
1627 self.setAddress(av.getAddress())
1628 self.setPhone(av.getTelephone())
1629 self.setTitle(av.getTitle())
1630 self.setFax(av.getFax())
1631 self._notifyModification()
1633 def setDataFromOtherCP(self,cp):
1634 # cp is a ConferenceParticipation object.
1635 if cp is None:
1636 return
1637 self.setFirstName(cp.getFirstName())
1638 self.setFamilyName(cp.getFamilyName())
1639 self.setEmail(cp.getEmail())
1640 self.setAffiliation(cp.getAffiliation())
1641 self.setAddress(cp.getAddress())
1642 self.setPhone(cp.getPhone())
1643 self.setTitle(cp.getTitle())
1644 self.setFax(cp.getFax())
1645 self._notifyModification()
1647 def delete( self ):
1648 TrashCanManager().add(self)
1650 def recover(self):
1651 TrashCanManager().remove(self)
1653 @Updates (['MaKaC.conference.ConferenceParticipation',
1654 'MaKaC.conference.SessionChair',
1655 'MaKaC.conference.SlotChair'], 'firstName')
1656 def setFirstName(self,newName):
1657 tmp=newName.strip()
1658 if tmp==self._firstName:
1659 return
1660 self._firstName=tmp
1661 self._notifyModification()
1663 def getFirstName( self ):
1664 return self._firstName
1666 @Updates (['MaKaC.conference.ConferenceParticipation',
1667 'MaKaC.conference.SessionChair',
1668 'MaKaC.conference.SlotChair'], 'familyName')
1669 def setFamilyName(self,newName):
1670 tmp=newName.strip()
1671 if tmp==self._surName:
1672 return
1673 self._surName=tmp
1674 self._notifyModification()
1676 def getFamilyName( self ):
1677 return self._surName
1679 @Updates (['MaKaC.conference.ConferenceParticipation',
1680 'MaKaC.conference.SessionChair',
1681 'MaKaC.conference.SlotChair'], 'email')
1682 def setEmail(self,newMail):
1683 tmp=newMail.strip()
1684 if tmp==self._email:
1685 return
1686 self._email=newMail.strip()
1687 self._notifyModification()
1689 def getEmail( self ):
1690 return self._email
1692 @Updates (['MaKaC.conference.ConferenceParticipation',
1693 'MaKaC.conference.SessionChair',
1694 'MaKaC.conference.SlotChair'], 'affiliation')
1695 def setAffiliation(self,newAffil):
1696 self._affiliation=newAffil.strip()
1697 self._notifyModification()
1699 def getAffiliation(self):
1700 return self._affiliation
1702 @Updates (['MaKaC.conference.ConferenceParticipation',
1703 'MaKaC.conference.SessionChair',
1704 'MaKaC.conference.SlotChair'], 'address')
1705 def setAddress(self,newAddr):
1706 self._address=newAddr.strip()
1707 self._notifyModification()
1709 def getAddress(self):
1710 return self._address
1712 @Updates (['MaKaC.conference.ConferenceParticipation',
1713 'MaKaC.conference.SessionChair',
1714 'MaKaC.conference.SlotChair'], 'phone')
1715 def setPhone(self,newPhone):
1716 self._phone=newPhone.strip()
1717 self._notifyModification()
1719 def getPhone(self):
1720 return self._phone
1722 @Updates (['MaKaC.conference.ConferenceParticipation',
1723 'MaKaC.conference.SessionChair',
1724 'MaKaC.conference.SlotChair'], 'title')
1725 def setTitle(self,newTitle):
1726 self._title=newTitle.strip()
1727 self._notifyModification()
1729 def getTitle(self):
1730 return self._title
1732 @Updates (['MaKaC.conference.ConferenceParticipation',
1733 'MaKaC.conference.SessionChair',
1734 'MaKaC.conference.SlotChair'], 'fax')
1735 def setFax(self,newFax):
1736 self._fax=newFax.strip()
1737 self._notifyModification()
1739 def getFax(self):
1740 return self._fax
1742 def getFullName( self ):
1743 res = self.getFamilyName()
1744 if self.getFirstName() != "":
1745 if res.strip() != "":
1746 res = "%s, %s"%( res, self.getFirstName() )
1747 else:
1748 res = self.getFirstName()
1749 if self.getTitle() != "":
1750 res = "%s %s"%( self.getTitle(), res )
1751 return res
1753 def getFullNameNoTitle( self ):
1754 res = self.getFamilyName()
1755 if self.getFirstName() != "":
1756 if res.strip() != "":
1757 res = "%s, %s"%( res, self.getFirstName() )
1758 else:
1759 res = self.getFirstName()
1760 return res
1762 def getDirectFullName( self ):
1763 res = "%s %s"%( self.getFirstName(), self.getFamilyName() )
1764 res=res.strip()
1765 if self.getTitle() != "":
1766 res = "%s %s"%( self.getTitle(), res )
1767 return res
1769 def getAbrName(self):
1770 res = self.getFamilyName()
1771 if self.getFirstName() != "":
1772 if res != "":
1773 res = "%s, "%res
1774 res = "%s%s."%(res, self.getFirstName()[0].upper())
1775 return res
1777 def _cmpFamilyName( cp1, cp2 ):
1778 o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName())
1779 o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName())
1780 o1=o1.lower().strip()
1781 o2=o2.lower().strip()
1782 return cmp( o1, o2 )
1783 _cmpFamilyName=staticmethod(_cmpFamilyName)
1786 class ConferenceChair(ConferenceParticipation, Fossilizable):
1788 fossilizes(IConferenceParticipationFossil)
1790 def __init__(self):
1791 self._conf=None
1792 self._id=""
1793 ConferenceParticipation.__init__(self)
1795 def _notifyModification( self ):
1796 if self._conf != None:
1797 self._conf.notifyModification()
1799 def clone(self):
1800 newCC=ConferenceChair()
1801 newCC.setValues(self.getValues())
1802 return newCC
1804 def getConference(self):
1805 return self._conf
1807 def getId(self):
1808 return self._id
1810 def includeInConference(self,conf,id):
1811 if self.getConference()==conf and self.getId()==id.strip():
1812 return
1813 self._conf=conf
1814 self._id=id
1816 def delete( self ):
1817 self._conf=None
1818 ConferenceParticipation.delete(self)
1820 def getLocator(self):
1821 if self.getConference() is None:
1822 return None
1823 loc=self.getConference().getLocator()
1824 loc["chairId"]=self.getId()
1825 return loc
1827 class SubmitterIndex(Persistent):
1828 """Index for contribution submitters.
1830 This class allows to index users with submission privileges over the
1831 conference contributions so the owner can answer optimally to the query
1832 if a user has any submission privilege over any contribution
1833 of the conference.
1834 It is implemented by simply using a BTree where the Avatar id is used
1835 as key (because it is unique and non variable) and a list of
1836 contributions over which he has submission privileges is kept as values.
1837 It is the responsability of the index owner (conference contributions)
1838 to keep it up-to-date i.e. notify conference sumitters additions and
1839 removals.
1842 def __init__( self ):
1843 self._idx = OOBTree()
1844 self._idxEmail = OOBTree()
1846 def _getIdxEmail(self):
1847 try:
1848 return self._idxEmail
1849 except:
1850 self._idxEmail = OOBTree()
1851 return self._idxEmail
1853 def getContributions(self,av):
1854 """Gives a list with the contributions over which a user has
1855 coordination privileges
1857 if av == None:
1858 return []
1859 ret = self._idx.get(av.getId(),[])
1860 if not ret:
1861 self._moveEmailtoId(av)
1862 ret = self._idx.get(av.getId(),[])
1863 return ret
1865 def index(self,av,contrib):
1866 """Registers in the index a submitter of a contribution.
1868 if av==None or contrib==None:
1869 return
1870 if not self._idx.has_key(av.getId()):
1871 l=[]
1872 self._idx[av.getId()]=l
1873 else:
1874 l=self._idx[av.getId()]
1875 if contrib not in l:
1876 l.append(contrib)
1877 self._idx[av.getId()]=l
1879 def indexEmail(self, email, contrib):
1880 if not email or not contrib:
1881 return
1882 if not self._getIdxEmail().has_key(email):
1883 l = [contrib]
1884 self._getIdxEmail()[email] = l
1885 else:
1886 l = self._getIdxEmail()[email]
1887 if not contrib in l:
1888 l.append(contrib)
1889 self._getIdxEmail()[email] = l
1892 def unindex(self,av,contrib):
1893 if av==None or contrib==None:
1894 return
1895 l=self._idx.get(av.getId(),[])
1896 if contrib in l:
1897 l.remove(contrib)
1898 self._idx[av.getId()]=l
1900 def unindexEmail(self, email, contrib):
1901 if not email or not contrib:
1902 return
1903 if self._getIdxEmail().has_key(email):
1904 l = self._getIdxEmail()[email]
1905 if contrib in l:
1906 l.remove(contrib)
1907 if l == []:
1908 del self._getIdxEmail()[email]
1909 else:
1910 self._getIdxEmail()[email] = l
1912 def _moveEmailtoId(self, av):
1913 id = av.getId()
1914 email = av.getEmail()
1915 if not self._idx.has_key(id):
1916 if self._getIdxEmail().has_key(email):
1917 self._idx[id] = self._getIdxEmail()[email]
1918 del self._getIdxEmail()[email]
1921 class ReportNumberHolder(Persistent):
1923 def __init__(self, owner):
1924 self._owner=owner
1925 self._reports={}
1927 def getOwner(self):
1928 return self._owner
1930 def addReportNumber(self, system, number):
1931 if system in self.getReportNumberKeys() or system in Config.getInstance().getReportNumberSystems().keys():
1932 try:
1933 if not number in self._reports[system]:
1934 self._reports[system].append(number)
1935 except:
1936 self._reports[system]=[ number ]
1937 self.notifyModification()
1939 def removeReportNumber(self, system, number):
1940 if self.hasReportNumber(system):
1941 if number in self._reports[system]:
1942 self._reports[system].remove(number)
1943 self.notifyModification()
1945 def removeReportNumberById(self, id):
1946 try:
1947 rn = self.listReportNumbers()[int(id)]
1948 self.removeReportNumber(rn[0], rn[1])
1949 except:
1950 pass
1952 def hasReportNumber(self, system):
1953 return self._reports.has_key(system)
1955 def getReportNumber(self, system):
1956 if self.hasReportNumber(system):
1957 return self._reports[system]
1958 return None
1960 def getReportNumberKeys(self):
1961 return self._reports.keys()
1963 def listReportNumbersOnKey(self, key):
1964 reports=[]
1965 if key in self._reports.keys():
1966 # compatibility with previous versions
1967 if type(self._reports[key]) is str:
1968 self._reports[key] = [ self._reports[key] ]
1969 for number in self._reports[key]:
1970 reports.append([key, number])
1971 return reports
1973 def listReportNumbers(self):
1974 reports=[]
1975 keys = self._reports.keys()
1976 keys.sort()
1977 for key in keys:
1978 # compatibility with previous versions
1979 if type(self._reports[key]) is str:
1980 self._reports[key] = [ self._reports[key] ]
1981 for number in self._reports[key]:
1982 reports.append([key, number])
1983 return reports
1985 def clone(self, owner):
1986 newR=ReportNumberHolder(owner)
1987 for key in self._reports.keys():
1988 for number in self._reports[key]:
1989 newR.addReportNumber(key, number)
1990 return newR
1992 def notifyModification(self):
1993 self._p_changed=1
1994 if self.getOwner() != None:
1995 self.getOwner().notifyModification()
1997 class Conference(CommonObjectBase, Locatable):
1998 """This class represents the real world conferences themselves. Objects of
1999 this class will contain basic data about the confence and will provide
2000 access to other objects representing certain parts of the conferences
2001 (ex: contributions, sessions, ...).
2004 fossilizes(IConferenceFossil, IConferenceMinimalFossil, IConferenceEventInfoFossil)
2006 def __init__(self, creator, id="", creationDate = None, modificationDate = None):
2007 """Class constructor. Initialise the class attributes to the default
2008 values.
2009 Params:
2010 confData -- (Dict) Contains the data the conference object has to
2011 be initialised to.
2013 #IndexedObject.__init__(self)
2014 if creator == None:
2015 raise MaKaCError( _("A creator must be specified when creating a new Event"), _("Event"))
2016 self.__creator = creator
2017 self.__creator.linkTo(self, "creator")
2018 self.id = id
2019 self.title = ""
2020 self.description = ""
2021 self.places = []
2022 self.rooms = []
2023 ###################################
2024 # Fermi timezone awareness #
2025 ###################################
2026 self.startDate = nowutc()
2027 self.endDate = nowutc()
2028 self.timezone = ""
2029 ###################################
2030 # Fermi timezone awareness(end) #
2031 ###################################
2032 self._screenStartDate = None
2033 self._screenEndDate = None
2034 self.contactInfo =""
2035 self.chairmanText = ""
2036 self.chairmans = []
2037 self._chairGen=Counter()
2038 self._chairs=[]
2039 self.sessions = {}
2040 self.__sessionGenerator = Counter() # Provides session unique
2041 # identifiers for this conference
2042 self.contributions = {}
2043 self.__contribGenerator = Counter() # Provides contribution unique
2044 # identifiers for this conference
2045 self.programDescription = ""
2046 self.program = []
2047 self.__programGenerator = Counter() # Provides track unique
2048 # identifiers for this conference
2049 self.__ac = AccessController(self)
2050 self.materials = {}
2051 self.__materialGenerator = Counter() # Provides material unique
2052 # identifiers for this conference
2053 self.paper = None
2054 self.slides = None
2055 self.video = None
2056 self.poster = None
2057 self.minutes=None
2058 self.__schedule=None
2059 self.__owners = []
2060 if creationDate:
2061 self._creationDS = creationDate
2062 else:
2063 self._creationDS = nowutc() #creation timestamp
2064 if modificationDate:
2065 self._modificationDS = modificationDate
2066 else:
2067 self._modificationDS = nowutc() #modification timestamp
2069 self.alarmList = {}
2070 self.__alarmCounter = Counter()
2072 self.abstractMgr = review.AbstractMgr(self)
2073 self._logo = None
2074 self._trackCoordinators = TCIndex() #index for the track coordinators
2075 self._supportEmail = "" #Support email for the conference
2076 self._contribTypes = {}
2077 self.___contribTypeGenerator = Counter()
2078 self._authorIdx=AuthorIndex()
2079 self._speakerIdx=AuthorIndex()
2080 self._primAuthIdx=_PrimAuthIdx(self)
2081 self._sessionCoordinators=SCIndex()
2082 self._sessionCoordinatorRights = []
2083 self._submitterIdx=SubmitterIndex()
2084 self._boa=BOAConfig(self)
2085 self._registrationForm = registration.RegistrationForm(self)
2086 self._evaluationCounter = Counter()
2087 self._evaluations = [Evaluation(self)]
2088 self._registrants = {} #key=registrantId; value=Registrant
2089 self._bookings = {}
2090 self._registrantGenerator = Counter()
2091 self._accessKey=""
2092 self._modifKey=""
2093 self._closed = False
2094 self._visibility = 999
2095 self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self)
2096 self._sections = []
2097 self._participation = Participation(self)
2098 self._logHandler = LogHandler()
2099 self._reportNumberHolder=ReportNumberHolder(self)
2100 self._enableSessionSlots = False
2101 self._enableSessions = False
2102 self._autoSolveConflict = True
2103 self.__badgeTemplateManager = BadgeTemplateManager(self)
2104 self.__posterTemplateManager = PosterTemplateManager(self)
2105 self._keywords = ""
2106 self._confPaperReview = ConferencePaperReview(self)
2107 self._confAbstractReview = ConferenceAbstractReview(self)
2108 self._orgText = ""
2109 self._comments = ""
2110 self._sortUrlTag = ""
2112 self._observers = []
2114 if PluginsHolder().hasPluginType("Collaboration"):
2115 from MaKaC.plugins.Collaboration.base import CSBookingManager
2116 self._CSBookingManager = CSBookingManager(self)
2118 def __str__(self):
2119 return "<Conference %s@%s>" % (self.getId(), hex(id(self)))
2121 @staticmethod
2122 def _cmpByDate(self, toCmp):
2123 res = cmp(self.getStartDate(), toCmp.getStartDate())
2124 if res != 0:
2125 return res
2126 else:
2127 return cmp(self, toCmp)
2129 def __cmp__(self, toCmp):
2130 if isinstance(toCmp, Conference):
2131 return cmp(self.getId(), toCmp.getId())
2132 else:
2133 return cmp(hash(self), hash(toCmp))
2135 def __eq__(self, toCmp):
2136 return self is toCmp
2138 def __ne__(self, toCmp):
2139 return not(self is toCmp)
2141 def setUrlTag(self, tag):
2142 self._sortUrlTag = tag
2144 def getUrlTag(self):
2145 try:
2146 return self._sortUrlTag
2147 except:
2148 self._sortUrlTag = ""
2149 return self._sortUrlTag
2151 def setComments(self,comm=""):
2152 self._comments = comm.strip()
2154 def getComments(self):
2155 try:
2156 if self._comments:
2157 pass
2158 except AttributeError,e:
2159 self.setComments()
2160 return self._comments
2162 def getConfPaperReview(self):
2163 if not hasattr(self, "_confPaperReview"):
2164 self._confPaperReview = ConferencePaperReview(self)
2165 return self._confPaperReview
2167 def getConfAbstractReview(self):
2168 if not hasattr(self, "_confAbstractReview"):
2169 self._confAbstractReview = ConferenceAbstractReview(self)
2170 return self._confAbstractReview
2172 def getOrgText( self ):
2173 try:
2174 return self._orgText
2175 except:
2176 self.setOrgText()
2177 return ""
2179 def setOrgText( self, org="" ):
2180 self._orgText = org
2182 def cleanCache( self ):
2183 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
2184 if minfo.isCacheActive():
2185 cache = EventCache({"id":self.getId(), "type": "normal"})
2186 cache.cleanCache()
2187 cache = EventCache({"id":self.getId(), "type": "manager"})
2188 cache.cleanCache()
2189 cache = EventCache({"id":self.getId(), "type": "static"})
2190 cache.cleanCache()
2192 def cleanCategoryCache( self ):
2193 if len(self.getOwnerList()) > 0:
2194 self.getOwnerList()[0].cleanCache()
2196 def isFullyPublic( self ):
2197 """ determines whether an event (or any part of it) is private or not"""
2198 if hasattr(self, "_fullyPublic"):
2199 return self._fullyPublic
2200 else:
2201 self.setFullyPublic()
2202 return self._fullyPublic
2204 def setFullyPublic( self ):
2205 """ This function calculates the self._fullyPublic attribute"""
2206 if self.isProtected():
2207 self._fullyPublic = False
2208 self._p_changed=1
2209 return
2210 for mat in self.getAllMaterialList():
2211 if not mat.isFullyPublic():
2212 self._fullyPublic = False
2213 self._p_changed=1
2214 return
2215 for cont in self.getContributionList():
2216 if not cont.isFullyPublic():
2217 self._fullyPublic = False
2218 self._p_changed=1
2219 return
2220 for ses in self.getSessionList():
2221 if not ses.isFullyPublic():
2222 self._fullyPublic = False
2223 self._p_changed=1
2224 return
2225 self._fullyPublic = True
2226 self._p_changed = 1
2228 def updateFullyPublic( self ):
2229 self.setFullyPublic()
2231 # Room booking related
2232 #self.__roomBookingGuids = []
2235 def getKeywords(self):
2236 try:
2237 return self._keywords
2238 except:
2239 self._keywords = ""
2240 return ""
2242 def setKeywords(self, keywords):
2243 self._keywords = keywords
2245 def _setCreator(self, av):
2246 self.__creator = av
2248 # Room booking related ===================================================
2250 def getRoomBookingList( self ):
2252 Returns list of bookings for this conference.
2254 from MaKaC.plugins.RoomBooking.default.dalManager import DALManager
2256 if not DALManager.isConnected():
2257 return []
2259 resvs = []
2260 for resvGuid in self.getRoomBookingGuids():
2261 r = resvGuid.getReservation()
2262 if r == None:
2263 self.removeRoomBookingGuid( resvGuid )
2264 elif r.isValid:
2265 resvs.append( r )
2266 return resvs
2268 def getBookedRooms( self ):
2270 Returns list of rooms booked for this conference.
2271 Returns [] if room booking module is off.
2273 rooms = []
2275 for r in self.getRoomBookingList():
2276 if not r.room in rooms:
2277 rooms.append( r.room )
2278 return rooms
2280 def getRoomBookingGuids( self ):
2281 try:
2282 self.__roomBookingGuids
2283 except AttributeError:
2284 self.__roomBookingGuids = []
2285 return self.__roomBookingGuids
2287 def setRoomBookingGuids( self, guids ):
2288 self.__roomBookingGuids = guids
2290 def addRoomBookingGuid( self, guid ):
2291 self.getRoomBookingGuids().append( guid )
2292 self._p_changed = True
2294 def removeRoomBookingGuid( self, guid ):
2295 self.getRoomBookingGuids().remove( guid )
2296 self._p_changed = True
2298 def __TMP_PopulateRoomBookings( self ):
2299 # TEMPORARY GENERATION OF RESERVATIONS FOR CONFERENCE
2300 from MaKaC.rb_reservation import ReservationBase
2301 from MaKaC.rb_location import ReservationGUID, Location
2302 resvs = []
2303 resvs.append( ReservationBase.getReservations( resvID = 395887 ) )
2304 resvs.append( ReservationBase.getReservations( resvID = 381406 ) )
2305 resvs.append( ReservationBase.getReservations( resvID = 387688 ) )
2306 resvs.append( ReservationBase.getReservations( resvID = 383459 ) )
2308 resvGuids = []
2309 for resv in resvs:
2310 resvGuids.append( ReservationGUID( Location.getDefaultLocation(), resv.id ) )
2312 self.__roomBookingGuids = resvGuids
2315 # ========================================================================
2317 def getParticipation(self):
2318 try :
2319 if self._participation :
2320 pass
2321 except AttributeError :
2322 self._participation = Participation(self)
2323 return self._participation
2325 def getType( self ):
2326 import MaKaC.webinterface.webFactoryRegistry as webFactoryRegistry
2327 wr = webFactoryRegistry.WebFactoryRegistry()
2328 wf = wr.getFactory(self)
2329 if wf != None:
2330 type = wf.getId()
2331 else:
2332 type = "conference"
2333 return type
2335 def getVerboseType( self ):
2336 # Like getType, but returns "Lecture" instead of "simple_type"
2337 type = self.getType()
2338 if type == "simple_event":
2339 type = "lecture"
2340 return type.capitalize()
2343 def getLogHandler(self):
2344 try :
2345 if self._logHandler:
2346 pass
2347 except AttributeError :
2348 self._logHandler = LogHandler()
2349 return self._logHandler
2352 def getEnableSessionSlots(self):
2353 #try :
2354 # if self._enableSessionSlots :
2355 # pass
2356 #except AttributeError :
2357 # self._enableSessionSlots = True
2358 #if self.getType() == "conference":
2359 # return True
2360 #return self._enableSessionSlots
2361 return True
2363 def getEnableSessions(self):
2364 try :
2365 if self._enableSessions :
2366 pass
2367 except AttributeError :
2368 self._enableSessions = True
2369 if self.getType() == "conference":
2370 return True
2371 return self._enableSessions
2373 def enableSessionSlots(self):
2374 self._enableSessionSlots = True
2376 def disableSessionSlots(self):
2377 self._enableSessionSlots = False
2379 def enableSessions(self):
2380 self._enableSessions = True
2382 def disableSessions(self):
2383 self._enableSessions = False
2385 def setValues(self, confData):
2387 Sets SOME values of the current conference object from a dictionary
2388 containing the following key-value pairs:
2389 visibility-(str)
2390 title-(str)
2391 description-(str)
2392 supportEmail-(str)
2393 contactInfo-(str)
2394 locationName-(str) => name of the location, if not specified
2395 it will be set to the conference location name.
2396 locationAddress-(str)
2397 roomName-(str) => name of the room, if not specified it will
2398 be set to the conference room name.
2399 Please, note that this method sets SOME values which means that if
2400 needed it can be completed to set more values. Also note that if
2401 the given dictionary doesn't contain all the values, the missing
2402 ones will be set to the default values.
2404 self.setVisibility(confData.get("visibility", "999"))
2405 self.setTitle(confData.get("title", _("NO TITLE ASSIGNED")))
2406 self.setDescription(confData.get("description", ""))
2407 self.setSupportEmail(confData.get("supportEmail", ""))
2408 self.setContactInfo(confData.get("contactInfo", ""))
2409 if confData.get("locationName", "").strip() == "":
2410 self.setLocation(None)
2411 else:
2412 #if the location name is defined we must set a new location (or
2413 # modify the existing one) for the conference
2414 loc = self.getLocation()
2415 if not loc:
2416 loc = CustomLocation()
2417 self.setLocation(loc)
2418 loc.setName(confData["locationName"])
2419 loc.setAddress(confData.get("locationAddress", ""))
2420 #same as for the location
2421 if confData.get("roomName", "").strip() == "":
2422 self.setRoom(None)
2423 else:
2424 room = self.getRoom()
2425 if not room:
2426 room = CustomRoom()
2427 self.setRoom(room)
2428 room.setName(confData["roomName"])
2429 self.notifyModification()
2431 def getVisibility ( self ):
2432 try:
2433 return int(self._visibility)
2434 except:
2435 self._visibility = 999
2436 return 999
2438 def getFullVisibility( self ):
2439 return max(0,min(self.getVisibility(), self.getOwnerList()[0].getVisibility()))
2441 def setVisibility( self, visibility=999 ):
2442 self._visibility = int(visibility)
2443 catIdx = indexes.IndexesHolder().getIndex('category')
2444 catIdx.reindexConf(self)
2445 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2446 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
2447 catDateIdx.reindexConf(self)
2448 catDateAllIdx.reindexConf(self)
2450 def isClosed( self ):
2451 try:
2452 return self._closed
2453 except:
2454 self._closed = False
2455 return False
2457 def setClosed( self, closed=True ):
2458 self._closed = closed
2460 def indexConf( self ):
2461 # called when event dates change
2462 # see also Category.indexConf()
2464 calIdx = indexes.IndexesHolder().getIndex('calendar')
2465 calIdx.indexConf(self)
2466 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2467 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
2468 catDateIdx.indexConf(self)
2469 catDateAllIdx.indexConf(self)
2471 Catalog.getIdx('categ_conf_sd').index_obj(self)
2473 def unindexConf( self ):
2474 calIdx = indexes.IndexesHolder().getIndex('calendar')
2475 calIdx.unindexConf(self)
2476 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2477 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
2478 catDateIdx.unindexConf(self)
2479 catDateAllIdx.unindexConf(self)
2481 Catalog.getIdx('categ_conf_sd').unindex_obj(self)
2483 def __generateNewContribTypeId( self ):
2484 """Returns a new unique identifier for the current conference sessions
2486 try:
2487 return str(self.___contribTypeGenerator.newCount())
2488 except:
2489 self.___contribTypeGenerator = Counter()
2490 return str(self.___contribTypeGenerator.newCount())
2492 def addContribType(self, ct):
2493 try:
2494 if self._contribTypes:
2495 pass
2496 except:
2497 self._contribTypes = {}
2498 if ct in self._contribTypes.values():
2499 return
2500 id = ct.getId()
2501 if id == "":
2502 id = self.__generateNewContribTypeId()
2503 ct.setId(id)
2504 self._contribTypes[id] = ct
2505 self.notifyModification()
2507 def newContribType(self, name, description):
2508 ct = ContributionType(name, description, self)
2509 self.addContribType(ct)
2510 return ct
2512 def getContribTypeList(self):
2513 try:
2514 return self._contribTypes.values()
2515 except:
2516 self._contribTypes = {}
2517 self.notifyModification()
2518 return self._contribTypes.values()
2520 def getContribTypeById(self, id):
2521 try:
2522 if self._contribTypes:
2523 pass
2524 except:
2525 self._contribTypes = {}
2526 self.notifyModification()
2527 if id in self._contribTypes.keys():
2528 return self._contribTypes[id]
2529 return None
2531 def removeContribType(self, ct):
2532 try:
2533 if self._contribTypes:
2534 pass
2535 except:
2536 self._contribTypes = {}
2537 if not ct in self._contribTypes.values():
2538 return
2539 del self._contribTypes[ct.getId()]
2540 for cont in self.getContributionList():
2541 if cont.getType() == ct:
2542 cont.setType(None)
2543 ct.delete()
2544 self.notifyModification()
2546 def recoverContribType(self, ct):
2547 ct.setConference(self)
2548 self.addContribType(ct)
2549 ct.recover()
2551 def _getRepository( self ):
2552 dbRoot = DBMgr.getInstance().getDBConnection().root()
2553 try:
2554 fr = dbRoot["local_repositories"]["main"]
2555 except KeyError, e:
2556 fr = fileRepository.MaterialLocalRepository()
2557 dbRoot["local_repositories"] = OOBTree()
2558 dbRoot["local_repositories"]["main"] = fr
2559 return fr
2561 def removeResource( self, res ):
2562 pass
2564 def getURL(self):
2565 cid = self.getUrlTag()
2566 if not cid:
2567 cid = self.getId()
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:
2575 self._logo.delete()
2576 self._logo = logoFile
2577 self.notifyModification()
2579 def getLogo( self ):
2580 return self._logo
2582 def getLogoURL( self ):
2583 try:
2584 if self._logo == None:
2585 return ""
2586 return self._logo.getURL()
2587 except AttributeError:
2588 self._logo = None
2589 return ""
2591 def removeLogo(self):
2592 if self._logo is None:
2593 return
2594 self._logo.delete()
2595 self._logo = None
2596 self.notifyModification()
2598 def recoverLogo(self, logo):
2599 logo.setOwner(self)
2600 if self._logo != None:
2601 self._logo.delete()
2602 self._logo = logo
2603 logo.recover()
2604 self.notifyModification()
2606 def getSession(self):
2607 return None
2609 def getContribution(self):
2610 return None
2612 def getSubContribution(self):
2613 return None
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()
2623 if raiseEvent:
2624 self._notify('infoChanged')
2626 self.cleanCache()
2627 self._p_changed=1
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):
2649 if self.__creator:
2650 self.__creator.unlinkTo(self, "creator")
2651 creator.linkTo(self, "creator")
2652 self.__creator = creator
2654 def getId( self ):
2655 """returns (string) the unique identifier of the conference"""
2656 return self.id
2658 def getUniqueId( self ):
2659 """returns (string) the unique identiffier of the item"""
2660 """used mainly in the web session access key table"""
2661 return "a%s" % self.id
2663 def setId(self, newId):
2664 """changes the current unique identifier of the conference to the
2665 one which is specified"""
2666 self.id = str(newId)
2668 def getLocator( self ):
2669 """Gives back (Locator) a globaly unique identification encapsulated in
2670 a Locator object for the conference instance """
2671 d = Locator()
2672 d["confId"] = self.getId()
2673 return d
2675 def getOwner( self ):
2676 if self.getOwnerList() == []:
2677 return None
2678 return self.getOwnerList()[0]
2680 def getOwnerList( self ):
2681 return self.__owners
2683 def getOwnerPath( self ):
2684 l=[]
2685 owner = self.getOwnerList()[0]
2686 while owner != None and owner.getId() != "0":
2687 l.append(owner)
2688 owner = owner.getOwner()
2689 return l
2691 def getOwnerById( self, key ):
2692 """Returns one specific category which contains the conference.
2693 Params:
2694 - key: The "id" of the category.
2696 for owner in self.__owners:
2697 if key == owner.getId():
2698 return owner
2699 return None
2701 def addOwner( self, newOwner ):
2702 if newOwner == None:
2703 return
2704 self.__owners.append( newOwner )
2705 self.notifyModification()
2707 def removeOwner( self, owner, notify=True ):
2708 if not (owner in self.__owners):
2709 return
2710 self.__owners.remove( owner )
2711 owner.removeConference( self )
2712 if notify:
2713 self.notifyModification()
2715 def getCategoriesPath(self):
2716 return [self.getOwnerList()[0].getCategoryPath()]
2718 def notifyContributions(self):
2720 for c in self.getContributionList():
2721 # take care of subcontributions
2722 for sc in c.getSubContributionList():
2723 sc._notify('deleted', c)
2725 c._notify('deleted', self)
2727 def delete( self ):
2728 """deletes the conference from the system.
2730 #we notify the observers that the conference has been deleted
2731 try:
2732 self._notify('deleted', self.getOwner())
2733 except Exception, e:
2734 try:
2735 Logger.get('Conference').error("Exception while notifying the observer of a conference deletion for conference %s: %s" %
2736 (self.getId(), str(e)))
2737 except Exception, e2:
2738 Logger.get('Conference').error("Exception while notifying a conference deletion: %s (origin: %s)" % (str(e2), str(e)))
2740 self.notifyContributions()
2742 #will have to remove it from all the owners (categories) and the
2743 # conference registry
2744 ConferenceHolder().remove( self )
2745 for owner in self.__owners:
2746 owner.removeConference( self, notify=False )
2748 for alarm in self.getAlarmList():
2749 if not alarm.getEndedOn():
2750 self.removeAlarm(alarm)
2752 self.removeAllEvaluations()
2754 #Delete the RoomBooking associated reservations
2755 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
2756 if minfo.getRoomBookingModuleActive() and CrossLocationDB.isConnected():
2757 for resv in self.getRoomBookingList():
2758 resv.remove()
2760 #For each conference we have a list of managers. If we delete the conference but we don't delete
2761 #the link in every manager to the conference then, when the manager goes to his "My profile" he
2762 #will see a link to a conference that doesn't exist. Therefore, we need to delete that link as well
2763 for manager in self.getManagerList():
2764 if isinstance(manager, MaKaC.user.Avatar):
2765 manager.unlinkTo(self, "manager")
2767 # Remote short URL mappings
2768 sum = ShortURLMapper()
2769 sum.remove(self)
2771 TrashCanManager().add(self)
2773 def getConference( self ):
2774 return self
2776 def getObservers(self):
2777 if not hasattr(self, "_observers"):
2778 self._observers = []
2779 return self._observers
2781 def setDates( self, sDate, eDate=None, check=1, moveEntries=0):
2783 Set the start/end date for a conference
2786 oldStartDate = self.getStartDate()
2787 oldEndDate = self.getEndDate()
2789 # do some checks first
2790 if sDate > eDate:
2791 # obvious case
2792 raise MaKaCError( _("Start date cannot be after the end date"), _("Event"))
2794 elif sDate == oldStartDate and eDate == oldEndDate:
2795 # if there's nothing to do (yet another obvious case)
2796 return
2798 # if we reached this point, it means either the start or
2799 # the end date (or both) changed
2800 # If only the end date was changed, moveEntries = 0
2801 if sDate == oldStartDate:
2802 moveEntries = 0
2804 # Pre-check for moveEntries
2805 if moveEntries == 1:
2806 # in case the entries are to be simply shifted
2807 # we should make sure the interval is big enough
2808 # just store the old values for later
2810 oldInterval = oldEndDate - oldStartDate
2811 newInterval = eDate - sDate
2813 entries = self.getSchedule().getEntries()
2814 if oldInterval > newInterval and entries:
2815 eventInterval = entries[-1].getEndDate() - entries[0].getStartDate()
2816 diff = entries[0].getStartDate() - oldStartDate
2817 if sDate + diff + eventInterval > eDate:
2818 raise TimingError(
2819 _("The start/end dates were not changed since the selected "
2820 "timespan is not large enough to accomodate the contained "
2821 "timetable entries and spacings."),
2822 explanation=_("You should try using a larger timespan."))
2824 # so, we really need to try changing something
2826 self.unindexConf()
2828 # set the dates
2829 self.setStartDate(sDate, check=0, moveEntries = moveEntries, index=False, notifyObservers = False)
2830 self.setEndDate(eDate, check=0, index=False, notifyObservers = False)
2832 # sanity check
2833 self._checkInnerSchedule()
2835 # reindex the conference
2836 self.indexConf()
2838 # clear the category cache
2839 self.cleanCategoryCache()
2841 # notify observers
2842 try:
2843 self._notify('dateChanged', {'oldStartDate': oldStartDate, 'newStartDate': self.getStartDate(), 'oldEndDate': oldEndDate, 'newEndDate': self.getEndDate()})
2844 except Exception, e:
2845 try:
2846 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" %
2847 (formatDateTime(oldStartDate), formatDateTime(oldEndDate),
2848 formatDateTime(self.getStartDate()), formatDateTime(self.getEndDate()), self.getId(), str(e)))
2849 except Exception, e2:
2850 Logger.get('Conference').error("Exception while notifying a start and end date change: %s (origin: %s)" % (str(e2), str(e)))
2853 def _checkInnerSchedule( self ):
2854 self.getSchedule().checkSanity()
2856 def setStartDate(self, sDate, check = 1, moveEntries = 0, index = True, notifyObservers = True):
2857 """ Changes the current conference starting date/time to the one specified by the parameters.
2859 if not sDate.tzname():
2860 raise MaKaCError("date should be timezone aware")
2861 if sDate == self.getStartDate():
2862 return
2863 ###################################
2864 # Fermi timezone awareness #
2865 ###################################
2866 if sDate.year < 1900:
2867 sDate = timezone('UTC').localize(1900,sDate.month, \
2868 sDate.day,sDate.hour,sDate.minute)
2869 ###################################
2870 # Fermi timezone awareness #
2871 ###################################
2872 if check != 0:
2873 self.verifyStartDate(sDate)
2874 oldSdate = self.getStartDate()
2875 diff = sDate - oldSdate
2877 if index:
2878 self.unindexConf()
2879 self.startDate = sDate
2880 if moveEntries and diff is not None:
2881 # If the start date changed, we move entries inside the timetable
2882 self.getSchedule()._startDate=None
2883 self.getSchedule()._endDate=None
2884 #if oldSdate.date() != sDate.date():
2885 # entries = self.getSchedule().getEntries()[:]
2886 #else:
2887 # entries = self.getSchedule().getEntriesOnDay(sDate.astimezone(timezone(self.getTimezone())))[:]
2888 entries = self.getSchedule().getEntries()[:]
2889 self.getSchedule().moveEntriesBelow(diff, entries)
2890 #datetime object is non-mutable so we must "force" the modification
2891 # otherwise ZODB won't be able to notice the change
2892 self.notifyModification()
2893 if index:
2894 self.indexConf()
2896 # update the time for the alarms to be sent
2897 self._updateAlarms()
2899 #if everything went well, we notify the observers that the start date has changed
2900 if notifyObservers:
2901 try:
2902 self._notify('startDateChanged', {'newDate': sDate, 'oldDate': oldSdate})
2903 except Exception, e:
2904 try:
2905 Logger.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s" %
2906 (formatDateTime(oldSdate), formatDateTime(sDate), self.getId(), str(e)))
2907 except Exception, e2:
2908 Logger.get('Conference').error("Exception while notifying a start date change: %s (origin: %s)" % (str(e2), str(e)))
2911 def _updateAlarms(self):
2912 c = Client()
2913 # are there any alarms? if so, update the relative ones
2914 for alarm in self.getAlarmList():
2915 tbef = alarm.getTimeBefore()
2916 if tbef:
2917 # only relative alarms
2918 c.moveTask(alarm, self.getStartDate() - tbef)
2920 def verifyStartDate(self, sdate, check=1):
2921 if sdate>self.getEndDate():
2922 raise MaKaCError( _("End date cannot be before the Start date"), _("Event"))
2924 def setStartTime(self, hours=0, minutes=0, notifyObservers = True):
2925 """ Changes the current conference starting time (not date) to the one specified by the parameters.
2928 sdate = self.getStartDate()
2929 self.startDate = datetime( sdate.year, sdate.month, sdate.day,
2930 int(hours), int(minutes) )
2931 self.verifyStartDate(self.startDate)
2932 self.notifyModification()
2934 #if everything went well, we notify the observers that the start date has changed
2935 if notifyObservers:
2936 try:
2937 self._notify('startTimeChanged', sdate)
2938 #for observer in self.getObservers():
2939 #observer.notifyEventDateChanges(sdate, self.startDate, None, None)
2940 except Exception, e:
2941 try:
2942 Logger.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s"%
2943 (formatDateTime(sdate), formatDateTime(self.startDate), self.getId(), str(e)))
2944 except Exception, e2:
2945 Logger.get('Conference').error("Exception while notifying a start time change: %s (origin: %s)"%(str(e2), str(e)))
2947 def getStartDate(self):
2948 """returns (datetime) the starting date of the conference"""
2949 return self.startDate
2951 ###################################
2952 # Fermi timezone awareness #
2953 ###################################
2955 def getAdjustedStartDate(self,tz=None):
2956 if not tz:
2957 tz = self.getTimezone()
2958 if tz not in all_timezones:
2959 tz = 'UTC'
2960 return self.getStartDate().astimezone(timezone(tz))
2962 ###################################
2963 # Fermi timezone awareness(end) #
2964 ###################################
2966 def setScreenStartDate(self, date):
2967 if date == self.getStartDate():
2968 date = None
2969 self._screenStartDate = date
2970 self.notifyModification()
2972 def getScreenStartDate(self):
2973 try:
2974 date = self._screenStartDate
2975 except:
2976 date = self._screenStartDate = None
2977 if date != None:
2978 return date
2979 else:
2980 return self.getStartDate()
2982 def getAdjustedScreenStartDate(self, tz=None):
2983 if not tz:
2984 tz = self.getTimezone()
2985 return self.getScreenStartDate().astimezone(timezone(tz))
2987 def calculateDayStartTime(self, day):
2988 """returns (date) the start date of the conference on a given day
2989 day is a tz aware datetime"""
2990 if self.getStartDate().astimezone(day.tzinfo).date() == day.date():
2991 return self.getStartDate().astimezone(day.tzinfo)
2992 return self.getSchedule().calculateDayStartDate(day)
2994 def verifyEndDate(self, edate):
2995 if edate<self.getStartDate():
2996 raise TimingError( _("End date cannot be before the start date"), _("Event"))
2997 if self.getSchedule().hasEntriesAfter(edate):
2998 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"))
3000 def setEndDate(self, eDate, check = 1, index = True, notifyObservers = True):
3001 """ Changes the current conference end date/time to the one specified by the parameters.
3003 if not eDate.tzname():
3004 raise MaKaCError("date should be timezone aware")
3005 if eDate == self.getEndDate():
3006 return
3007 if eDate.year < 1900:
3008 eDate = datetime(1900,eDate.month,eDate.day,eDate.hour,eDate.minute)
3009 if check != 0:
3010 self.verifyEndDate(eDate)
3011 if index:
3012 self.unindexConf()
3014 oldEdate = self.endDate
3015 self.endDate = eDate
3016 #datetime object is non-mutable so we must "force" the modification
3017 # otherwise ZODB won't be able to notice the change
3018 self.notifyModification()
3019 if index:
3020 self.indexConf()
3022 #if everything went well, we notify the observers that the start date has changed
3023 if notifyObservers:
3024 try:
3025 self._notify('endDateChanged', {'newDate': eDate, 'oldDate': oldEdate})
3026 except Exception, e:
3027 try:
3028 Logger.get('Conference').error("Exception while notifying the observer of a end date change from %s to %s for conference %s: " %
3029 (formatDateTime(oldEdate), formatDateTime(eDate), self.getId(), str(e)))
3030 except Exception, e2:
3031 Logger.get('Conference').error("Exception while notifying a end date change: %s (origin: %s)" % (str(e2), str(e)))
3034 def setEndTime(self, hours = 0, minutes = 0, notifyObservers = True):
3035 """ Changes the current conference end time (not date) to the one specified by the parameters.
3037 edate = self.getEndDate()
3038 self.endDate = datetime( edate.year, edate.month, edate.day, int(hours), int(minutes) )
3039 self.verifyEndDate(self.endDate)
3040 self.notifyModification()
3042 #if everything went well, we notify the observers that the start date has changed
3043 if notifyObservers:
3044 try:
3045 self._notify('endTimeChanged', edate)
3046 #for observer in self.getObservers():
3047 except Exception, e:
3048 #observer.notifyEventDateChanges(None, None, edate, self.endDate)
3049 try:
3050 Logger.get('Conference').error("Exception while notifying the observer of a end timet change from %s to %s for conference %s: %s" %
3051 (formatDateTime(edate), formatDateTime(self.endDate), self.getId(), str(e)))
3052 except Exception, e2:
3053 Logger.get('Conference').error("Exception while notifying a end time change: %s (origin: %s)"%(str(e2), str(e)))
3055 def getEndDate(self):
3056 """returns (datetime) the ending date of the conference"""
3057 return self.endDate
3059 ##################################
3060 # Fermi timezone awareness #
3061 ##################################
3063 def getAdjustedEndDate(self,tz=None):
3064 if not tz:
3065 tz = self.getTimezone()
3066 if tz not in all_timezones:
3067 tz = 'UTC'
3068 return self.getEndDate().astimezone(timezone(tz))
3070 ##################################
3071 # Fermi timezone awareness(end) #
3072 ##################################
3074 def setScreenEndDate(self, date):
3075 if date == self.getEndDate():
3076 date = None
3077 self._screenEndDate = date
3078 self.notifyModification()
3080 def getScreenEndDate(self):
3081 try:
3082 date = self._screenEndDate
3083 except:
3084 date = self._screenEndDate = None
3085 if date != None:
3086 return date
3087 else:
3088 return self.getEndDate()
3090 def getAdjustedScreenEndDate(self, tz=None):
3091 if not tz:
3092 tz = self.getTimezone()
3093 return self.getScreenEndDate().astimezone(timezone(tz))
3095 def isEndDateAutoCal( self ):
3096 """Says whether the end date has been explicitely set for the session
3097 or it must be calculated automatically
3099 return self._endDateAutoCal
3101 ####################################
3102 # Fermi timezone awareness #
3103 ####################################
3104 def setTimezone(self, tz):
3105 try:
3106 oldTimezone = self.timezone
3107 except AttributeError:
3108 oldTimezone = tz
3109 self.timezone = tz
3110 #for observer in self.getObservers():
3111 try:
3112 #observer.notifyTimezoneChange(oldTimezone, tz)
3113 self._notify('timezoneChanged', oldTimezone)
3114 except Exception, e:
3115 try:
3116 Logger.get('Conference').error("Exception while notifying the observer of a timezone change from %s to %s for conference %s: %s" %
3117 (str(oldTimezone), str(tz), self.getId(), str(e)))
3118 except Exception, e2:
3119 Logger.get('Conference').error("Exception while notifying a timezone change: %s (origin: %s)"%(str(e2), str(e)))
3121 def getTimezone(self):
3122 try:
3123 return self.timezone
3124 except:
3125 return 'UTC'
3127 def moveToTimezone(self, tz):
3128 if self.getTimezone() == tz:
3129 return
3130 sd=self.getAdjustedStartDate()
3131 ed=self.getAdjustedEndDate()
3132 self.setTimezone(tz)
3133 try:
3134 sDate = timezone(tz).localize(datetime(sd.year, \
3135 sd.month, \
3136 sd.day, \
3137 sd.hour, \
3138 sd.minute))
3139 eDate = timezone(tz).localize(datetime(ed.year, \
3140 ed.month, \
3141 ed.day, \
3142 ed.hour, \
3143 ed.minute))
3144 except ValueError,e:
3145 raise MaKaCError("Error moving the timezone: %s"%e)
3146 self.setDates( sDate.astimezone(timezone('UTC')), \
3147 eDate.astimezone(timezone('UTC')),
3148 moveEntries=1)
3152 ####################################
3153 # Fermi timezone awareness(end) #
3154 ####################################
3156 def getTitle(self):
3157 """returns (String) the title of the conference"""
3158 return self.title
3160 def setTitle(self, title):
3161 """changes the current title of the conference to the one specified"""
3162 oldTitle = self.title
3164 self.title = title
3165 self.cleanCategoryCache()
3166 self.notifyModification()
3168 #we notify the observers that the conference's title has changed
3169 try:
3170 self._notify('eventTitleChanged', oldTitle, title)
3171 except Exception, e:
3172 Logger.get('Conference').exception("Exception while notifying the observer of a conference title change for conference %s: %s" %
3173 (self.getId(), str(e)))
3176 def getDescription(self):
3177 """returns (String) the description of the conference"""
3178 return self.description
3180 def setDescription(self, desc):
3181 """changes the current description of the conference"""
3182 self.description = desc
3183 self.notifyModification()
3185 def getSupportEmail(self, returnNoReply=False, caption=False):
3187 Returns the support email address associated with the conference
3188 :param returnNoReply: Return no-reply address in case there's no support e-mail (default True)
3189 :type returnNoReply: bool
3192 try:
3193 if self._supportEmail:
3194 pass
3195 except AttributeError:
3196 self._supportEmail = ""
3197 if self._supportEmail.strip() == "" and returnNoReply:
3198 # In case there's no conference support e-mail, return the no-reply
3199 # address, and the 'global' support e-mail if there isn't one
3200 return Config.getInstance().getNoReplyEmail()
3201 else:
3202 supportCaption = self.getDisplayMgr().getSupportEmailCaption()
3204 if caption and supportCaption:
3205 return '"%s" <%s>' % (supportCaption, self._supportEmail)
3206 else:
3207 return self._supportEmail
3209 def setSupportEmail( self, newSupportEmail ):
3210 self._supportEmail = newSupportEmail.strip()
3212 def hasSupportEmail( self ):
3213 try:
3214 if self._supportEmail:
3215 pass
3216 except AttributeError, e:
3217 self._supportEmail = ""
3218 return self._supportEmail != "" and self._supportEmail != None
3220 def getChairmanText( self ):
3221 try:
3222 if self.chairmanText:
3223 pass
3224 except AttributeError, e:
3225 self.chairmanText = ""
3226 return self.chairmanText
3228 def setChairmanText( self, newText ):
3229 self.chairmanText = newText.strip()
3231 def appendChairmanText( self, newText ):
3232 self.setChairmanText( "%s, %s"%(self.getChairmanText(), newText.strip()) )
3233 self._chairGen=Counter()
3234 self._chairs=[]
3236 def _resetChairs(self):
3237 try:
3238 if self._chairs:
3239 return
3240 except AttributeError:
3241 self._chairs=[]
3242 for oc in self.chairmans:
3243 newChair=ConferenceChair()
3244 newChair.setDataFromAvatar(oc)
3245 self._addChair(newChair)
3247 def getChairList(self):
3248 """Method returning a list of the conference chairmans (Avatars)
3250 self._resetChairs()
3251 return self._chairs
3253 def _addChair(self,newChair):
3254 for chair in self._chairs:
3255 if newChair.getEmail() != "" and newChair.getEmail() == chair.getEmail():
3256 return
3257 try:
3258 if self._chairGen:
3259 pass
3260 except AttributeError:
3261 self._chairGen=Counter()
3262 id = newChair.getId()
3263 if id == "":
3264 id=int(self._chairGen.newCount())
3265 if isinstance(newChair,ConferenceChair):
3266 newChair.includeInConference(self,id)
3267 self._chairs.append(newChair)
3268 if isinstance(newChair, MaKaC.user.Avatar):
3269 newChair.linkTo(self, "chair")
3270 self.notifyModification()
3272 def addChair(self,newChair):
3273 """includes the specified user in the list of conference
3274 chairs"""
3275 self._resetChairs()
3276 self._addChair(newChair)
3278 def removeChair(self,chair):
3279 """removes the specified user from the list of conference
3280 chairs"""
3281 self._resetChairs()
3282 if chair not in self._chairs:
3283 return
3284 self._chairs.remove(chair)
3285 if isinstance(chair, MaKaC.user.Avatar):
3286 chair.unlinkTo(self, "chair")
3287 chair.delete()
3288 self.notifyModification()
3290 def recoverChair(self, ch):
3291 self.addChair(ch)
3292 ch.recover()
3294 def getChairById(self,id):
3295 id=int(id)
3296 for chair in self._chairs:
3297 if chair.getId()==id:
3298 return chair
3299 return None
3301 def getAllSessionsConvenerList(self) :
3302 dictionary = {}
3303 for session in self.getSessionList() :
3304 for convener in session.getConvenerList() :
3305 key = convener.getEmail()+" "+convener.getFirstName().lower()+" "+convener.getFamilyName().lower()
3306 dictionary.setdefault(key, set()).add(convener)
3307 for slot in session.getSlotList():
3308 for convener in slot.getConvenerList() :
3309 key = convener.getEmail()+" "+convener.getFirstName().lower()+" "+convener.getFamilyName().lower()
3310 dictionary.setdefault(key, set()).add(convener)
3312 return dictionary
3314 def getContactInfo(self):
3315 return self.contactInfo
3317 def setContactInfo(self, contactInfo):
3318 self.contactInfo = contactInfo
3319 self.notifyModification()
3321 def getLocationParent( self ):
3323 Returns the object from which the room/location
3324 information should be inherited.
3325 For Conferences, it's None, since they can't inherit
3326 from anywhere else.
3328 return None
3330 def getLocation( self ):
3331 return self.getOwnLocation()
3333 def getRoom( self ):
3334 return self.getOwnRoom()
3336 def getLocationList(self):
3337 """Method returning a list of "location" objects which contain the
3338 information about the different places the conference is gonna
3339 happen
3341 return self.places
3343 def getFavoriteRooms(self):
3344 roomList = []
3345 roomList.extend(self.getRoomList())
3346 #roomList.extend(map(lambda x: x._getName(), self.getBookedRooms()))
3348 return roomList
3350 def addLocation(self, newPlace):
3351 self.places.append( newPlace )
3352 self.notifyModification()
3354 def setAccessKey(self, accessKey=""):
3355 """sets the access key of the conference"""
3356 self._accessKey = accessKey
3357 self.notifyModification()
3359 def getAccessKey(self):
3360 try:
3361 return self._accessKey
3362 except AttributeError:
3363 self._accessKey = ""
3364 return self._accessKey
3366 def setModifKey(self, modifKey=""):
3367 """sets the modification key of the conference"""
3368 self._modifKey = modifKey
3369 self.notifyModification()
3371 def getModifKey(self):
3372 try:
3373 return self._modifKey
3374 except AttributeError:
3375 self._modifKey = ""
3376 return self._modifKey
3378 def __generateNewSessionId( self ):
3379 """Returns a new unique identifier for the current conference sessions
3381 return str(self.__sessionGenerator.newCount())
3383 def addSession(self,newSession, check = 2, id = None):
3384 """Adds a new session object to the conference taking care of assigning
3385 a new unique id to it
3387 """check parameter:
3388 0: no check at all
3389 1: check and raise error in case of problem
3390 2: check and adapt the owner dates"""
3392 if self.hasSession(newSession):
3393 return
3394 if self.getSchedule().isOutside(newSession):
3395 if check == 1:
3396 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 elif check == 2:
3398 if self.getSchedule().getStartDate() > newSession.getStartDate():
3399 self.setStartDate(newSession.getStartDate())
3400 if self.getSchedule().getEndDate() < newSession.getEndDate():
3401 self.setEndDate(newSession.getEndDate())
3402 if id!=None:
3403 sessionId = id
3404 else:
3405 sessionId=self.__generateNewSessionId()
3406 self.sessions[sessionId]=newSession
3407 newSession.includeInConference(self,sessionId)
3408 #keep the session coordinator index updated
3409 for sc in newSession.getCoordinatorList():
3410 self.addSessionCoordinator(newSession,sc)
3411 self.notifyModification()
3413 def hasSession(self,session):
3414 if session != None and session.getConference()==self and \
3415 self.sessions.has_key(session.getId()):
3416 return True
3417 return False
3419 def removeSession(self,session, deleteContributions=False):
3420 if self.hasSession(session):
3421 for sc in session.getCoordinatorList():
3422 self.removeSessionCoordinator(session,sc)
3424 if deleteContributions:
3425 for contrib in session.getContributionList():
3426 contrib.delete()
3428 del self.sessions[session.getId()]
3430 session.delete()
3431 self.notifyModification()
3433 def recoverSession(self, session, check, isCancelled):
3434 self.addSession(session, check, session.getId())
3435 session.recover(isCancelled)
3437 def getSessionById( self, sessionId ):
3438 """Returns the session from the conference list corresponding to the
3439 unique session id specified
3441 return self.sessions.get(sessionId,None)
3443 def getRoomList(self):
3444 roomList =[]
3445 for session in self.sessions.values():
3446 if session.getRoom()!=None:
3447 roomname = session.getRoom().getName()
3448 if roomname not in roomList:
3449 roomList.append(roomname)
3450 return roomList
3452 def getSessionList( self ):
3453 """Retruns a list of the conference session objects
3455 return self.sessions.values()
3457 def getSessionListSorted( self ):
3458 """Retruns a sorted list of the conference sessions
3460 res=[]
3461 for entry in self.getSchedule().getEntries():
3462 if isinstance(entry,LinkedTimeSchEntry) and \
3463 isinstance(entry.getOwner(),SessionSlot):
3464 session=entry.getOwner().getSession()
3465 if session not in res:
3466 res.append(session)
3467 return res
3469 def getNumberOfSessions( self ):
3470 return len(self.sessions)
3472 def _generateNewContributionId( self ):
3473 """Returns a new unique identifier for the current conference
3474 contributions
3476 return str(self.__contribGenerator.newCount())
3478 def genNewAbstractId(self):
3479 return str(self.__contribGenerator.newCount())
3481 def syncContribCounter(self):
3482 self.__contribGenerator.sync(self.getAbstractMgr()._getOldAbstractCounter())
3483 return self.__contribGenerator._getCount()
3485 def addContribution(self,newContrib,id=""):
3486 """Adds a new contribution object to the conference taking care of
3487 assigning a new unique id to it
3489 if self.hasContribution(newContrib):
3490 return
3491 if isinstance(newContrib.getCurrentStatus(),ContribStatusWithdrawn):
3492 raise MaKaCError( _("Cannot add a contribution which has been withdrawn"), _("Event"))
3493 if id is None or id=="":
3494 contribId=self._generateNewContributionId()
3495 while self.contributions.has_key(contribId):
3496 contribId=self._generateNewContributionId()
3497 else:
3498 contribId=str(id)
3499 if self.contributions.has_key(contribId):
3500 raise MaKaCError( _("Cannot add this contribution id:(%s) as it has already been used")%contribId, _("Event"))
3501 newContrib.includeInConference(self,contribId)
3502 self.contributions[contribId]=newContrib
3503 for auth in newContrib.getAuthorList():
3504 self.indexAuthor(auth)
3505 for spk in newContrib.getSpeakerList():
3506 self.indexSpeaker(spk)
3507 for sub in newContrib.getSubmitterList():
3508 self.addContribSubmitter(newContrib,sub)
3510 newContrib._notify('created', self)
3511 self.notifyModification()
3513 def hasContribution(self,contrib):
3514 return contrib.getConference()==self and \
3515 self.contributions.has_key(contrib.getId())
3517 def removeContribution( self, contrib, callDelete=True ):
3518 if not self.contributions.has_key( contrib.getId() ):
3519 return
3520 for sub in contrib.getSubmitterList()[:]:
3521 self.removeContribSubmitter(contrib,sub)
3522 for auth in contrib.getPrimaryAuthorList()[:]:
3523 contrib.removePrimaryAuthor(auth)
3524 for auth in contrib.getCoAuthorList()[:]:
3525 contrib.removeCoAuthor(auth)
3526 for spk in contrib.getSpeakerList()[:]:
3527 contrib.removeSpeaker(spk)
3528 del self.contributions[ contrib.getId() ]
3529 if callDelete:
3530 contrib.delete()
3531 #else:
3532 # contrib.unindex()
3533 self.notifyModification()
3535 def recoverContribution(self, contrib):
3536 self.addContribution(contrib, contrib.getId())
3537 contrib.recover()
3539 # Note: this kind of factories should never be used as they only allow to
3540 # create a single type of contributions
3541 def newContribution( self, id=None ):
3542 """Creates and returns a new contribution object already added to the
3543 conference list (all its data is set to the default)
3545 c = Contribution()
3546 self.addContribution( c, id )
3547 return c
3549 def getOwnContributionById( self, id ):
3550 """Returns the contribution from the conference list corresponding to
3551 the unique contribution id specified
3553 if self.contributions.has_key( id ):
3554 return self.contributions[ id ]
3555 return None
3557 def getContributionById( self, id ):
3558 """Returns the contribution corresponding to the id specified
3560 return self.contributions.get(str(id).strip(),None)
3562 def getContributionList(self):
3563 """Returns a list of the conference contribution objects
3565 return self.contributions.values()
3567 def iterContributions(self):
3568 return self.contributions.itervalues()
3570 def getContributionListWithoutSessions(self):
3571 """Returns a list of the conference contribution objects which do not have a session
3573 return [c for c in self.contributions.values() if not c.getSession()]
3575 def getContributionListSortedById(self, includeWithdrawn=True):
3576 """Returns a list of the conference contribution objects, sorted by their id
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: c.getId())
3582 return contributions
3584 def getNumberOfContributions(self, only_scheduled=False):
3585 if only_scheduled:
3586 return len(filter(lambda c: c.isScheduled(), self.contributions.itervalues()))
3587 else:
3588 return len(self.contributions)
3590 def getProgramDescription(self):
3591 try:
3592 return self.programDescription
3593 except:
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:
3610 return
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:
3622 track.delete()
3623 if track in self.program:
3624 self.program.remove( track )
3625 self.notifyModification()
3627 def recoverTrack(self, track):
3628 self.addTrack(track)
3629 track.recover()
3631 def newTrack( self ):
3634 t = Track()
3635 self.addTrack( t )
3636 return t
3638 def getTrackById( self, id ):
3641 for track in self.program:
3642 if track.getId() == id.strip():
3643 return track
3644 return None
3646 def getTrackList( self ):
3649 return self.program
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):
3677 return
3678 newPos=self.getTrackPos(track)-1
3679 self.moveTrack(track,newPos)
3681 def moveDownTrack(self,track):
3684 if self.isLastTrack(track):
3685 return
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.
3697 if len(l) == 0:
3698 return []
3699 elif len(l) == 1:
3700 return [l[0]]
3701 else:
3702 res = []
3703 for i in l:
3704 res.append( i )
3705 res.sort( self._cmpTracks )
3706 return res
3708 def canIPAccess( self, ip ):
3709 if not self.__ac.canIPAccess( ip ):
3710 return False
3711 for owner in self.getOwnerList():
3712 if not owner.canIPAccess(ip):
3713 return False
3714 return True
3716 def requireDomain( self, dom ):
3717 self.__ac.requireDomain( dom )
3718 self._notify('accessDomainAdded', dom)
3720 def freeDomain( self, dom ):
3721 self.__ac.freeDomain( dom )
3722 self._notify('accessDomainRemoved', dom)
3724 def getDomainList( self ):
3725 return self.__ac.getRequiredDomainList()
3727 def isProtected( self ):
3728 """Tells whether a conference is protected for accessing or not
3730 return self.__ac.isProtected()
3732 def getAccessProtectionLevel( self ):
3733 return self.__ac.getAccessProtectionLevel()
3735 def isItselfProtected( self ):
3736 return self.__ac.isItselfProtected()
3738 def hasAnyProtection( self ):
3739 """Tells whether a conference has any kind of protection over it:
3740 access or domain protection.
3742 if self.isProtected():
3743 return True
3744 if self.getDomainList():
3745 return True
3747 if self.getAccessProtectionLevel() == -1:
3748 return False
3750 for owner in self.getOwnerList():
3751 if owner.hasAnyProtection():
3752 return True
3754 return False
3756 def hasProtectedOwner( self ):
3757 return self.__ac._getFatherProtection()
3759 def setProtection( self, private ):
3761 Allows to change the conference access protection
3764 oldValue = 1 if self.isProtected() else -1
3766 self.__ac.setProtection( private )
3767 self.updateFullyPublic()
3768 self.cleanCategoryCache()
3770 if oldValue != private:
3771 # notify listeners
3772 self._notify('protectionChanged', oldValue, private)
3774 def grantAccess( self, prin ):
3775 self.__ac.grantAccess( prin )
3776 if isinstance(prin, MaKaC.user.Avatar):
3777 prin.linkTo(self, "access")
3779 def revokeAccess( self, prin ):
3780 self.__ac.revokeAccess( prin )
3781 if isinstance(prin, MaKaC.user.Avatar):
3782 prin.unlinkTo(self, "access")
3784 def canView( self, aw ):
3785 """tells whether the specified access wrappers has access to the current
3786 object or any of its parts"""
3787 if self.canAccess( aw ):
3788 return True
3789 for session in self.getSessionList():
3790 if session.canView( aw ):
3791 return True
3792 for contrib in self.getContributionList():
3793 if contrib.canView( aw ):
3794 return True
3795 return False
3797 def isAllowedToAccess( self, av):
3798 """tells if a user has privileges to access the current conference
3799 (independently that it is protected or not)
3801 if not av:
3802 return False
3803 if (av in self.getChairList()) or (self.__ac.canUserAccess( av )) or (self.canUserModify( av )):
3804 return True
3806 # if the conference is not protected by itself
3807 if not self.isItselfProtected():
3808 # then inherit behavior from parent category
3809 for owner in self.getOwnerList():
3810 if owner.isAllowedToAccess( av ):
3811 return True
3813 # track coordinators are also allowed to access the conference
3814 for track in self.getTrackList():
3815 if track.isCoordinator( av ):
3816 return True
3818 # paper reviewing team should be also allowed to access
3819 if self.getConfPaperReview().isInReviewingTeam(av):
3820 return True
3822 # video services managers are also allowed to access the conference
3823 if PluginsHolder().hasPluginType("Collaboration"):
3824 if self.getCSBookingManager().isPluginManagerOfAnyPlugin(av):
3825 return True
3826 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
3827 if RCCollaborationAdmin.hasRights(user=av) or \
3828 RCCollaborationPluginAdmin.hasRights(user=av, plugins ='any'):
3829 return True
3831 return False
3833 def canAccess( self, aw ):
3834 """Tells whether an access wrapper is allowed to access the current
3835 conference: when the conference is protected, only if the user is a
3836 chair or is granted to access the conference, when the client ip is
3837 not restricted.
3839 # Allow harvesters (Invenio, offline cache) to access
3840 # protected pages
3841 if self.__ac.isHarvesterIP(aw.getIP()):
3842 return True
3844 # Managers have always access
3845 if self.canUserModify(aw.getUser()):
3846 return True
3848 if self.isProtected():
3849 if self.isAllowedToAccess( aw.getUser() ):
3850 return True
3851 else:
3852 return self.canKeyAccess(aw)
3853 else:
3854 # Domain control is triggered just for PUBLIC events
3855 return self.canIPAccess(aw.getIP())
3857 def canKeyAccess( self, aw, key=None ):
3858 sess = aw.getSession()
3859 accessKey = self.getAccessKey()
3860 if accessKey != "" and sess:
3861 if key and key == accessKey:
3862 return True
3863 keys = sess.getVar("accessKeys")
3864 if keys != None:
3865 if keys.has_key(self.getUniqueId()):
3866 if keys[self.getUniqueId()] == accessKey:
3867 return True
3868 return False
3870 def canKeyModify( self, aw ):
3871 sess = aw.getSession()
3872 modifKey = self.getModifKey()
3873 if modifKey != "" and sess:
3874 keys = sess.getVar("modifKeys")
3875 if keys != None:
3876 if keys.has_key(self.id):
3877 if keys[self.id] == modifKey:
3878 return True
3879 return False
3881 def grantModification( self, prin, sendEmail=True ):
3882 email = None
3883 if isinstance(prin, ConferenceChair):
3884 email = prin.getEmail()
3885 elif isinstance(prin, str):
3886 email = prin
3887 if email != None:
3888 if email == "":
3889 return
3890 ah = AvatarHolder()
3891 results=ah.match({"email":email}, exact=1)
3892 #No registered user in Indico with that email
3893 if len(results) == 0:
3894 self.__ac.grantModificationEmail(email)
3895 if sendEmail and isinstance(prin, ConferenceChair):
3896 notif = pendingQueues._PendingConfManagerNotification( [prin] )
3897 mail.GenericMailer.sendAndLog( notif, self.getConference() )
3898 #The user is registered in Indico and is activated as well
3899 elif len(results) == 1 and results[0] is not None and results[0].isActivated():
3900 self.__ac.grantModification(results[0])
3901 results[0].linkTo(self, "manager")
3902 else:
3903 self.__ac.grantModification( prin )
3904 if isinstance(prin, MaKaC.user.Avatar):
3905 prin.linkTo(self, "manager")
3907 def revokeModification( self, prin ):
3908 self.__ac.revokeModification( prin )
3909 if isinstance(prin, MaKaC.user.Avatar):
3910 prin.unlinkTo(self, "manager")
3912 def canUserModify( self, av ):
3913 if av == None:
3914 return False
3915 if ( av == self.getCreator()) or self.getAccessController().canModify( av ):
3916 return True
3917 for owner in self.getOwnerList():
3918 if owner.canUserModify( av ):
3919 return True
3920 return False
3922 def canModify( self, aw ):
3923 """Tells whether an access wrapper is allowed to modify the current
3924 conference: only if the user is granted to modify the conference and
3925 he is accessing from an IP address which is not restricted.
3927 return self.canUserModify( aw.getUser() ) or self.canKeyModify( aw )
3929 def getManagerList( self ):
3930 return self.__ac.getModifierList()
3932 def addToRegistrars(self, av):
3933 self.getRegistrarList().append(av)
3934 self.notifyModification()
3935 if isinstance(av, MaKaC.user.Avatar):
3936 av.linkTo(self, "registrar")
3938 def removeFromRegistrars(self, av):
3939 self.getRegistrarList().remove(av)
3940 self.notifyModification()
3941 if isinstance(av, MaKaC.user.Avatar):
3942 av.unlinkTo(self, "registrar")
3944 def isRegistrar(self, av):
3945 if av == None:
3946 return False
3947 try:
3948 return av in self.getRegistrarList()
3949 except AttributeError:
3950 return False
3952 def getRegistrarList(self):
3953 try:
3954 return self.__registrars
3955 except AttributeError:
3956 self.__registrars = []
3957 return self.__registrars
3959 def canManageRegistration(self, av):
3960 return self.isRegistrar(av) or self.canUserModify(av)
3962 def getAllowedToAccessList( self ):
3963 return self.__ac.getAccessList()
3965 def addMaterial( self, newMat ):
3966 newMat.setId( str(self.__materialGenerator.newCount()) )
3967 newMat.setOwner( self )
3968 self.materials[ newMat.getId() ] = newMat
3969 self.notifyModification()
3971 def removeMaterial( self, mat ):
3972 if mat.getId() in self.materials.keys():
3973 mat.delete()
3974 self.materials[mat.getId()].setOwner(None)
3975 del self.materials[ mat.getId() ]
3976 self.notifyModification()
3977 elif mat.getId().lower() == 'paper':
3978 self.removePaper()
3979 self.notifyModification()
3980 elif mat.getId().lower() == 'slides':
3981 self.removeSlides()
3982 self.notifyModification()
3983 elif mat.getId().lower() == 'minutes':
3984 self.removeMinutes()
3985 self.notifyModification()
3986 elif mat.getId().lower() == 'video':
3987 self.removeVideo()
3988 self.notifyModification()
3989 elif mat.getId().lower() == 'poster':
3990 self.removePoster()
3991 self.notifyModification()
3993 def recoverMaterial(self, recMat):
3994 # Id must already be set in recMat.
3995 recMat.setOwner(self)
3996 self.materials[recMat.getId()] = recMat
3997 recMat.recover()
3998 self.notifyModification()
4000 def getMaterialRegistry(self):
4002 Return the correct material registry for this type
4004 from MaKaC.webinterface.materialFactories import ConfMFRegistry
4005 return ConfMFRegistry
4007 def getMaterialById( self, matId ):
4008 if matId.lower() == 'paper':
4009 return self.getPaper()
4010 elif matId.lower() == 'slides':
4011 return self.getSlides()
4012 elif matId.lower() == 'video':
4013 return self.getVideo()
4014 elif matId.lower() == 'poster':
4015 return self.getPoster()
4016 elif matId.lower() == 'minutes':
4017 return self.getMinutes()
4018 elif self.materials.has_key(matId):
4019 return self.materials[ matId ]
4020 return None
4022 def getMaterialList( self ):
4023 return self.materials.values()
4025 def getAllMaterialList( self ):
4026 l = self.getMaterialList()
4027 if self.getPaper():
4028 l.append( self.getPaper() )
4029 if self.getSlides():
4030 l.append( self.getSlides() )
4031 if self.getVideo():
4032 l.append( self.getVideo() )
4033 if self.getPoster():
4034 l.append( self.getPoster() )
4035 if self.getMinutes():
4036 l.append( self.getMinutes() )
4037 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
4038 return l
4040 def _getMaterialFiles(self, material):
4042 Adaption of _getMaterialFiles in WPTPLConferenceDisplay for desired format, objects
4043 seemed mutually exclusive hence use of similar logic here specific to Conference.
4045 files = []
4046 processed = []
4048 for res in material.getResourceList():
4049 try:
4050 ftype = res.getFileType()
4051 fname = res.getFileName()
4052 furl = urlHandlers.UHFileAccess.getURL(res)
4054 if fname in processed:
4055 fname = "%s - %s" % (fname, processed.count(fname))
4057 processed.append(res.getFileName())
4058 except:
4059 # If we are here then the resource is a Link object.
4060 fname, ftype, furl = str(res.getURL()), "link", str(res.getURL())
4061 fdesc = res.getDescription()
4062 files.append({'title': fname,
4063 'description': fdesc,
4064 'type': ftype,
4065 'url': furl})
4066 return files
4068 def getAllMaterialDict(self, child=None):
4070 This method iterates through the children of the conference, creating
4071 a dictionary which maps type to material link URLs.
4074 child = self if child is None else child
4076 node = {}
4077 node['title'] = child.getTitle()
4079 try:
4080 node['type'] = child.getType()
4081 except:
4082 # If we land here, it's a session which doesn't have 'getType'
4083 node['type'] = 'session'
4085 node['children'] = []
4086 node['material'] = []
4088 if node['type'] in ['conference', 'meeting']:
4089 for session in child.getSessionList():
4090 node['children'].append(self.getAllMaterialDict(session))
4092 for contrib in child.getContributionList():
4093 node['children'].append(self.getAllMaterialDict(contrib))
4095 for material in child.getAllMaterialList():
4096 files = self._getMaterialFiles(material)
4098 for f in files:
4099 materialNode = {}
4100 materialNode['type'] = 'material'
4101 materialNode['title'] = material.getTitle()
4103 if material.getTitle() != 'Minutes':
4104 materialNode['title'] += ' - ' + f['title']
4106 materialNode['materialType'] = f['type']
4107 materialNode['url'] = str(f['url'])
4109 node['material'].append(materialNode)
4111 return node
4113 def setPaper( self, newPaper ):
4114 if self.getPaper() != None:
4115 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
4116 self.paper=newPaper
4117 self.paper.setOwner( self )
4118 self.notifyModification()
4120 def removePaper( self ):
4121 if self.paper is None:
4122 return
4123 self.paper.delete()
4124 self.paper.setOwner(None)
4125 self.paper = None
4126 self.notifyModification()
4128 def recoverPaper(self, p):
4129 self.setPaper(p)
4130 p.recover()
4132 def getPaper( self ):
4133 try:
4134 if self.paper:
4135 pass
4136 except AttributeError:
4137 self.paper = None
4138 return self.paper
4140 def setSlides( self, newSlides ):
4141 if self.getSlides() != None:
4142 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
4143 self.slides=newSlides
4144 self.slides.setOwner( self )
4145 self.notifyModification()
4147 def removeSlides( self ):
4148 if self.slides is None:
4149 return
4150 self.slides.delete()
4151 self.slides.setOwner( None )
4152 self.slides= None
4153 self.notifyModification()
4155 def recoverSlides(self, s):
4156 self.setSlides(s)
4157 s.recover()
4159 def getSlides( self ):
4160 try:
4161 if self.slides:
4162 pass
4163 except AttributeError:
4164 self.slides = None
4165 return self.slides
4167 def setVideo( self, newVideo ):
4168 if self.getVideo() != None:
4169 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
4170 self.video=newVideo
4171 self.video.setOwner( self )
4172 self.notifyModification()
4174 def removeVideo( self ):
4175 if self.getVideo() is None:
4176 return
4177 self.video.delete()
4178 self.video.setOwner(None)
4179 self.video = None
4180 self.notifyModification()
4182 def recoverVideo(self, v):
4183 self.setVideo(v)
4184 v.recover()
4186 def getVideo( self ):
4187 try:
4188 if self.video:
4189 pass
4190 except AttributeError:
4191 self.video = None
4192 return self.video
4194 def setPoster( self, newPoster ):
4195 if self.getPoster() != None:
4196 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
4197 self.poster=newPoster
4198 self.poster.setOwner( self )
4199 self.notifyModification()
4201 def removePoster( self ):
4202 if self.getPoster() is None:
4203 return
4204 self.poster.delete()
4205 self.poster.setOwner(None)
4206 self.poster = None
4207 self.notifyModification()
4209 def recoverPoster(self, p):
4210 self.setPoster(p)
4211 p.recover()
4213 def getPoster( self ):
4214 try:
4215 if self.poster:
4216 pass
4217 except AttributeError:
4218 self.poster = None
4219 return self.poster
4221 def setMinutes( self, newMinutes ):
4222 if self.getMinutes() != None:
4223 raise MaKaCError( _("The Minutes for this conference has already been set"))
4224 self.minutes=newMinutes
4225 self.minutes.setOwner( self )
4226 self.notifyModification()
4228 def createMinutes( self ):
4229 if self.getMinutes() != None:
4230 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
4231 self.minutes = Minutes()
4232 self.minutes.setOwner( self )
4233 self.notifyModification()
4234 return self.minutes
4236 def removeMinutes( self ):
4237 if self.getMinutes() is None:
4238 return
4239 self.minutes.delete()
4240 self.minutes.setOwner( None )
4241 self.minutes = None
4242 self.notifyModification()
4244 def recoverMinutes(self, min):
4245 self.removeMinutes() # To ensure that the current minutes are put in
4246 # the trash can.
4247 self.minutes = min
4248 self.minutes.setOwner( self )
4249 min.recover()
4250 self.notifyModification()
4251 return self.minutes
4253 def getMinutes( self ):
4254 #To be removed
4255 try:
4256 if self.minutes:
4257 pass
4258 except AttributeError, e:
4259 self.minutes = None
4260 return self.minutes
4262 def _setSchedule( self, sch=None ):
4263 self.__schedule=ConferenceSchedule(self)
4264 for session in self.getSessionList():
4265 for slot in session.getSlotList():
4266 self.__schedule.addEntry(slot.getConfSchEntry())
4268 def getSchedule( self ):
4269 try:
4270 if not self.__schedule:
4271 self._setSchedule()
4272 except AttributeError, e:
4273 self._setSchedule()
4274 return self.__schedule
4276 def fit( self ):
4277 sch = self.getSchedule()
4279 sDate = sch.calculateStartDate()
4280 eDate = sch.calculateEndDate()
4281 self.setStartDate(sDate)
4282 self.setEndDate(eDate)
4284 def fitSlotsOnDay( self, day ):
4285 for entry in self.getSchedule().getEntriesOnDay(day) :
4286 if isinstance(entry.getOwner(), SessionSlot) :
4287 entry.getOwner().fit()
4289 def getDisplayMgr(self):
4291 Return the display manager for the conference
4293 from MaKaC.webinterface import displayMgr
4294 return displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self)
4296 def getDefaultStyle( self ):
4297 return self.getDisplayMgr().getDefaultStyle()
4299 def clone( self, startDate, options, eventManager=None, userPerformingClone = None ):
4300 # startDate must be in the timezone of the event (to avoid problems with daylight-saving times)
4301 cat = self.getOwnerList()[0]
4302 managing = options.get("managing",None)
4303 if managing is not None:
4304 creator = managing
4305 else:
4306 creator = self.getCreator()
4307 conf = cat.newConference(creator)
4308 if managing is not None :
4309 conf.grantModification(managing)
4310 conf.setTitle(self.getTitle())
4311 conf.setDescription(self.getDescription())
4312 conf.setTimezone(self.getTimezone())
4313 for loc in self.getLocationList():
4314 if loc is not None:
4315 conf.addLocation(loc.clone())
4316 if self.getRoom() is not None:
4317 conf.setRoom(self.getRoom().clone())
4318 startDate = timezone(self.getTimezone()).localize(startDate).astimezone(timezone('UTC'))
4319 timeDelta = startDate - self.getStartDate()
4320 endDate = self.getEndDate() + timeDelta
4321 conf.setDates( startDate, endDate, moveEntries=1 )
4322 conf.setContactInfo(self.getContactInfo())
4323 conf.setChairmanText(self.getChairmanText())
4324 conf.setVisibility(self.getVisibility())
4325 conf.setSupportEmail(self.getSupportEmail())
4326 conf.setReportNumberHolder(self.getReportNumberHolder().clone(self))
4327 for ch in self.getChairList():
4328 conf.addChair(ch.clone())
4329 ContextManager.setdefault("clone.unique_id_map", {})[self.getUniqueId()] = conf.getUniqueId()
4330 # Display Manager
4331 from MaKaC.webinterface import displayMgr
4332 selfDispMgr=displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self)
4333 selfDispMgr.clone(conf)
4334 # Contribution Types' List (main detailes of the conference)
4335 for t in self.getContribTypeList() :
4336 conf.addContribType(t.clone(conf))
4337 for item in self.getSections() :
4338 conf._sections.append(item)
4339 if options.get("sessions", False):
4340 for entry in self.getSchedule().getEntries():
4341 if isinstance(entry,BreakTimeSchEntry):
4342 conf.getSchedule().addEntry(entry.clone(conf))
4343 db_root = DBMgr.getInstance().getDBConnection().root()
4344 if db_root.has_key( "webfactoryregistry" ):
4345 confRegistry = db_root["webfactoryregistry"]
4346 else:
4347 confRegistry = OOBTree.OOBTree()
4348 db_root["webfactoryregistry"] = confRegistry
4349 meeting=False
4350 # if the event is a meeting or a lecture
4351 if confRegistry.get(str(self.getId()), None) is not None :
4352 meeting=True
4353 confRegistry[str(conf.getId())] = confRegistry[str(self.getId())]
4354 # if it's a conference, no web factory is needed
4355 # Tracks in a conference
4356 if options.get("tracks",False) :
4357 for tr in self.getTrackList() :
4358 conf.addTrack(tr.clone(conf))
4359 # Meetings' and conferences' sessions cloning
4360 if options.get("sessions",False) :
4361 for s in self.getSessionList() :
4362 newSes = s.clone(timeDelta, conf, options)
4363 ContextManager.setdefault("clone.unique_id_map", {})[s.getUniqueId()] = newSes.getUniqueId()
4364 conf.addSession(newSes)
4365 # Materials' cloning
4366 if options.get("materials",False) :
4367 for m in self.getMaterialList() :
4368 conf.addMaterial(m.clone(conf))
4369 if self.getPaper() is not None:
4370 conf.setPaper(self.getPaper().clone(conf))
4371 if self.getSlides() is not None:
4372 conf.setSlides(self.getSlides().clone(conf))
4373 if self.getVideo() is not None:
4374 conf.setVideo(self.getVideo().clone(conf))
4375 if self.getPoster() is not None:
4376 conf.setPoster(self.getPoster().clone(conf))
4377 if self.getMinutes() is not None:
4378 conf.setMinutes(self.getMinutes().clone(conf))
4379 # access and modification keys
4380 if options.get("keys", False) :
4381 conf.setAccessKey(self.getAccessKey())
4382 conf.setModifKey(self.getModifKey())
4383 # Access Control cloning
4384 if options.get("access",False) :
4385 conf.setProtection(self.getAccessController()._getAccessProtection())
4386 for mgr in self.getManagerList() :
4387 conf.grantModification(mgr)
4388 for user in self.getAllowedToAccessList() :
4389 conf.grantAccess(user)
4390 for right in self.getSessionCoordinatorRights():
4391 conf.addSessionCoordinatorRight(right)
4392 for domain in self.getDomainList():
4393 conf.requireDomain(domain)
4394 # conference's registration form
4395 if options.get("registration",False) :
4396 conf.setRegistrationForm(self.getRegistrationForm().clone(conf))
4398 # conference's evaluation
4399 if options.get("evaluation",False) :
4400 #Modify this, if you have now many evaluations.
4401 #You will have to clone every evaluations of this conference.
4402 conf.setEvaluations([self.getEvaluation().clone(conf)])
4404 #conference's abstracts
4405 if options.get("abstracts",False) :
4406 conf.abstractMgr = self.abstractMgr.clone(conf)
4407 # conference's alerts
4408 if options.get("alerts",False) :
4409 for alarm in self.getAlarmList() :
4410 # for absoulte alarms, only clone alarms that will happen in the future
4411 if alarm._relative is not None or alarm.getStartOn() > nowutc():
4412 # .clone takes care of enqueuing it
4413 alarm.clone(conf)
4414 # Meetings' and conferences' contributions cloning
4415 if options.get("contributions",False) :
4416 sch = conf.getSchedule()
4417 for cont in self.getContributionList():
4418 if cont.getSession() is None :
4419 if not meeting:
4420 nc = cont.clone(conf, options, timeDelta)
4421 conf.addContribution(nc)
4422 if cont.isScheduled() :
4423 sch.addEntry(nc.getSchEntry())
4424 ContextManager.setdefault("clone.unique_id_map", {})[cont.getUniqueId()] = nc.getUniqueId()
4425 elif cont.isScheduled():
4426 # meetings...only scheduled
4427 nc = cont.clone(conf, options, timeDelta)
4428 conf.addContribution(nc)
4429 sch.addEntry(nc.getSchEntry())
4430 ContextManager.setdefault("clone.unique_id_map", {})[cont.getUniqueId()] = nc.getUniqueId()
4431 # Participants' module settings and list cloning
4432 if options.get("participants",False) :
4433 self.getParticipation().clone(conf, options, eventManager)
4434 conf.notifyModification()
4436 #we inform the plugins in case they want to add anything to the new conference
4437 self._notify('cloneEvent', {'conf': conf, 'user': userPerformingClone, 'options': options})
4438 return conf
4440 def newAlarm(self, when, enqueue=True):
4442 if type(when) == timedelta:
4443 relative = when
4444 dtStart = None
4445 else:
4446 relative = None
4447 dtStart = when
4449 confRelId = self._getNextAlarmId()
4450 al = tasks.AlarmTask(self, confRelId,
4451 startDateTime=dtStart,
4452 relative=relative)
4454 self.addAlarm(al, enqueue)
4455 return al
4457 def removeAlarm(self, alarm):
4458 confRelId = alarm.getConfRelativeId()
4460 if confRelId in self.alarmList:
4461 del self.alarmList[confRelId]
4462 self._p_changed = 1
4464 tl = Client()
4465 tl.dequeue(alarm)
4466 else:
4467 raise Exception("alarm not in list!")
4469 def _getNextAlarmId(self):
4470 return self.__alarmCounter.newCount()
4472 def addAlarm(self, alarm, enqueue = True):
4473 if enqueue:
4474 tl = Client()
4475 tl.enqueue(alarm)
4477 self.alarmList[alarm.getConfRelativeId()] = alarm
4478 self._p_changed = 1
4480 def recoverAlarm(self, alarm):
4481 self.addAlarm(alarm)
4482 alarm.conf = self
4483 alarm.recover()
4485 def getAlarmList(self):
4486 return self.alarmList.values()
4488 def getAlarmById(self, id):
4489 """For given id returns corresponding Alarm or None if not found."""
4490 return self.alarmList.get(id, None)
4492 def getCoordinatedTracks( self, av ):
4493 """Returns a list with the tracks for which a user is coordinator.
4495 try:
4496 if self._trackCoordinators:
4497 pass
4498 except AttributeError:
4499 self._trackCoordinators = TCIndex()
4500 self.notifyModification()
4501 return self._trackCoordinators.getTracks( av )
4503 def addTrackCoordinator( self, track, av ):
4504 """Makes a user become coordinator for a track.
4506 try:
4507 if self._trackCoordinators:
4508 pass
4509 except AttributeError:
4510 self._trackCoordinators = TCIndex()
4511 self.notifyModification()
4512 if track in self.program:
4513 track.addCoordinator( av )
4514 self._trackCoordinators.indexCoordinator( av, track )
4515 self.notifyModification()
4517 def removeTrackCoordinator( self, track, av ):
4518 """Removes a user as coordinator for a track.
4520 try:
4521 if self._trackCoordinators:
4522 pass
4523 except AttributeError:
4524 self._trackCoordinators = TCIndex()
4525 self.notifyModification()
4526 if track in self.program:
4527 track.removeCoordinator( av )
4528 self._trackCoordinators.unindexCoordinator( av, track )
4529 self.notifyModification()
4531 def _rebuildAuthorIndex(self):
4532 self._authorIdx=AuthorIndex()
4533 for contrib in self.getContributionList():
4534 if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn):
4535 for auth in contrib.getAuthorList():
4536 self._authorIdx.index(auth)
4538 def getAuthorIndex(self):
4539 try:
4540 if self._authorIdx:
4541 pass
4542 except AttributeError:
4543 self._rebuildAuthorIndex()
4544 return self._authorIdx
4546 def indexAuthor(self,auth):
4547 c=auth.getContribution()
4548 if c.isAuthor(auth):
4549 if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4550 self.getAuthorIndex().index(auth)
4551 if c.isPrimaryAuthor(auth):
4552 self._getPrimAuthIndex().index(auth)
4554 def unindexAuthor(self,auth):
4555 c=auth.getContribution()
4556 if c.isAuthor(auth):
4557 self.getAuthorIndex().unindex(auth)
4558 if c.isPrimaryAuthor(auth):
4559 self._getPrimAuthIndex().unindex(auth)
4561 def _rebuildSpeakerIndex(self):
4562 self._speakerIdx=AuthorIndex()
4563 for contrib in self.getContributionList():
4564 if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn):
4565 for auth in contrib.getSpeakerList():
4566 self._speakerIdx.index(auth)
4567 for subcontrib in contrib.getSubContributionList():
4568 for auth in subcontrib.getSpeakerList():
4569 self._speakerIdx.index(auth)
4571 def getSpeakerIndex(self):
4572 try:
4573 if self._speakerIdx:
4574 pass
4575 except AttributeError:
4576 self._rebuildSpeakerIndex()
4577 return self._speakerIdx
4579 def indexSpeaker(self,auth):
4580 c=auth.getContribution()
4581 if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4582 self.getSpeakerIndex().index(auth)
4584 def unindexSpeaker(self,auth):
4585 c=auth.getContribution()
4586 if c and not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4587 self.getSpeakerIndex().unindex(auth)
4589 def getRegistrationForm(self):
4590 try:
4591 if self._registrationForm is None:
4592 self._registrationForm = registration.RegistrationForm(self)
4593 except AttributeError,e:
4594 self._registrationForm = registration.RegistrationForm(self)
4595 return self._registrationForm
4597 def setRegistrationForm(self,rf):
4598 self._registrationForm = rf
4599 rf.setConference(self)
4601 def removeRegistrationForm(self):
4602 try:
4603 self._registrationForm.delete()
4604 self._registrationForm.setConference(None)
4605 self._registrationForm = None
4606 except AttributeError:
4607 self._registrationForm = None
4609 def recoverRegistrationForm(self, rf):
4610 self.setRegistrationForm(rf)
4611 rf.recover()
4613 def getEvaluation(self, id=0):
4614 ############################################################################
4615 #For the moment only one evaluation per conference is used. #
4616 #In the future if there are more than one evaluation, modify this function.#
4617 ############################################################################
4618 """ Return the evaluation given by its ID or None if nothing found.
4619 Params:
4620 id -- id of the wanted evaluation
4622 for evaluation in self.getEvaluations():
4623 if str(evaluation.getId()) == str(id) :
4624 return evaluation
4625 if HelperMaKaCInfo.getMaKaCInfoInstance().isDebugActive():
4626 raise Exception(_("Error with id: expected '%s', found '%s'.")%(id, self.getEvaluations()[0].getId()))
4627 else:
4628 return self.getEvaluations()[0]
4630 def getEvaluations(self):
4631 if not hasattr(self, "_evaluations"):
4632 self._evaluations = [Evaluation(self)]
4633 return self._evaluations
4635 def setEvaluations(self, evaluationsList):
4636 self._evaluations = evaluationsList
4637 for evaluation in self._evaluations:
4638 evaluation.setConference(self)
4640 def removeEvaluation(self, evaluation):
4641 """remove the given evaluation from its evaluations."""
4642 evaluations = self.getEvaluations()
4643 if evaluations.count(evaluation)>0:
4644 evaluations.remove(evaluation)
4645 evaluation.removeReferences()
4646 self.notifyModification()
4648 def removeAllEvaluations(self):
4649 for evaluation in self.getEvaluations():
4650 evaluation.removeReferences()
4651 self._evaluations = []
4652 self.notifyModification()
4654 def _getEvaluationCounter(self):
4655 if not hasattr(self, "_evaluationCounter"):
4656 self._evaluationCounter = Counter()
4657 return self._evaluationCounter
4659 ## Videoconference bookings related
4660 def getBookings(self):
4661 try:
4662 if self._bookings:
4663 pass
4664 except AttributeError, e:
4665 self._bookings = {}
4666 self.notifyModification()
4667 return self._bookings
4669 def getBookingsList(self, sort = False):
4670 bl = self.getBookings().values()
4671 if sort:
4672 bl.sort()
4673 return bl
4675 def _getBookingGenerator(self):
4676 try:
4677 return self._bookingGenerator
4678 except AttributeError, e:
4679 self._bookingGenerator = Counter()
4680 return self._bookingGenerator
4682 def getNewBookingId(self):
4683 return str(self._getBookingGenerator().newCount())
4685 def addBooking(self, bp):
4686 if (bp.getId() == ""):
4687 bp.setId(self.getNewBookingId())
4688 self.getBookings()[bp.getId()] = bp
4689 self.notifyModification()
4691 def hasBooking(self,booking):
4692 return booking.getConference()==self and \
4693 self.getBookings().has_key(booking.getId())
4695 def removeBooking(self, booking):
4696 if self.hasBooking(booking):
4697 deletion= booking.deleteBooking()
4698 if deletion[0] != 1:
4699 del self.getBookings()[booking.getId()]
4700 self.notifyModification()
4701 return deletion
4703 def getBookingByType(self, type):
4704 if self.getBookings().has_key(type):
4705 return self.getBookings()[type]
4706 return None
4708 def getBookingById(self, id):
4709 if self.getBookings().has_key(id):
4710 return self.getBookings()[id]
4711 return None
4713 ## End of Videoconference bookings related
4715 def getModPay(self):
4716 try:
4717 if self._modPay is None:
4718 self._modPay= epayment.EPayment(self)
4719 except AttributeError,e:
4720 self._modPay= epayment.EPayment(self)
4721 return self._modPay
4723 def getRegistrants(self):
4724 try:
4725 if self._registrants:
4726 pass
4727 except AttributeError, e:
4728 self._registrants = {}
4729 self.notifyModification()
4730 return self._registrants
4732 def getRegistrantsByEmail(self):
4733 try:
4734 if self._registrantsByEmail:
4735 pass
4736 except AttributeError, e:
4737 self._registrantsByEmail = self._createRegistrantsByEmail()
4738 self.notifyModification()
4739 return self._registrantsByEmail
4741 def _createRegistrantsByEmail(self):
4742 dicByEmail = {}
4743 for r in self.getRegistrantsList():
4744 dicByEmail[r.getEmail()] = r
4745 return dicByEmail
4747 def getRegistrantsList(self, sort = False):
4748 rl = self.getRegistrants().values()
4749 if sort:
4750 rl.sort(registration.Registrant._cmpFamilyName)
4751 return rl
4753 def _getRegistrantGenerator(self):
4754 try:
4755 return self._registrantGenerator
4756 except AttributeError, e:
4757 self._registrantGenerator = Counter()
4758 return self._registrantGenerator
4760 def addRegistrant(self, rp):
4761 rp.setId( str(self._getRegistrantGenerator().newCount()) )
4762 rp.setOwner( self )
4763 self.getRegistrants()[rp.getId()] = rp
4764 self.notifyModification()
4766 def updateRegistrantIndexByEmail(self, rp, newEmail):
4767 oldEmail = rp.getEmail()
4768 if oldEmail != newEmail:
4769 if self.getRegistrantsByEmail().has_key(oldEmail):
4770 del self.getRegistrantsByEmail()[oldEmail]
4771 self.getRegistrantsByEmail()[newEmail] = rp
4772 self.notifyModification()
4774 def hasRegistrant(self,rp):
4775 return rp.getConference()==self and \
4776 self.getRegistrants().has_key(rp.getId())
4778 def hasRegistrantByEmail(self, email):
4779 # Return true if there is someone with the email of the param "email"
4780 return self.getRegistrantsByEmail().has_key(email)
4782 def removeRegistrant(self, id):
4783 part = self.getRegistrants()[id]
4784 self._registrationForm.notifyRegistrantRemoval(self.getRegistrants()[id])
4785 del self.getRegistrantsByEmail()[self.getRegistrantById(id).getEmail()]
4786 del self.getRegistrants()[id]
4787 if part.getAvatar() is not None:
4788 part.getAvatar().removeRegistrant(part)
4789 TrashCanManager().add(part)
4790 self.notifyModification()
4792 def getRegistrantById(self, id):
4793 if self.getRegistrants().has_key(id):
4794 return self.getRegistrants()[id]
4795 return None
4797 def _getPrimAuthIndex(self):
4798 try:
4799 if self._primAuthIdx:
4800 pass
4801 except AttributeError:
4802 self._primAuthIdx=_PrimAuthIdx(self)
4803 return self._primAuthIdx
4805 def getContribsMatchingAuth(self,query,onlyPrimary=True):
4806 if str(query).strip()=="":
4807 return self.getContributionList()
4808 res=self._getPrimAuthIndex().match(query)
4809 return [self.getContributionById(id) for id in res]
4811 def getCoordinatedSessions( self, av ):
4812 """Returns a list with the sessions for which a user is coordinator.
4814 try:
4815 if self._sessionCoordinators:
4816 pass
4817 except AttributeError:
4818 self._sessionCoordinators = SCIndex()
4819 sessions = self._sessionCoordinators.getSessions( av )
4820 for session in self.getSessionList():
4821 if session not in sessions and av != None:
4822 for email in av.getEmails():
4823 if email in session.getCoordinatorEmailList():
4824 sessions.append(session)
4825 break
4826 return sessions
4828 def getManagedSession( self, av ):
4829 ls = []
4830 for session in self.getSessionList():
4831 pending = False
4832 if av != None:
4833 for email in av.getEmails():
4834 if email in session.getAccessController().getModificationEmail():
4835 pending = True
4836 break
4837 if av in session.getManagerList() or pending:
4838 ls.append(session)
4839 return ls
4841 def addSessionCoordinator(self,session,av):
4842 """Makes a user become coordinator for a session.
4844 try:
4845 if self._sessionCoordinators:
4846 pass
4847 except AttributeError:
4848 self._sessionCoordinators = SCIndex()
4849 if self.sessions.has_key(session.getId()):
4850 session.addCoordinator(av)
4851 self._sessionCoordinators.index(av,session)
4853 def removeSessionCoordinator( self, session, av ):
4854 """Removes a user as coordinator for a session.
4856 try:
4857 if self._sessionCoordinators:
4858 pass
4859 except AttributeError:
4860 self._sessionCoordinators = SCIndex()
4861 if self.sessions.has_key(session.getId()):
4862 session.removeCoordinator( av )
4863 self._sessionCoordinators.unindex(av,session)
4865 def _getSubmitterIdx(self):
4866 try:
4867 return self._submitterIdx
4868 except AttributeError:
4869 self._submitterIdx=SubmitterIndex()
4870 return self._submitterIdx
4872 def addContribSubmitter(self,contrib,av):
4873 self._getSubmitterIdx().index(av,contrib)
4875 def removeContribSubmitter(self,contrib,av):
4876 self._getSubmitterIdx().unindex(av,contrib)
4878 def getContribsForSubmitter(self,av):
4879 return self._getSubmitterIdx().getContributions(av)
4881 def getBOAConfig(self):
4882 try:
4883 if self._boa:
4884 pass
4885 except AttributeError:
4886 self._boa=BOAConfig(self)
4887 return self._boa
4889 def getSessionCoordinatorRights(self):
4890 try:
4891 if self._sessionCoordinatorRights:
4892 pass
4893 except AttributeError, e:
4894 self._sessionCoordinatorRights = []
4895 self.notifyModification()
4896 return self._sessionCoordinatorRights
4898 def hasSessionCoordinatorRight(self, right):
4899 return right in self.getSessionCoordinatorRights()
4901 def addSessionCoordinatorRight(self, right):
4902 if SessionCoordinatorRights().hasRight(right) and not self.hasSessionCoordinatorRight(right):
4903 self._sessionCoordinatorRights.append(right)
4904 self.notifyModification()
4906 def removeSessionCoordinatorRight(self, right):
4907 if SessionCoordinatorRights().hasRight(right) and self.hasSessionCoordinatorRight(right):
4908 self._sessionCoordinatorRights.remove(right)
4909 self.notifyModification()
4911 def getSections(self):
4912 try:
4913 if self._sections:
4914 pass
4915 except AttributeError, e:
4916 self._sections = ConfSectionsMgr().getSectionKeys()
4917 self.notifyModification()
4918 return self._sections
4920 def hasEnabledSection(self, section):
4921 # This hack is there since there is no more enable/disable boxes
4922 # in the conference managment area corresponding to those features.
4923 # Until the managment area is improved to get a more user-friendly
4924 # way of enabling/disabling those features, we always make them
4925 # available for the time being, but we keep the previous code for
4926 # further improvements
4927 return True
4929 def enableSection(self, section):
4930 if ConfSectionsMgr().hasSection(section) and not self.hasEnabledSection(section):
4931 self._sections.append(section)
4932 self.notifyModification()
4934 def disableSection(self, section):
4935 if ConfSectionsMgr().hasSection(section) and self.hasEnabledSection(section):
4936 self._sections.remove(section)
4937 self.notifyModification()
4939 def getPendingQueuesMgr(self):
4940 try:
4941 if self._pendingQueuesMgr:
4942 pass
4943 except AttributeError, e:
4944 self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self)
4945 return self._pendingQueuesMgr
4947 def getAccessController(self):
4948 return self.__ac
4950 def _cmpTitle( c1, c2 ):
4951 o1 = c1.getTitle().lower().strip()
4952 o2 = c2.getTitle().lower().strip()
4953 return cmp( o1, o2 )
4954 _cmpTitle=staticmethod(_cmpTitle)
4956 def getReportNumberHolder(self):
4957 try:
4958 if self._reportNumberHolder:
4959 pass
4960 except AttributeError, e:
4961 self._reportNumberHolder=ReportNumberHolder(self)
4962 return self._reportNumberHolder
4964 def setReportNumberHolder(self, rnh):
4965 self._reportNumberHolder=rnh
4967 def getBadgeTemplateManager(self):
4968 try:
4969 if self.__badgeTemplateManager:
4970 pass
4971 except AttributeError:
4972 self.__badgeTemplateManager = BadgeTemplateManager(self)
4973 return self.__badgeTemplateManager
4975 def setBadgeTemplateManager(self, badgeTemplateManager):
4976 self.__badgeTemplateManager = badgeTemplateManager
4978 def getPosterTemplateManager(self):
4979 try:
4980 if self.__posterTemplateManager:
4981 pass
4982 except AttributeError:
4983 self.__posterTemplateManager = PosterTemplateManager(self)
4985 return self.__posterTemplateManager
4987 def setPosterTemplateManager(self, posterTemplateManager):
4988 self.__posterTemplateManager = posterTemplateManager
4990 def getCSBookingManager(self):
4992 if PluginsHolder().hasPluginType("Collaboration"):
4993 if not hasattr(self, "_CSBookingManager"):
4994 from MaKaC.plugins.Collaboration.base import CSBookingManager
4995 self._CSBookingManager = CSBookingManager(self)
4996 return self._CSBookingManager
4997 else:
4998 return None
5001 class DefaultConference(Conference):
5002 """ 'default' conference, which stores the
5003 default templates for posters and badges
5006 def indexConf(self):
5007 pass
5009 def __init__(self):
5010 """ Default constructor
5012 try:
5013 Conference.__init__(self, AdminList.getInstance().getList()[0], "default")
5014 except IndexError:
5015 raise MaKaCError(_("""There are no admin users. The "default" conference that stores the template cannot be created.
5016 Please add at least 1 user to the admin list."""))
5019 class ConferenceHolder( ObjectHolder ):
5020 """Specialised ObjectHolder dealing with conference objects. It gives a
5021 common entry point and provides simple methods to access and
5022 maintain the collection of stored conferences (DB).
5024 idxName = "conferences"
5025 counterName = "CONFERENCE"
5027 def _newId( self ):
5028 id = ObjectHolder._newId( self )
5029 return "%s"%id
5031 def getById( self, id, quiet=False ):
5032 """returns an object from the index which id corresponds to the one
5033 which is specified.
5036 if (id == "default"):
5037 return CategoryManager().getDefaultConference()
5039 if type(id) is int:
5040 id = str(id)
5041 if self._getIdx().has_key(str(id)):
5042 return self._getIdx()[str(id)]
5043 elif quiet:
5044 return None
5045 else:
5046 raise NoReportError( _("The specified event with id \"%s\" does not exist or has been deleted.") % escape_html(str(id)) )
5048 class ConfSectionsMgr:
5050 def __init__(self):
5051 self._sections = {
5052 "cfa": "Call for abstracts",
5053 "paperReviewing" : "Paper Reviewing",
5054 "evaluation": "Evaluation Form",
5055 "videoconference": "Videoconference", # only for meetings
5056 "collaboration": "Collaboration", # only for meetings
5057 "regForm": "Registration Form"
5060 def hasSection(self, s):
5061 # This hack is there since there is no more enable/disable boxes
5062 # in the conference managment area corresponding to those features.
5063 # Until the managment area is improved to get a more user-friendly
5064 # way of enabling/disabling those features, we always make them
5065 # available in the side menu for the time being, but we keep
5066 # the previous code for further improvements
5067 #return self._sections.has_key(s)
5068 return True
5070 def getSections(self):
5071 return self._sections
5073 def getSectionList(self, sort=False):
5074 l=self._sections.values()
5075 if sort:
5076 l.sort()
5077 return l
5079 def getSectionKeys(self, sort=False):
5080 l=self._sections.keys()
5081 if sort:
5082 l.sort()
5083 return l
5085 def getSection(self, id):
5086 if self._sections.has_key(id):
5087 return self._sections[id]
5088 return None
5091 class Observer(object):
5092 """ Base class for Observer objects.
5093 Inheriting classes should overload the following boolean class attributes:
5094 _shouldBeTitleNotified
5095 _shouldBeDateChangeNotified
5096 _shouldBeLocationChangeNotified
5097 _shouldBeDeletionNotified
5098 And set them to True if they want to be notified of the corresponding event.
5099 In that case, they also have to implement the corresponding methods:
5100 _notifyTitleChange (for title notification)
5101 _notifyEventDateChanges and _notifyTimezoneChange (for date / timezone notification)
5102 _shouldBeLocationChangeNotified (for location notification)
5103 _notifyDeletion (for deletion notification).
5104 The interface for those methods is also specified in this class. If the corresponding
5105 class attribute is set to False but the method is not implemented, an exception will be thrown.
5107 _shouldBeTitleNotified = False
5108 _shouldBeDateChangeNotified = False
5109 _shouldBeLocationChangeNotified = False
5110 _shouldBeDeletionNotified = False
5112 def getObserverName(self):
5113 name = "'Observer of class" + self.__class__.__name__
5114 try:
5115 conf = self.getOwner()
5116 name = name + " of event " + conf.getId() + "'"
5117 except AttributeError:
5118 pass
5119 return name
5121 def notifyTitleChange(self, oldTitle, newTitle):
5122 if self._shouldBeTitleNotified:
5123 self._notifyTitleChange(oldTitle, newTitle)
5125 def notifyEventDateChanges(self, oldStartDate = None, newStartDate = None, oldEndDate = None, newEndDate = None):
5126 if self._shouldBeDateChangeNotified:
5127 self._notifyEventDateChanges(oldStartDate, newStartDate, oldEndDate, newEndDate)
5129 def notifyTimezoneChange(self, oldTimezone, newTimezone):
5130 if self._shouldBeDateChangeNotified:
5131 self._notifyTimezoneChange(oldTimezone, newTimezone)
5133 def notifyLocationChange(self, newLocation):
5134 if self._shouldBeLocationChangeNotified:
5135 self._notifyLocationChange(newLocation)
5137 def notifyDeletion(self):
5138 if self._shouldBeDeletionNotified:
5139 self._notifyDeletion()
5141 def _notifyTitleChange(self, oldTitle, newTitle):
5142 """ To be implemented by inheriting classes
5143 Notifies the observer that the Conference object's title has changed
5145 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method _notifyTitleChange")
5147 def _notifyEventDateChanges(self, oldStartDate, newStartDate, oldEndDate, newEndDate):
5148 """ To be implemented by inheriting classes
5149 Notifies the observer that the start and / or end dates of the object it is attached to has changed.
5150 If the observer finds any problems during whatever he needs to do as a consequence of
5151 the event dates changing, he should write strings describing the problems
5152 in the 'dateChangeNotificationProblems' context variable (which is a list of strings).
5154 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyStartDateChange")
5156 def _notifyTimezoneChange(self, oldTimezone, newTimezone):
5157 """ To be implemented by inheriting classes.
5158 Notifies the observer that the end date of the object it is attached to has changed.
5159 This method has to return a list of strings describing problems encountered during
5160 whatever the DateChangeObserver object does as a consequence of the notification.
5161 If there are no problems, the DateChangeObserver should return an empty list.
5163 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTimezoneChange")
5165 def _notifyLocationChange(self):
5166 """ To be implemented by inheriting classes
5167 Notifies the observer that the location of the object it is attached to has changed.
5169 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyLocationChange")
5171 def _notifyDeletion(self):
5172 """ To be implemented by inheriting classes
5173 Notifies the observer that the Conference object it is attached to has been deleted
5175 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyDeletion")
5177 class TitleChangeObserver(Observer):
5178 """ Base class for objects who want to be notified of a Conference object being deleted.
5179 Inheriting classes have to implement the notifyTitleChange method, and probably the __init__ method too.
5182 def notifyTitleChange(self, oldTitle, newTitle):
5183 """ To be implemented by inheriting classes
5184 Notifies the observer that the Conference object's title has changed
5186 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTitleChange")
5189 class SessionChair(ConferenceParticipation):
5191 def __init__(self):
5192 self._session=None
5193 self._id=""
5194 ConferenceParticipation.__init__(self)
5196 def _notifyModification( self ):
5197 if self._session != None:
5198 self._session.notifyModification()
5200 def clone(self):
5201 chair = SessionChair()
5202 chair.setValues(self.getValues())
5203 return chair
5205 def getSession(self):
5206 return self._session
5208 def getConference(self):
5209 s=self.getSession()
5210 if s is None:
5211 return None
5212 return s.getConference()
5214 def includeInSession(self,session,id):
5215 if self.getSession()==session and self.getId()==id.strip():
5216 return
5217 self._session=session
5218 self._id=id
5220 def delete( self ):
5221 self._session=None
5222 ConferenceParticipation.delete(self)
5224 def getLocator(self):
5225 if self.getSession() is None:
5226 return None
5227 loc=self.getSession().getLocator()
5228 loc["convId"]=self.getId()
5229 return loc
5231 def isSessionManager(self):
5232 # pendings managers
5233 if self.getEmail() in self._session.getAccessController().getModificationEmail():
5234 return True
5235 # managers list
5236 for manager in self._session.getManagerList():
5237 if self.getEmail() == manager.getEmail():
5238 return True
5239 return False
5241 def isSessionCoordinator(self):
5242 # pendings coordinators
5243 if self.getEmail() in self._session.getConference().getPendingQueuesMgr().getPendingCoordinatorsKeys():
5244 return True
5245 # coordinator list
5246 for coord in self._session.getCoordinatorList():
5247 if self.getEmail() == coord.getEmail():
5248 return True
5249 return False
5252 class SlotChair(ConferenceParticipation):
5254 def __init__(self):
5255 self._slot=None
5256 self._id=""
5257 ConferenceParticipation.__init__(self)
5259 def _notifyModification( self ):
5260 if self._slot != None:
5261 self._slot.notifyModification()
5263 def clone(self):
5264 chair = SlotChair()
5265 chair.setValues(self.getValues())
5266 return chair
5268 def getSlot(self):
5269 return self._slot
5271 def getSession(self):
5272 s=self.getSlot()
5273 if s is None:
5274 return None
5275 return s.getSession()
5277 def getConference(self):
5278 s=self.getSlot()
5279 if s is None:
5280 return None
5281 return s.getConference()
5283 def includeInSlot(self,slot,id):
5284 if self.getSlot()==slot and self.getId()==id.strip():
5285 return
5286 self._slot=slot
5287 self._id=id
5289 def delete( self ):
5290 self._slot=None
5291 ConferenceParticipation.delete(self)
5293 def getLocator(self):
5294 if self.getSlot() is None:
5295 return None
5296 loc=self.getSlot().getLocator()
5297 loc["convId"]=self.getId()
5298 return loc
5300 class SessionCoordinatorRights:
5302 def __init__(self):
5303 self._rights = {"modifContribs": "Modify the contributions",
5304 "unrestrictedSessionTT": "Unrestricted session timetable management"
5307 def hasRight(self, r):
5308 return self._rights.has_key(r)
5310 def getRights(self):
5311 return self._rights
5313 def getRightList(self, sort=False):
5314 l=self._rights.values()
5315 if sort:
5316 l.sort()
5317 return l
5319 def getRightKeys(self):
5320 return self._rights.keys()
5322 def getRight(self, id):
5323 if self._rights.has_key(id):
5324 return self._rights[id]
5325 return None
5327 class SCIndex(Persistent):
5328 """Index for conference session coordinators.
5330 This class allows to index conference session coordinators so the owner
5331 can answer optimally to the query if a user is coordinating
5332 any conference session.
5333 It is implemented by simply using a BTree where the Avatar id is used
5334 as key (because it is unique and non variable) and a list of
5335 coordinated sessions is kept as keys. It is the responsability of the
5336 index owner (conference) to keep it up-to-date i.e. notify session
5337 coordinator additions and removals.
5340 def __init__( self ):
5341 self._idx=OOBTree()
5344 def getSessions(self,av):
5345 """Gives a list with the sessions a user is coordinating.
5347 if av == None:
5348 return []
5349 return self._idx.get(av.getId(),[])
5351 def index(self,av,session):
5352 """Registers in the index a coordinator of a session.
5354 if av == None or session == None:
5355 return
5356 if not self._idx.has_key(av.getId()):
5357 l=[]
5358 self._idx[av.getId()]=l
5359 else:
5360 l=self._idx[av.getId()]
5361 if session not in l:
5362 l.append(session)
5363 self.notifyModification()
5365 def unindex(self,av,session):
5366 if av==None or session==None:
5367 return
5368 l=self._idx.get(av.getId(),[])
5369 if session in l:
5370 l.remove(session)
5371 self.notifyModification()
5373 def notifyModification(self):
5374 self._idx._p_changed=1
5377 class Session(CommonObjectBase, Locatable):
5378 """This class implements a conference session, being the different parts
5379 in which the conference can be divided and the contributions can be
5380 organised in. The class contains necessary attributes to store session
5381 basic data and provides the operations related to sessions. In
5382 principle, a session has no sense to exist without being related to a
5383 conference but it is allowed for flexibility.
5386 fossilizes(ISessionFossil)
5389 def __init__(self, **sessionData):
5390 """Class constructor. Initialise the class attributes to the default
5391 values.
5392 Params:
5393 sessionData -- (Dict) Contains the data the session object has to
5394 be initialised to.
5396 self.conference=None
5397 self.id="not assigned"
5398 self.title=""
5399 self.description=""
5400 #################################
5401 # Fermi timezone awareness #
5402 #################################
5403 self.startDate = nowutc()
5404 #################################
5405 # Fermi timezone awareness(end) #
5406 #################################
5408 self.duration=timedelta(minutes=1)
5409 self.places=[]
5410 self.rooms=[]
5411 self.conveners=[] # This attribute must not be used and should disappear someday
5412 self._conveners=[]
5413 self._convenerGen=Counter()
5414 self.convenerText=""
5415 self.contributions={}
5416 self._contributionDuration=timedelta(minutes=20)
5417 self.__ac=AccessController(self)
5418 self.materials={}
5419 self.__materialGenerator=Counter()
5420 self.minutes=None
5421 self._comments = ""
5422 self.slots={}
5423 self.__slotGenerator=Counter()
5424 self._setSchedule()
5425 self._coordinators=OOBTree()
5426 self._coordinatorsEmail = []
5427 self._code=""
5428 self._color="#e3f2d3"
5429 self._textColor="#202020"
5430 self._textColorToLinks=False
5431 self._ttType=SlotSchTypeFactory.getDefaultId()
5432 self._closed = False
5433 self._registrationSession = None
5434 self._creationDS = nowutc()
5435 self._modificationDS = nowutc()
5436 self._keywords = ""
5438 def getTimezone( self ):
5439 return self.getConference().getTimezone()
5441 def isFullyPublic( self ):
5442 if hasattr(self, "_fullyPublic"):
5443 return self._fullyPublic
5444 else:
5445 self.setFullyPublic()
5446 return self._fullyPublic
5448 def setFullyPublic( self ):
5449 if self.isProtected():
5450 self._fullyPublic = False
5451 self._p_changed = 1
5452 return
5453 for res in self.getAllMaterialList():
5454 if not res.isFullyPublic():
5455 self._fullyPublic = False
5456 self._p_changed = 1
5457 return
5458 for res in self.getContributionList():
5459 if not res.isFullyPublic():
5460 self._fullyPublic = False
5461 self._p_changed = 1
5462 return
5463 self._fullyPublic = True
5464 self._p_changed = 1
5466 def updateFullyPublic( self ):
5467 self.setFullyPublic()
5468 self.getOwner().updateFullyPublic()
5470 def getKeywords(self):
5471 try:
5472 return self._keywords
5473 except:
5474 self._keywords = ""
5475 return ""
5477 def setKeywords(self, keywords):
5478 self._keywords = keywords
5480 def notifyModification( self, date = None ):
5481 """Method called to notify the current session has been modified.
5483 self.setModificationDate(date)
5485 parent = self.getConference()
5486 if parent:
5487 parent.setModificationDate(date)
5488 self._p_changed=1
5490 def getModificationDate( self ):
5491 """Returns the date in which the session was last modified"""
5492 try:
5493 return self._modificationDS
5494 except:
5495 self._modificationDS = nowutc()
5496 return self._modificationDS
5498 def getCreationDate( self ):
5499 """Returns the date in which the session was created"""
5500 try:
5501 return self._creationDS
5502 except:
5503 self._creationDS = nowutc()
5504 return self._creationDS
5506 def getLogInfo(self):
5507 data = {}
5508 data["subject"] = self.title
5509 data["session id"] = self.id
5510 data["session code"] = self._code
5511 data["title"] = self.title
5512 data["description"] = self.description
5513 data["start date"] = self.startDate
5514 data["duration"] = self.duration
5515 for p in self.places :
5516 data["place"] = p.getName()
5517 for r in self.rooms :
5518 data["room"] = r.getName()
5519 for sc in self.getConvenerList() :
5520 data["convener %s"%sc.getId()] = sc.getFullName()
5521 for co in self.getCoordinatorList() :
5522 data["contribution %s"%co.getId()] = co.getFullName()
5523 for s in self.getSlotList() :
5524 data["contribution %s"%s.getId()] = s.getTitle()
5525 for c in self.getContributionList() :
5526 data["contribution %s"%c.getId()] = c.getTitle()
5528 return data
5530 def getEnableSessionSlots(self):
5531 try:
5532 return self.getConference().getEnableSessionSlots()
5533 except:
5534 return True
5536 def cmpSessionByTitle(session1, session2):
5537 return cmp(session1.getTitle(), session2.getTitle())
5538 cmpSessionByTitle = staticmethod(cmpSessionByTitle)
5540 def hasRegistrationSession(self):
5541 return self.getRegistrationSession() is not None
5543 def getRegistrationSession(self):
5544 try:
5545 if self._registrationSession:
5546 pass
5547 except AttributeError, e:
5548 self._registrationSession = None
5549 return self._registrationSession
5551 def setRegistrationSession(self, rs):
5552 self._registrationSession = rs
5554 def isClosed( self ):
5555 if self.getConference().isClosed():
5556 return True
5557 try:
5558 return self._closed
5559 except:
5560 self._closed = False
5561 return False
5563 def setClosed( self, closed=True ):
5564 self._closed = closed
5565 self.notifyModification()
5567 def includeInConference(self,conf,newId):
5568 self.conference=conf
5569 self.id=newId
5570 for slot in self.getSlotList():
5571 conf.getSchedule().addEntry(slot.getConfSchEntry(),2)
5572 self.getConference().addSession(self)
5573 self.notifyModification()
5575 def delete(self):
5576 while len(self.getConvenerList()) > 0:
5577 self.removeConvener(self.getConvenerList()[0])
5578 while len(self.getMaterialList()) > 0:
5579 self.removeMaterial(self.getMaterialList()[0])
5580 self.removeMinutes()
5581 for c in self.getCoordinatorList()[:]:
5582 self.removeCoordinator(c)
5583 while len(self.contributions.values())>0:
5584 self.removeContribution(self.contributions.values()[0])
5585 while len(self.slots.values())>0:
5586 self._removeSlot(self.slots.values()[0])
5587 if self.getConference() is not None:
5588 self.getConference().removeSession(self)
5589 if self.hasRegistrationSession():
5590 self.getConference().getRegistrationForm().getSessionsForm().removeSession(self.getId())
5591 self.getRegistrationSession().setRegistrationForm(None)
5592 TrashCanManager().add(self.getRegistrationSession())
5593 self.conference=None
5594 TrashCanManager().add(self)
5596 def recover(self, isCancelled):
5597 if self.hasRegistrationSession():
5598 if not isCancelled:
5599 self.getRegistrationSession().setRegistrationForm(self.getConference().getRegistrationForm())
5600 self.getConference().getRegistrationForm().getSessionsForm().addSession(self.getRegistrationSession())
5601 TrashCanManager().remove(self.getRegistrationSession())
5602 TrashCanManager().remove(self)
5604 def getLocator( self ):
5605 """Gives back a globaly unique identification encapsulated in a Locator
5606 object for the session instance
5608 if self.conference == None:
5609 return Locator()
5610 lconf = self.conference.getLocator()
5611 lconf["sessionId"] = self.getId()
5612 return lconf
5614 def getConference( self ):
5615 return self.conference
5617 def getSession( self ):
5618 return self
5620 def getOwner( self ):
5621 return self.getConference()
5623 def getId( self ):
5624 return self.id
5626 def getUniqueId( self ):
5627 """returns (string) the unique identiffier of the item"""
5628 """used mainly in the web session access key table"""
5629 return "%ss%s" % (self.getConference().getUniqueId(),self.id)
5631 def getModifKey( self ):
5632 return self.getConference().getModifKey()
5634 def getAccessKey( self ):
5635 return self.getConference().getAccessKey()
5637 def getContribDuration(self):
5638 try:
5639 return self._contributionDuration
5640 except:
5641 self._contributionDuration = timedelta(minutes=20)
5642 return self._contributionDuration
5644 def setContribDuration(self, hour=0, min=20, dur=None):
5645 if dur is not None:
5646 self._contributionDuration=dur
5647 else:
5648 self._contributionDuration = timedelta(hours=hour,minutes=min)
5650 def fit(self):
5651 #if not self.getConference().getEnableSessionSlots():
5652 # self.getSlotList()[0].fit()
5653 self.setStartDate(self.getMinSlotStartDate(),0,0)
5654 self.setEndDate(self.getMaxSlotEndDate(),0)
5656 def addSlot(self,newSlot):
5657 id = newSlot.getId()
5658 if id == "not assigned":
5659 newSlot.setId(str(self.__slotGenerator.newCount()))
5660 self.slots[newSlot.getId()]=newSlot
5661 self.fit()
5662 self.getSchedule().addEntry(newSlot.getSessionSchEntry(),2)
5663 if self.getConference() is not None:
5664 self.getConference().getSchedule().addEntry(newSlot.getConfSchEntry(),2)
5665 self.notifyModification()
5667 def _removeSlot(self,slot):
5668 del self.slots[slot.getId()]
5669 self.getSchedule().removeEntry(slot.getSessionSchEntry())
5670 if self.getConference() is not None:
5671 self.getConference().getSchedule().removeEntry(slot.getConfSchEntry())
5672 slot.delete()
5674 def removeSlot(self, slot, force=False):
5675 if self.slots.has_key(slot.getId()):
5676 if len(self.slots)==1 and not force:
5677 raise MaKaCError( _("A session must have at least one slot"), _("Session"))
5678 self._removeSlot(slot)
5679 self.fit()
5680 self.notifyModification()
5682 def recoverSlot(self, slot):
5683 self.addSlot(slot)
5684 slot.recover()
5686 def getSlotById(self,slotId):
5687 return self.slots.get(slotId,None)
5689 def getSlotList(self):
5690 return self.slots.values()
5692 def getSortedSlotList(self):
5693 sl = self.getSlotList()
5694 sl.sort(utils.sortSlotByDate)
5695 return sl
5697 def getMinSlotStartTime(self):
5698 min = (25,61)
5699 for slot in self.getSlotList():
5700 if slot.isMoreThanDay():
5701 return (0,0)
5702 shour = slot.getStartDate().hour
5703 smin = slot.getStartDate().minute
5704 if (shour, smin) < min:
5705 min = (shour, smin)
5706 return min
5708 def getMaxSlotEndTime(self):
5709 max = (-1,-1)
5710 for slot in self.getSlotList():
5711 if slot.isMoreThanDay():
5712 return (23, 59)
5713 endDate = slot.getEndDate()
5714 if (endDate.hour, endDate.minute) > max:
5715 newEndDate = endDate - timedelta(0, 0, 0)
5716 max = (newEndDate.hour, newEndDate.minute)
5717 return max
5719 def getMinSlotStartDate(self):
5720 slotList = self.getSlotList()
5721 if len(slotList)==0:
5722 return self.getStartDate()
5723 else:
5724 sDate = self.getEndDate()
5725 for slot in slotList:
5726 if slot.getStartDate() < sDate:
5727 sDate = slot.getStartDate()
5728 return sDate
5730 def getMaxSlotEndDate(self):
5731 slotList = self.getSlotList()
5732 if len(slotList)==0:
5733 return self.getEndDate()
5734 else:
5735 eDate = self.getStartDate()
5736 for slot in slotList:
5737 if slot.getEndDate() > eDate:
5738 eDate = slot.getEndDate()
5739 return eDate
5741 def _getCorrectColor(self, color):
5742 if not color.startswith("#"):
5743 color = "#%s"%color
5744 m = re.match("^#[0-9A-Fa-f]{6}$", color)
5745 if m:
5746 return color
5747 return None
5749 def _getCorrectBgColor(self, color):
5750 color=self._getCorrectColor(color)
5751 if color is None:
5752 return self._color
5753 return color
5755 def _getCorrectTextColor(self, color):
5756 color=self._getCorrectColor(color)
5757 if color is None:
5758 return self._textColor
5759 return color
5761 def setValues( self, sessionData,check=2,moveEntries=0 ):
5762 """Sets all the values of the current session object from a dictionary
5763 containing the following key-value pairs:
5764 title-(str)
5765 description-(str)
5766 locationName-(str) => name of the location, if not specified
5767 it will be set to the conference location name.
5768 locationAddress-(str)
5769 roomName-(str) => name of the room, if not specified it will
5770 be set to the conference room name.
5771 sDate - (datetime) => starting date of the session, if not
5772 specified it will be set to now.
5773 eDate - (datetime) => ending date of the session, if not
5774 specified the end date will be set to the start one
5775 durHour - (int) => hours of duration for each entry in the session
5776 by default.
5777 durMin - (int) => hours of duration for each entry in the session
5778 by default.
5779 _conveners - (str)
5780 check parameter:
5781 0: no check at all
5782 1: check and raise error in case of problem
5783 2: check and adapt the owner dates
5784 Please, note that this method sets ALL values which means that if
5785 the given dictionary doesn't contain any of the keys the value
5786 will set to a default value.
5789 self.setTitle( sessionData.get("title", "NO TITLE ASSIGNED") )
5790 self.setDescription( sessionData.get("description", "") )
5791 code = sessionData.get("code", "")
5792 if code.strip() == "":
5793 if self.getId()=="not assigned":
5794 self.setCode("no code")
5795 else:
5796 self.setCode(self.getId())
5797 else:
5798 self.setCode(code)
5799 bgcolor = sessionData.get("backgroundColor", "")
5800 if bgcolor.strip() != "":
5801 self.setColor(self._getCorrectBgColor(bgcolor))
5802 textcolor = sessionData.get("textColor", "")
5803 if textcolor.strip() != "":
5804 if sessionData.has_key("autotextcolor"):
5805 self.setTextColor(utils.getTextColorFromBackgroundColor(self.getColor()))
5806 else:
5807 self.setTextColor(self._getCorrectTextColor(textcolor))
5808 self.setTextColorToLinks(sessionData.has_key("textcolortolinks"))
5810 if "locationName" in sessionData:
5811 loc = self.getOwnLocation()
5812 if not loc:
5813 loc = CustomLocation()
5814 self.setLocation( loc )
5815 loc.setName( sessionData["locationName"] )
5816 loc.setAddress( sessionData.get("locationAddress", "") )
5817 else:
5818 self.setLocation(None)
5820 #same as for the location
5821 if "roomName" in sessionData:
5822 room = self.getOwnRoom()
5823 if not room:
5824 room = CustomRoom()
5825 self.setRoom( room )
5826 room.setName( sessionData["roomName"] )
5827 else:
5828 self.setRoom(None)
5830 if sessionData.get("sDate",None) is not None:
5831 self.setStartDate(sessionData["sDate"],check,moveEntries=moveEntries)
5832 if sessionData.get("eDate",None) is not None:
5833 self.setEndDate(sessionData["eDate"],check)
5834 self._checkInnerSchedule()
5835 if sessionData.get("contribDuration","")!="":
5836 self._contributionDuration = sessionData.get("contribDuration")
5837 else:
5838 self._contributionDuration = timedelta(hours=int(sessionData.get("durHour",0)), minutes=int(sessionData.get("durMin",20)))
5839 self.notifyModification()
5841 def move(self, sDate):
5843 Move a session from the old start date to a new start date, and
5844 it moves all the entries of the session as well, without date validations.
5846 if sDate is not None:
5847 oldStartDate=self.startDate
5848 self.startDate=copy.copy(sDate)
5849 diff=self.startDate-oldStartDate
5850 # Check date to not be prior conference start date and to not surpass conference end date
5851 # The schedule is returning the datetime object as timezone aware relative to the conference
5852 # timezone. Must adjust the startdate accordingly for comparison. JMF
5853 conftz = self.getConference().getTimezone()
5854 if self.getStartDate() < self.getConference().getSchedule().getStartDate() or \
5855 self.getEndDate() > self.getConference().getSchedule().getEndDate():
5856 raise MaKaCError( _("Impossible to move the session because it would be out of the conference dates"))
5857 for entry in self.getSchedule().getEntries():
5858 if isinstance(entry,LinkedTimeSchEntry) and \
5859 isinstance(entry.getOwner(), SessionSlot):
5860 e = entry.getOwner()
5861 e.move(e.getStartDate() + diff)
5862 self.getSchedule().reSchedule()
5863 self.getConference().getSchedule().reSchedule()
5864 self.notifyModification()
5866 def clone(self, deltaTime, conf, options):
5867 ses = Session()
5868 conf.addSession(ses,check=0)
5869 ses.setTitle(self.getTitle())
5870 ses.setDescription(self.getDescription())
5871 startDate = self.getStartDate() + deltaTime
5872 ses.setStartDate(startDate, check=1)
5873 ses.setDuration(dur=self.getDuration())
5875 if self.getOwnLocation() is not None:
5876 ses.addLocation(self.getOwnLocation().clone())
5877 if self.getOwnRoom() is not None:
5878 ses.setRoom(self.getOwnRoom().clone())
5879 ses.setColor(self.getColor())
5880 ses.setTextColor(self.getTextColor())
5881 ses.setTextColorToLinks(self.isTextColorToLinks())
5882 ses.setCode(self.getCode())
5883 ses.setContribDuration(dur=self.getContribDuration())
5884 ses.setScheduleType(self.getScheduleType())
5885 ses.setComments(self.getComments())
5887 # Access Control cloning
5888 if options.get("access", False) :
5889 ses.setProtection(self.getAccessController()._getAccessProtection())
5890 for mgr in self.getManagerList() :
5891 ses.grantModification(mgr)
5892 for user in self.getAllowedToAccessList() :
5893 ses.grantAccess(user)
5894 for domain in self.getDomainList():
5895 ses.requireDomain(domain)
5896 for coord in self.getCoordinatorList():
5897 ses.addCoordinator(coord)
5899 #slots in timeschedule
5900 for slot in self.getSlotList() :
5901 newslot = slot.clone(ses, options)
5902 ses.addSlot(newslot)
5903 ContextManager.setdefault("clone.unique_id_map", {})[slot.getUniqueId()] = newslot.getUniqueId()
5905 ses.notifyModification()
5907 return ses
5910 def setTitle( self, newTitle ):
5911 self.title = newTitle
5912 self.notifyModification()
5914 def getTitle( self ):
5915 return self.title
5917 def setDescription(self, newDescription ):
5918 self.description = newDescription
5919 self.notifyModification()
5921 def getDescription(self):
5922 return self.description
5924 def getCode(self):
5925 try:
5926 if self._code:
5927 pass
5928 except AttributeError:
5929 self._code=self.id
5930 return self._code
5932 def setCode(self,newCode):
5933 self._code=str(newCode).strip()
5935 def getColor(self):
5936 try:
5937 if self._color:
5938 pass
5939 except AttributeError:
5940 self._color="#e3f2d3"
5941 return self._color
5942 getBgColor=getColor
5944 def setColor(self,newColor):
5945 self._color=str(newColor).strip()
5946 setBgColor=setColor
5948 def getTextColor(self):
5949 try:
5950 if self._textColor:
5951 pass
5952 except AttributeError:
5953 self._textColor="#202020"
5954 return self._textColor
5956 def setTextColor(self,newColor):
5957 self._textColor=str(newColor).strip()
5959 def isTextColorToLinks(self):
5960 try:
5961 if self._textColorToLink:
5962 pass
5963 except AttributeError:
5964 self._textColorToLink=False
5965 return self._textColorToLink
5967 def setTextColorToLinks(self, v):
5968 self._textColorToLink=v
5970 def getStartDate(self):
5971 return self.startDate
5973 def getAdjustedStartDate(self,tz=None):
5974 if not tz:
5975 tz = self.getConference().getTimezone()
5976 if tz not in all_timezones:
5977 tz = 'UTC'
5978 return self.startDate.astimezone(timezone(tz))
5980 def verifyStartDate(self, sdate, check=2):
5981 """check parameter:
5982 0: no check at all
5983 1: check and raise error in case of problem (default)
5984 2: check and adapt the owner dates
5987 conf=self.getConference()
5989 if conf is not None and sdate < conf.getSchedule().getStartDate():
5990 if check==1:
5991 raise ParentTimingError( _("The session starting date cannot be prior to the event starting date"), _("Session"))
5992 elif check==2:
5993 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
5994 conf, sdate.astimezone(timezone(conf.getTimezone()))))
5995 conf.setStartDate(sdate,check=0,moveEntries=0)
5997 def setStartDate(self,newDate,check=2,moveEntries=0):
5999 moveEntries parameter:
6000 0: do not move inner slots
6001 1: move
6002 2: do not move but check that session is not out of the conference dates
6005 if not newDate.tzname():
6006 raise MaKaCError("date should be timezone aware")
6007 if check != 0:
6008 self.verifyStartDate(newDate,check)
6009 oldSdate = self.getStartDate()
6010 try:
6011 tz = str(self.getStartDate().tzinfo)
6012 except:
6013 tz = 'UTC'
6014 diff = newDate - oldSdate
6015 self.startDate=copy.copy(newDate)
6016 if moveEntries == 1 and diff is not None and diff != timedelta(0):
6017 # If the start date changed, we move entries inside the timetable
6018 newDateTz = newDate.astimezone(timezone(tz))
6019 if oldSdate.astimezone(timezone(tz)).date() != newDateTz.date():
6020 entries = self.getSchedule().getEntries()[:]
6021 else:
6022 entries = self.getSchedule().getEntriesOnDay(newDateTz)[:]
6023 self.getSchedule().moveEntriesBelow(diff, entries)
6025 if moveEntries != 0 and self.getConference() and \
6026 not self.getConference().getEnableSessionSlots() and \
6027 self.getSlotList() != [] and \
6028 self.getSlotList()[0].getStartDate() != newDate:
6029 self.getSlotList()[0].startDate = newDate
6031 if check == 1:
6032 self._checkInnerSchedule()
6033 self.notifyModification()
6035 def _checkInnerSchedule( self ):
6036 self.getSchedule().checkSanity()
6038 def getEndDate(self):
6039 return self.startDate+self.duration
6041 ####################################
6042 # Fermi timezone awareness #
6043 ####################################
6045 def getAdjustedEndDate(self,tz=None):
6046 return self.getAdjustedStartDate(tz) + self.duration
6048 ####################################
6049 # Fermi timezone awareness(end) #
6050 ####################################
6052 def verifyEndDate(self, edate,check=1):
6053 """check parameter:
6054 0: no check at all
6055 1: check and raise error in case of problem
6056 2: check and adapt the owner dates
6058 try:
6059 tz = timezone(self.getConference().getTimezone())
6060 except:
6061 tz = timezone('UTC')
6062 # compare end date with start date
6063 if edate<=self.getStartDate():
6064 if check == 1:
6065 raise MaKaCError( _("End date cannot be prior to the Start date"), _("Session"))
6066 if check == 2:
6067 self.setStartDate(edate)
6068 # check conference dates
6069 if (self.getConference()):
6070 conf=self.getConference()
6071 confStartDate = conf.getSchedule().getStartDate()
6072 confEndDate = conf.getSchedule().getEndDate()
6073 if conf is not None and (edate>confEndDate or edate<=confStartDate):
6074 if check==1:
6075 raise ParentTimingError( _("The end date has to be between the event dates (%s - %s)")%\
6076 (confStartDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
6077 confEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
6078 _("Session"))
6079 if check==2:
6080 if edate>confEndDate:
6081 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
6082 self.getConference(),
6083 edate.astimezone(tz)))
6084 self.getConference().setEndDate(edate)
6085 if edate<=confStartDate:
6086 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
6087 self.getConference(),
6088 edate.astimezone(tz)))
6089 self.getConference().setStartDate(edate)
6090 # check inner schedule
6091 if len(self.getSlotList()) != 0 and self.getSlotList()[-1].getSchedule().hasEntriesAfter(edate):
6092 raise TimingError( _("Cannot change end date: some entries in the session schedule end after the new date"), _("Session"))
6094 def setEndDate(self,newDate,check=2):
6095 if not newDate.tzname():
6096 raise MaKaCError("date should be timezone aware")
6097 if check != 0:
6098 self.verifyEndDate(newDate,check)
6099 self.duration=newDate-self.getStartDate()
6100 # A session is not always linked to a conference (for eg. at creation time)
6101 #if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSlotList()[0].getEndDate() != newDate:
6102 # self.getSlotList()[0].duration = self.duration
6103 self.notifyModification()
6105 def setDates(self,sDate,eDate,check=1,moveEntries=0):
6106 if eDate<=sDate:
6107 tz = timezone(self.getConference().getTimezone())
6108 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"))
6109 self.setStartDate(sDate,check,moveEntries)
6110 self.setEndDate(eDate,check)
6111 self._checkInnerSchedule()
6113 def getDuration( self ):
6114 return self.duration
6116 def setDuration(self,hours=0,minutes=15,dur=0):
6117 if dur==0:
6118 dur = timedelta(hours=int(hours),minutes=int(minutes))
6119 if dur.seconds <= 0:
6120 raise MaKaCError( _("The duration cannot be less than zero"), _("Session"))
6121 self.duration = dur
6122 self.verifyEndDate(self.getEndDate())
6123 self.notifyModification()
6125 def getStartOnDay(self, day, tz=None):
6126 if not tz:
6127 tz = self.getConference().getTimezone()
6128 if type(day) is datetime:
6129 day = day.astimezone(timezone(tz))
6130 if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() :
6131 return None
6132 minTime = self.getEndDate()
6133 for e in self.getSchedule().getEntriesOnDay(day) :
6134 if e.getStartDate() < minTime :
6135 minTime = e.getStartDate()
6136 if minTime == self.getEndDate() :
6137 minTime = day.replace(hour=8, minute=0)#datetime.combine(day,time(hour=8, minute=0))
6138 if minTime < self.getStartDate() :
6139 return self.getStartDate()
6140 return minTime
6142 def getEndOnDay(self, day, tz=None):
6143 if not tz:
6144 tz = self.getConference().getTimezone()
6145 if type(day) is datetime:
6146 day = day.astimezone(timezone(tz))
6147 if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() :
6148 return None
6149 maxTime = self.getStartDate();
6150 for e in self.getSchedule().getEntriesOnDay(day) :
6151 if e.getEndDate() > maxTime :
6152 maxTime = e.getEndDate()
6153 if maxTime == self.getStartDate() :
6154 maxTime = day.replace(hour=19, minute=0)#datetime.combine(day,time(19,0))
6155 if maxTime > self.getEndDate() :
6156 return self.getEndDate()
6157 return maxTime
6159 def getLocationParent( self ):
6161 Returns the object from which the room/location
6162 information should be inherited
6164 return self.getConference()
6166 def getLocationList(self):
6167 """Method returning a list of "location" objects which contain the
6168 information about the different places the conference is gonna
6169 happen
6171 return self.places
6173 def addLocation(self, newPlace):
6174 self.places.append( newPlace )
6175 self.notifyModification()
6177 def _resetConveners(self):
6178 try:
6179 if self._conveners:
6180 return
6181 except AttributeError:
6182 self._conveners=[]
6183 for oc in self.conveners:
6184 newConv=SessionChair()
6185 newConv.setDataFromAvatar(oc)
6186 self._addConvener(newConv)
6188 def getConvenerList(self):
6189 self._resetConveners()
6190 return self._conveners
6192 def getAllConvenerList(self):
6193 convenerList = set()
6194 for slot in self.getSlotList():
6195 for convener in slot.getConvenerList():
6196 convenerList.add(convener)
6197 return convenerList
6199 def _addConvener(self,newConv):
6200 if newConv in self._conveners:
6201 return
6202 try:
6203 if self._convenerGen:
6204 pass
6205 except AttributeError:
6206 self._convenerGen=Counter()
6207 id = newConv.getId()
6208 if id == "":
6209 id=int(self._convenerGen.newCount())
6210 newConv.includeInSession(self,id)
6211 self._conveners.append(newConv)
6212 self.notifyModification()
6214 def addConvener(self,newConv):
6215 self._resetConveners()
6216 self._addConvener(newConv)
6217 if isinstance(newConv, MaKaC.user.Avatar):
6218 conv.unlinkTo(self, "convener")
6220 def removeConvener(self,conv):
6221 self._resetConveners()
6222 if conv not in self._conveners:
6223 return
6224 #--Pending queue: remove pending Convener waiting to became manager if anything
6225 self.getConference().getPendingQueuesMgr().removePendingManager(conv)
6227 #--Pending queue: remove pending Convener waiting to became coordinator if anything
6228 self.getConference().getPendingQueuesMgr().removePendingCoordinator(conv)
6230 self._conveners.remove(conv)
6231 if isinstance(conv, MaKaC.user.Avatar):
6232 conv.linkTo(self, "convener")
6233 conv.delete()
6234 self.notifyModification()
6236 def recoverConvener(self, con):
6237 self.addConvener(con)
6238 con.recover()
6240 def getConvenerById(self,id):
6241 id=int(id)
6242 for conv in self._conveners:
6243 if conv.getId()==id:
6244 return conv
6245 return None
6247 def getConvenerText( self ):
6248 #to be removed
6249 try:
6250 if self.convenerText:
6251 pass
6252 except AttributeError, e:
6253 self.convenerText = ""
6254 return self.convenerText
6256 def setConvenerText( self, newText ):
6257 self.convenerText = newText.strip()
6259 def appendConvenerText( self, newText ):
6260 self.setConvenerText( "%s, %s"%(self.getConvenerText(), newText.strip()) )
6262 def addContribution(self, newContrib, id=None):
6263 """Registers the contribution passed as parameter within the session
6264 assigning it a unique id.
6266 if self.hasContribution(newContrib):
6267 return
6268 self.getConference().addContribution(newContrib,id)
6269 self.contributions[newContrib.getId()]=newContrib
6270 newContrib.setSession(self)
6271 self.notifyModification()
6273 def hasContribution(self,contrib):
6274 return contrib.getSession()==self and \
6275 self.contributions.has_key(contrib.getId())
6277 def removeContribution(self,contrib):
6278 """Removes the indicated contribution from the session
6280 if not self.hasContribution(contrib):
6281 return
6282 if contrib.isScheduled():
6283 # unschedule the contribution
6284 sch=contrib.getSchEntry().getSchedule()
6285 sch.removeEntry(contrib.getSchEntry())
6286 del self.contributions[contrib.getId()]
6287 contrib.setSession(None)
6289 self.notifyModification()
6291 def newContribution( self, params = None, id=None ):
6292 c = Contribution()
6293 if params:
6294 c.setValues(params)
6295 self.addContribution( c, id )
6296 return c
6298 def getContributionById(self,id):
6299 id=str(id).strip()
6300 if self.contributions.has_key( id ):
6301 return self.contributions[ id ]
6302 return None
6304 def getContributionList( self ):
6305 return self.contributions.values()
6307 def getNumberOfContributions(self, only_scheduled=False):
6308 if only_scheduled:
6309 return len(filter(lambda c: c.isScheduled(), self.contributions.itervalues()))
6310 else:
6311 return len(self.contributions)
6313 def canIPAccess( self, ip ):
6314 if not self.__ac.canIPAccess( ip ):
6315 return False
6316 if self.getOwner() != None:
6317 return self.getOwner().canIPAccess(ip)
6318 return True
6320 def isProtected( self ):
6321 # tells if a session is protected or not
6322 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
6324 def getAccessProtectionLevel( self ):
6325 return self.__ac.getAccessProtectionLevel()
6327 def isItselfProtected( self ):
6328 return self.__ac.isItselfProtected()
6330 def hasAnyProtection( self ):
6331 """Tells whether a session has any kind of protection over it:
6332 access or domain protection.
6334 if self.__ac.isProtected():
6335 return True
6336 if self.getDomainList():
6337 return True
6338 if self.getAccessProtectionLevel() == -1:
6339 return False
6341 return self.getOwner().hasAnyProtection()
6343 def hasProtectedOwner( self ):
6344 if self.getOwner() != None:
6345 return self.getOwner().isProtected()
6346 return False
6348 def setProtection( self, private ):
6349 self.__ac.setProtection( private )
6350 self.updateFullyPublic()
6352 def grantAccess( self, prin ):
6353 self.__ac.grantAccess( prin )
6354 if isinstance(prin, MaKaC.user.Avatar):
6355 prin.linkTo(self, "access")
6357 def revokeAccess( self, prin ):
6358 self.__ac.revokeAccess( prin )
6359 if isinstance(prin, MaKaC.user.Avatar):
6360 prin.unlinkTo(self, "access")
6362 def canView( self, aw ):
6363 """tells whether the specified user has access to the current object
6364 or any of its sub-objects
6366 if self.canAccess( aw ):
6367 return True
6368 ### TODO: Replace this code when plugins allow extension points+notifications ##################
6369 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
6370 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
6371 RCCollaborationPluginAdmin.hasRights(user = aw.getUser(), plugins = "any"):
6372 return True
6373 ################################################################################################
6374 for contrib in self.getContributionList():
6375 if contrib.canView( aw ):
6376 return True
6377 return False
6379 def isAllowedToAccess( self, user ):
6380 if not user:
6381 return False
6382 if user in self.getCoordinatorList() or self.__ac.canUserAccess( user ) \
6383 or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess(user)):
6384 return True
6385 return False
6387 def canAccess( self, aw ):
6388 # Allow harvesters (Invenio, offline cache) to access
6389 # protected pages
6390 if self.__ac.isHarvesterIP(aw.getIP()):
6391 return True
6392 #####################################################
6394 if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ):
6395 return False
6396 if not self.isProtected():
6397 return True
6398 flag = self.isAllowedToAccess( aw.getUser() )
6399 return flag or self.conference.canKeyAccess( aw )
6401 def grantModification( self, sb, sendEmail=True ):
6402 if isinstance(sb, SessionChair) or isinstance(sb, SlotChair):
6403 ah = AvatarHolder()
6404 results=ah.match({"email":sb.getEmail()}, exact=1)
6405 r=None
6406 for i in results:
6407 if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]:
6409 break
6410 if r is not None and r.isActivated():
6411 self.__ac.grantModification( r )
6412 r.linkTo(self, "manager")
6413 elif sb.getEmail() != "":
6414 modificationEmailGranted = self.__ac.grantModificationEmail(sb.getEmail())
6415 if modificationEmailGranted and sendEmail:
6416 notif = pendingQueues._PendingManagerNotification( [sb] )
6417 mail.GenericMailer.sendAndLog( notif, self.getConference() )
6418 else:
6419 self.__ac.grantModification( sb )
6420 if isinstance(sb, MaKaC.user.Avatar):
6421 sb.linkTo(self, "manager")
6423 def revokeModification( self, prin ):
6424 self.__ac.revokeModification( prin )
6425 if isinstance(prin, MaKaC.user.Avatar):
6426 prin.unlinkTo(self, "manager")
6428 def canModify( self, aw ):
6429 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
6431 def canUserModify( self, av ):
6432 """Tells whether a user is allowed to modify the current session:
6433 only if the user is granted to modify the session or the user
6434 can modify the corresponding conference.
6436 return self.getConference().canUserModify( av ) or self.__ac.canModify( av )
6438 def getManagerList( self ):
6439 return self.__ac.getModifierList()
6441 def getAllowedToAccessList( self ):
6442 return self.__ac.getAccessList()
6444 def addMaterial( self, newMat ):
6445 newMat.setId( str(self.__materialGenerator.newCount()) )
6446 newMat.setOwner( self )
6447 self.materials[ newMat.getId() ] = newMat
6448 self.notifyModification()
6450 def removeMaterial( self, mat ):
6451 if mat.getId() in self.materials.keys():
6452 self.materials[mat.getId()].setOwner(None)
6453 del self.materials[ mat.getId() ]
6454 mat.delete()
6455 self.notifyModification()
6456 return "done: %s"%mat.getId()
6457 elif mat.getId().lower() == 'minutes':
6458 self.removeMinutes()
6459 return "done: %s"%mat.getId()
6460 return "not done: %s"%mat.getId()
6462 def recoverMaterial(self, recMat):
6463 # Id must already be set in recMat.
6464 recMat.setOwner( self )
6465 self.materials[ recMat.getId() ] = recMat
6466 recMat.recover()
6467 self.notifyModification()
6469 def getMaterialRegistry(self):
6471 Return the correct material registry for this type
6473 from MaKaC.webinterface.materialFactories import SessionMFRegistry
6474 return SessionMFRegistry
6476 def getMaterialById( self, matId ):
6477 if matId.lower() == 'minutes':
6478 return self.getMinutes()
6479 elif self.materials.has_key(matId):
6480 return self.materials[ matId ]
6481 return None
6483 def getMaterialList( self ):
6484 return self.materials.values()
6486 def getAllMaterialList( self ):
6487 l = self.getMaterialList()
6488 if self.getMinutes():
6489 l.append( self.getMinutes() )
6490 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
6491 return l
6493 def _setSchedule(self):
6494 self.__schedule=SessionSchedule(self)
6495 sl=self.getSlotList()
6496 for slot in self.getSlotList():
6497 self.__schedule.addEntry(slot.getSchEntry())
6499 def getSchedule( self ):
6500 try:
6501 if self.__schedule is None or not isinstance(self.__schedule,SessionSchedule):
6502 self._setSchedule()
6503 except AttributeError, e:
6504 self._setSchedule()
6505 return self.__schedule
6507 def getMasterSchedule( self ):
6508 return self.getOwner().getSchedule()
6510 def requireDomain( self, dom ):
6511 self.__ac.requireDomain( dom )
6513 def freeDomain( self, dom ):
6514 self.__ac.freeDomain( dom )
6516 def getDomainList( self ):
6517 return self.__ac.getRequiredDomainList()
6519 def setComments(self,comm):
6520 self._comments = comm.strip()
6522 def getComments(self):
6523 try:
6524 if self._comments:
6525 pass
6526 except AttributeError,e:
6527 self._comments=""
6528 return self._comments
6530 def createMinutes( self ):
6531 if self.getMinutes() != None:
6532 raise MaKaCError( _("The minutes for this session have already been created"), _("Session"))
6533 self.minutes = Minutes()
6534 self.minutes.setOwner( self )
6535 self.notifyModification()
6536 return self.minutes
6538 def removeMinutes( self ):
6539 if self.minutes is None:
6540 return
6541 self.minutes.delete()
6542 self.minutes.setOwner( None )
6543 self.minutes = None
6544 self.notifyModification()
6546 def recoverMinutes(self, min):
6547 self.removeMinutes() # To ensure that the current minutes are put in
6548 # the trash can.
6549 self.minutes = min
6550 self.minutes.setOwner( self )
6551 min.recover()
6552 self.notifyModification()
6553 return self.minutes
6555 def getMinutes( self ):
6556 #To be removed
6557 try:
6558 if self.minutes:
6559 pass
6560 except AttributeError, e:
6561 self.minutes = None
6563 return self.minutes
6565 def _addCoordinator(self, av):
6566 if av is None or self._coordinators.has_key(av.getId()):
6567 return
6568 self._coordinators[av.getId()]=av
6569 if self.getConference() is not None:
6570 self.getConference().addSessionCoordinator(self,av)
6572 def getCoordinatorEmailList(self):
6573 try:
6574 return self._coordinatorsEmail
6575 except:
6576 self._coordinatorsEmail = []
6577 return self._coordinatorsEmail
6579 def _addCoordinatorEmail(self, email):
6580 if not email in self.getCoordinatorEmailList():
6581 self.getCoordinatorEmailList().append(email)
6583 def removeCoordinatorEmail(self, email):
6584 if email in self.getCoordinatorEmailList():
6585 if email in self.getCoordinatorEmailList():
6586 self.getCoordinatorEmailList().remove(email)
6587 self._p_changed = 1
6589 def addCoordinator( self, sb, sendEmail=True ):
6590 """Grants coordination privileges to user.
6592 Arguments:
6593 sb -- It can be either:
6594 (MaKaC.user.Avatar) the user to which
6595 coordination privileges must be granted.
6597 (MaKaC.conference.SessionChair) a non-existing which
6598 has to become indico user before to be granted with privileges.
6600 try:
6601 if self._coordinators:
6602 pass
6603 except AttributeError, e:
6604 self._coordinators=OOBTree()
6606 if isinstance(sb, SessionChair):
6607 ah = AvatarHolder()
6608 results=ah.match({"email":sb.getEmail()}, exact=1)
6609 r=None
6611 for i in results:
6612 if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]:
6614 break
6616 if r is not None and r.isActivated():
6618 self._addCoordinator(r)
6619 r.linkTo(self, "coordinator")
6620 else:
6621 self.getConference().getPendingQueuesMgr().addPendingCoordinator(sb)
6622 else:
6623 self._addCoordinator(sb)
6624 if isinstance(sb, MaKaC.user.Avatar):
6625 sb.linkTo(self, "coordinator")
6627 def removeCoordinator( self, av ):
6628 """Revokes coordination privileges to user.
6630 Arguments:
6631 av -- (MaKaC.user.Avatar) user for which coordination privileges
6632 must be revoked
6634 try:
6635 if self._coordinators:
6636 pass
6637 except AttributeError, e:
6638 self._coordinators=OOBTree()
6640 if av is None or not self._coordinators.has_key(av.getId()):
6641 return
6642 del self._coordinators[av.getId()]
6643 if isinstance(av, MaKaC.user.Avatar):
6644 av.unlinkTo(self, "coordinator")
6645 if self.getConference() is not None:
6646 self.getConference().removeSessionCoordinator(self,av)
6648 def isCoordinator( self, av ):
6649 """Tells whether the specified user is a coordinator of the session.
6651 Arguments:
6652 av -- (MaKaC.user.Avatar) user to be checked
6654 Return value: (boolean)
6656 try:
6657 if self._coordinators:
6658 pass
6659 except AttributeError, e:
6660 self._coordinators=OOBTree()
6661 if (av is not None) and self._coordinators.has_key(av.getId()):
6662 return True
6663 ret = False
6664 if isinstance(av, MaKaC.user.Avatar):
6665 for email in av.getEmails():
6666 if email in self.getCoordinatorEmailList():
6667 self.addCoordinator(av)
6668 self.removeCoordinatorEmail(email)
6669 ret = True
6670 return ret
6672 def hasConvenerByEmail(self, email):
6673 for convener in self.getConvenerList():
6674 if email == convener.getEmail():
6675 return True
6676 return False
6679 def getCoordinatorList( self ):
6680 """Return all users which have privileges to coordinate the session.
6682 Return value: (list)
6684 try:
6685 if self._coordinators:
6686 pass
6687 except AttributeError, e:
6688 self._coordinators=OOBTree()
6690 return self._coordinators.values()
6692 def canCoordinate(self,aw, right=""):
6693 """Tells if a user has coordination privileges.
6695 Only session coordinators have coordination privileges over a
6696 session.
6698 Params:
6699 aw -- (MaKaC.accessControl.AccessWrapper) User access
6700 information for which the coordination privileges must be
6701 checked.
6703 Return value: (boolean)
6705 if right != "":
6706 return self.isCoordinator(aw.getUser()) and self.getConference().hasSessionCoordinatorRight(right)
6707 return self.isCoordinator(aw.getUser())
6710 def getScheduleType(self):
6711 try:
6712 if self._ttType:
6713 pass
6714 except AttributeError:
6715 self._ttType=SlotSchTypeFactory.getDefaultId()
6716 return self._ttType
6718 def setScheduleType(self,t):
6719 try:
6720 if self._ttType:
6721 pass
6722 except AttributeError:
6723 self._ttType=SlotSchTypeFactory.getDefaultId()
6724 t=str(t).strip().lower()
6725 if t not in SlotSchTypeFactory.getIdList() or t==self._ttType:
6726 return
6727 self._ttType=t
6728 for slot in self.getSlotList():
6729 slot.setScheduleType(t)
6731 def getAccessController(self):
6732 return self.__ac
6735 def _cmpTitle( s1, s2 ):
6736 s1=s1.getTitle().lower().strip()
6737 s2=s2.getTitle().lower().strip()
6738 return cmp( s1, s2 )
6739 _cmpTitle=staticmethod(_cmpTitle)
6741 class SessionSlot(Persistent, Fossilizable, Locatable):
6743 fossilizes(ISessionSlotFossil)
6745 def __init__(self,session,**sessionSlotData):
6746 self.session = session
6747 self.id = "not assigned"
6748 self.title = ""
6749 self.startDate=None
6750 self.duration = timedelta(minutes=1)
6751 self.places = []
6752 self.rooms = []
6753 self._conveners = []
6754 self._convenerGen=Counter()
6755 self._schedule=SlotSchTypeFactory.getDefaultKlass()(self)
6756 self._sessionSchEntry=LinkedTimeSchEntry(self)
6757 self._confSchEntry=LinkedTimeSchEntry(self)
6758 self._contributionDuration = None
6760 def getTimezone( self ):
6761 return self.getConference().getTimezone()
6763 def getLogInfo(self):
6764 data = {}
6765 data["id"] = self.id
6766 data["title"] = self.title
6767 data["session"] = self.session.getTitle()
6768 data["start date"] = self.startDate
6769 data["duration"] = self.duration
6770 i = 0
6771 for p in self.places :
6772 data["place %s"%i] = p.getName()
6773 i+=1
6774 i = 0
6775 for r in self.rooms :
6776 data["room %s"%i] = r.getName()
6777 i+=1
6778 for c in self._conveners :
6779 data["convener %s"%c.getId()] = c.getFullName()
6780 return data
6782 def clone(self,session, options):
6784 slot = SessionSlot(session)
6785 slot.session = session
6786 slot.setTitle(self.getTitle())
6787 timeDifference = session.getConference().getStartDate() - self.getSession().getConference().getStartDate()
6788 slot.setStartDate(self.getStartDate() + timeDifference)
6789 slot.setDuration(dur=self.getDuration(), check=2)
6791 #places
6792 if self.getOwnLocation() is not None:
6793 slot.setLocation(self.getOwnLocation().clone())
6794 #rooms
6795 if self.getOwnRoom() is not None:
6796 slot.setRoom(self.getOwnRoom().clone())
6798 #chairs = conveners
6799 for ch in self.getOwnConvenerList() :
6800 slot.addConvener(ch.clone())
6802 #populate the timetable
6803 if options.get("contributions", False) :
6804 for entry in self.getEntries() :
6805 if isinstance(entry, BreakTimeSchEntry) :
6806 newentry = entry.clone(slot)
6807 slot.getSchedule().addEntry(newentry,0)
6808 elif isinstance(entry, ContribSchEntry) :
6809 contrib = entry.getOwner()
6810 newcontrib = contrib.clone(session, options, timeDifference)
6811 slot.getSchedule().addEntry(newcontrib.getSchEntry(),0)
6812 ContextManager.setdefault("clone.unique_id_map", {})[contrib.getUniqueId()] = newcontrib.getUniqueId()
6814 slot.setContribDuration(0, 0, self.getContribDuration())
6815 slot.notifyModification()
6817 return slot
6819 def fit( self ):
6821 sets the start date of the slot to the start date of the first son
6822 and the end date to the end date of the last son
6824 sch = self.getSchedule()
6825 entries = sch.getEntries()
6826 if len(entries) > 0:
6827 self.setStartDate(entries[0].getStartDate(),0,0)
6828 self.setEndDate(sch.calculateEndDate(), check=0)
6830 def recalculateTimes( self, type, diff ):
6832 recalculate and reschedule the contributions of the session slot with a time "diff" of separation.
6834 if type=="duration":
6835 entries = self.getSchedule().getEntries()[:]
6837 while i<len(entries):
6838 entry=entries[i]
6839 if i+1 == len(entries):
6840 dur=self.getEndDate()-entry.getStartDate()
6841 else:
6842 nextentry=entries[i+1]
6843 dur=nextentry.getStartDate()-entry.getStartDate()-diff
6844 if dur<timedelta(0):
6845 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())
6846 entry.setDuration(dur=dur)
6847 i+=1
6848 if len(entries) != 0 and self.getEndDate() < entry.getEndDate():
6849 self.setEndDate(entry.getEndDate(),2)
6850 elif type=="startingTime":
6851 st = self.getStartDate()
6852 entries = self.getSchedule().getEntries()[:]
6853 for entry in entries:
6854 entry.setStartDate(st,0,0)
6855 # add diff to last item end date if and only if the item is
6856 # not a break
6857 #if not isinstance(entry, BreakTimeSchEntry):
6858 # st=entry.getEndDate()+diff
6859 #else:
6860 # st=entry.getEndDate()
6861 st=entry.getEndDate()+diff
6862 if len(entries) != 0 and self.getEndDate() < st:
6863 self.setEndDate(st,2)
6865 def setValues(self,data,check=2, moveEntriesBelow=0):
6866 """check parameter:
6867 0: no check at all
6868 1: check and raise error in case of problem
6869 2: check and adapt the owner dates
6872 # In order to move the entries below, it is needed to know the diff (we have to move them)
6873 # and the list of entries to move. It's is needed to take those datas in advance because they
6874 # are going to be modified before the moving.
6875 if moveEntriesBelow == 1:
6876 oldStartDate=copy.copy(self.getStartDate())
6877 oldDuration=copy.copy(self.getDuration())
6878 i=self.getConfSchEntry().getSchedule().getEntries().index(self.getConfSchEntry())+1
6879 entriesList = self.getConfSchEntry().getSchedule().getEntries()[i:]
6880 self.title=data.get("title", "NO TITLE ASSIGNED")
6881 # Do we move all entries in the slot
6882 move = int(data.get("move",0))
6884 if "locationName" in data:
6885 loc = self.getOwnLocation()
6886 if not loc:
6887 loc = CustomLocation()
6888 self.setLocation( loc )
6889 loc.setName( data["locationName"] )
6890 loc.setAddress( data.get("locationAddress", "") )
6891 else:
6892 self.setLocation( None )
6894 if "roomName" in data:
6895 room = self.getOwnRoom()
6896 if not room:
6897 room = CustomRoom()
6898 self.setRoom( room )
6899 room.setName( data["roomName"] )
6900 else:
6901 self.setRoom( None )
6902 sDate = eDate = None
6903 confTZ = self.getOwner().getConference().getTimezone()
6904 if data.get("sDate",None) is not None:
6905 sd = data.get("sDate")
6906 sDate = timezone(confTZ).localize(datetime(sd.year,sd.month,sd.day,sd.hour,sd.minute))
6907 elif data.get("sYear","")!="" and data.get("sMonth","")!="" and \
6908 data.get("sDay","")!="" and data.get("sHour","")!="" and \
6909 data.get("sMinute","")!="":
6910 sDate = timezone(confTZ).localize(datetime(int(data["sYear"]),int(data["sMonth"]),
6911 int(data["sDay"]),int(data["sHour"]),
6912 int(data["sMinute"])))
6913 if data.get("eDate",None) is not None:
6914 ed = data.get("eDate")
6915 eDate = timezone(confTZ).localize(datetime(ed.year,ed.month,ed.day,ed.hour,ed.minute))
6916 elif data.get("eYear","")!="" and data.get("eMonth","")!="" and \
6917 data.get("eDay","")!="" and data.get("eHour","")!="" and \
6918 data.get("eMinute","")!="":
6919 eDate = timezone(confTZ).localize(datetime(int(data["eYear"]),int(data["eMonth"]),
6920 int(data["eDay"]),int(data["eHour"]),
6921 int(data["eMinute"])))
6922 if sDate != None and eDate != None:
6923 sDateUTC = sDate.astimezone(timezone('UTC'))
6924 eDateUTC = eDate.astimezone(timezone('UTC'))
6925 self.setDates(sDateUTC,eDateUTC,check,moveEntries=move)
6926 elif sDate != None:
6927 sDateUTC = sDate.astimezone(timezone('UTC'))
6928 self.setStartDate(sDateUTC,check,moveEntries=move)
6929 if data.get("durHours","")!="" and data.get("durMins","")!="":
6930 self.setDuration(hours=data["durHours"],minutes=data["durMins"],check=check)
6931 if data.get("contribDurHours","")!="" and data.get("contribDurMins","")!="":
6932 self.setContribDuration(int(data["contribDurHours"]),int(data["contribDurMins"]))
6933 elif data.get("contribDuration","")!="":
6934 self.setContribDuration(dur=data.get("contribDuration"))
6935 else:
6936 self.setContribDuration(None,None)
6937 conveners = data.get("conveners",None)
6938 if conveners is not None:
6939 self.clearConvenerList()
6940 for conv in conveners:
6941 sc = SlotChair()
6942 sc.setTitle(conv.getTitle())
6943 sc.setFirstName(conv.getFirstName())
6944 sc.setFamilyName(conv.getFamilyName())
6945 sc.setAffiliation(conv.getAffiliation())
6946 sc.setEmail(conv.getEmail())
6947 self.addConvener(sc)
6948 if moveEntriesBelow == 1:
6949 diff = (self.getStartDate() - oldStartDate) + (self.getDuration() - oldDuration)
6950 self.getSchedule().moveEntriesBelow(diff, entriesList)
6951 self._checkInnerSchedule()
6952 self.notifyModification()
6954 def _checkInnerSchedule( self ):
6955 self.getSchedule().checkSanity()
6957 def setContribDuration(self, hour=0, min=0, dur=None):
6958 self._contributionDuration = None
6959 if dur is not None:
6960 self._contributionDuration=dur
6961 elif hour != None and min != None:
6962 self._contributionDuration = timedelta(hours=hour,minutes=min)
6964 def getContribDuration(self):
6966 Duration by default for contributions within the slots.
6968 try:
6969 if self._contributionDuration:
6970 pass
6971 except AttributeError, e:
6972 self._contributionDuration = None
6973 return self._contributionDuration
6975 def notifyModification( self ):
6976 self.getSession().notifyModification()
6977 self._p_changed = 1
6979 def getLocator( self ):
6980 l=self.getSession().getLocator()
6981 l["slotId"]=self.getId()
6982 return l
6984 def getConference( self ):
6985 return self.getSession().getConference()
6987 def getSession(self):
6988 return self.session
6990 def getOwner( self ):
6991 return self.session
6993 def _setSchedule(self,klass):
6994 old_sch=self.getSchedule()
6995 self._schedule=klass(self)
6996 #after removing old entries, one could try to fit them into the new
6997 # schedule, but there are several things to consider which are left
6998 # for later implementation (breaks, entries not fitting in the
6999 # slots,...)
7000 while len(old_sch.getEntries())>0:
7001 entry=old_sch.getEntries()[0]
7002 old_sch.removeEntry(entry)
7003 self.notifyModification()
7005 def getSchedule(self):
7006 return self._schedule
7008 def getMasterSchedule( self ):
7009 return self.getOwner().getSchedule()
7011 def getConfSchEntry( self ):
7012 try:
7013 if self._confSchEntry:
7014 pass
7015 except AttributeError:
7016 self._confSchEntry=LinkedTimeSchEntry(self)
7017 return self._confSchEntry
7019 def getSessionSchEntry( self ):
7020 try:
7021 if self._sessionSchEntry:
7022 pass
7023 except AttributeError:
7024 self._sessionSchEntry=self._schEntry
7025 return self._sessionSchEntry
7027 def setId( self, newId ):
7028 self.id=str(newId)
7029 self.notifyModification()
7031 def getId( self ):
7032 return self.id
7034 def getUniqueId( self ):
7035 """Returns (string) the unique identiffier of the item.
7036 Used mainly in the web session access key table"""
7037 return "%sl%s" % (self.getSession().getUniqueId(),self.id)
7039 def setTitle( self, newTitle ):
7040 self.title=newTitle
7041 self.notifyModification()
7043 def getTitle( self ):
7044 try:
7045 if self.title:
7046 pass
7047 except AttributeError,e:
7048 self.title=""
7049 return self.title
7051 def getFullTitle( self ):
7052 return self.getSession().getTitle() + (": " + self.getTitle() if self.getTitle() else "")
7054 def getName(self):
7055 return "slot %s"%self.getId()
7057 def getDescription(self):
7058 return self.getSession().getDescription()
7060 def setDates(self,sDate,eDate,check=2,moveEntries=0):
7061 """check parameter:
7062 0: no check at all
7063 1: check and raise error in case of problem
7064 2: check and adapt the owner dates"""
7066 if sDate>eDate:
7067 raise MaKaCError(_("End date cannot be prior to Start date"),_("Slot"))
7069 self.setStartDate(sDate, check, moveEntries, checkDuration=False)
7070 self.setDuration(0, 0, 0, eDate-sDate, check)
7071 self.notifyModification()
7073 def getEntries(self):
7074 entriesList = self.getSchedule().getEntries()
7075 return entriesList
7077 def move(self, sDate):
7078 diff=sDate-self.startDate
7079 self.startDate = sDate
7080 for slotEntry in self.getSchedule().getEntries():
7081 if isinstance(slotEntry, BreakTimeSchEntry):
7082 slotEntry.startDate = slotEntry.getStartDate() + diff
7083 else:
7084 se = slotEntry.getOwner()
7085 se.startDate = se.getStartDate() + diff
7086 self.getSchedule().reSchedule()
7088 def verifyStartDate(self, sDate,check=2):
7089 """check parameter:
7090 0: no check at all
7091 1: check and raise error in case of problem
7092 2: check and adapt the owner dates"""
7094 tz = timezone(self.getConference().getTimezone())
7096 if sDate < self.getSession().getStartDate():
7097 if check == 1:
7098 raise ParentTimingError(_("The slot \"%s\" cannot start (%s) before its parent session starts (%s)")%\
7099 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7100 self.getSession().getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7101 _("Slot"))
7102 elif check == 2:
7103 self.getSession().setStartDate(sDate, check, 0)
7105 def setStartDate(self,sDate,check=2,moveEntries=0,checkDuration=True):
7106 """check parameter:
7107 0: no check at all
7108 1: check and raise error in case of problem
7109 2: check and adapt the owner dates"""
7110 if sDate is None:
7111 return
7112 if not sDate.tzname():
7113 raise MaKaCError("date should be timezone aware")
7114 if check != 0:
7115 #If not using .fit() at the end of this method, comment it out
7116 #if self.getSession().getStartDate() > sDate:
7117 # self.getSession().duration += self.getSession().getStartDate() - sDate
7118 self.verifyStartDate(sDate,check)
7120 # calculate the difference betwwen old and new date
7121 difference = None
7122 if self.startDate is not None:
7123 difference = sDate - self.getStartDate()
7125 self.startDate=copy.copy(sDate)
7127 if difference != None and difference != timedelta(0) and moveEntries:
7128 ContextManager.get('autoOps').append((self, "ENTRIES_MOVED",
7129 self, sDate.astimezone(timezone(self.getTimezone()))))
7130 self.getSchedule().moveEntriesBelow(difference,self.getSchedule().getEntries()[:])
7132 if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getStartDate() != sDate:
7133 self.getSession().setStartDate(sDate, check, 0)
7134 if check != 0 and self.getSession() and checkDuration:
7135 self.verifyDuration(self.getDuration(), check=check)
7137 # synchronize with other timetables
7138 self.getSessionSchEntry().synchro()
7139 self.getConfSchEntry().synchro()
7140 self.getSession().fit()
7141 self.notifyModification()
7143 def setEndDate(self,eDate,check=2):
7144 if not eDate.tzname():
7145 raise MaKaCError("date should be timezone aware")
7146 if check != 0:
7147 self.verifyDuration(eDate-self.startDate, check)
7148 self.setDuration(dur=eDate-self.startDate,check=check)
7149 if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getEndDate() != eDate:
7150 self.getSession().setEndDate(eDate, check)
7151 self.getSession().fit()
7152 self.notifyModification()
7154 def getStartDate( self ):
7155 return self.startDate
7157 def getAdjustedStartDate(self,tz=None):
7158 if not tz:
7159 tz = self.getConference().getTimezone()
7160 if tz not in all_timezones:
7161 tz = 'UTC'
7162 return self.startDate.astimezone(timezone(tz))
7164 def getEndDate( self ):
7165 if self.startDate is None:
7166 return None
7167 return self.startDate+self.duration
7169 def getAdjustedEndDate( self, tz=None ):
7170 if not tz:
7171 tz = self.getConference().getTimezone()
7172 if tz not in all_timezones:
7173 tz = 'UTC'
7174 if self.getEndDate():
7175 return self.getEndDate().astimezone(timezone(tz))
7176 return None
7178 def getDuration( self ):
7179 return self.duration
7181 def isMoreThanDay(self):
7182 if self.getDuration() >= timedelta(days=1):
7183 return True
7184 return False
7186 def verifyDuration(self, dur, check=1):
7187 """check parameter:
7188 0: no check at all
7189 1: check and raise error in case of problem
7190 2: check and adapt the owner dates"""
7192 tz = timezone(self.getConference().getTimezone())
7193 if dur <= timedelta(0):
7194 raise MaKaCError( _("The duration cannot be less than zero"), _("Slot"))
7195 if dur.days > 1:
7196 raise MaKaCError( _("The duration cannot be more than one day"), _("Slot"))
7197 if self.startDate is not None:
7198 sessionStartDate = self.getSession().getStartDate()
7199 sessionEndDate = self.getSession().getEndDate()
7200 # end date has to be between the session dates
7201 eDate = self.startDate + dur
7202 if eDate > sessionEndDate:
7203 if check==1:
7204 raise EntryTimingError(_("The session slot cannot end (%s) after its parent session (%s)") \
7205 % (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7206 sessionEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7207 _("Slot"))
7208 elif check==2:
7209 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
7210 self.getSession(), eDate.astimezone(tz)))
7211 self.getSession().setEndDate(eDate,check)
7212 if eDate.astimezone(tz).date() > self.startDate.astimezone(tz).date():
7213 raise TimingError( _("The time slot must end on the same day it has started"), _("Slot"))
7214 # do not modify if slot entries will be affected
7215 sch = self.getSchedule()
7216 entries = sch.getEntries()
7217 if entries != []:
7218 if eDate < sch.calculateEndDate():
7219 raise TimingError(_("The session slot cannot end at (%s) because there is a contribution (%s) ending after that time. ")%\
7220 (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7221 sch.calculateEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7222 _("Slot"))
7224 def setDuration(self, days=0,hours=0,minutes=0,dur=0,check=1):
7225 """check parameter:
7226 0: no check at all
7227 1: check and raise error in case of problem
7228 2: check and adapt the owner dates"""
7230 if dur==0:
7231 dur = timedelta(days=int(days),hours=int(hours),minutes=int(minutes))
7232 if dur==0 and check==2:
7233 ContextManager.get('autoOps').append((self, "DURATION_SET",
7234 self, 1))
7235 dur = timedelta(minutes=1)
7236 if dur > timedelta(days=1) and check==2:
7237 pass#dur = timedelta(days=1)
7238 if check != 0:
7239 self.verifyDuration(dur, check)
7240 self.duration = dur
7241 self.getSessionSchEntry().synchro()
7242 self.getConfSchEntry().synchro()
7243 self.getSession().fit()
7244 self.notifyModification()
7246 def getLocationParent( self ):
7248 Returns the object from which the room/location
7249 information should be inherited
7251 return self.session.conference
7253 def delete(self):
7254 self.getSchedule().clear()
7255 if self.getSession() is not None:
7256 self.getSession().removeSlot(self)
7257 self.session=None
7258 TrashCanManager().add(self)
7260 def recover(self):
7261 TrashCanManager().remove(self)
7263 def canAccess(self,aw):
7264 return self.getSession().canAccess(aw)
7266 def canView(self,aw):
7267 return self.getSession().canView(aw)
7269 def isProtected(self):
7270 return self.getSession().isProtected()
7272 def getAccessKey( self ):
7273 return self.getSession().getAccessKey()
7275 def setScheduleType(self,id):
7276 id=str(id).strip().lower()
7277 currentId=SlotSchTypeFactory.getId(self.getSchedule())
7278 if id not in SlotSchTypeFactory.getIdList() or id==currentId:
7279 return
7280 self._setSchedule(SlotSchTypeFactory.getScheduleKlass(id))
7282 def getConvenerList(self):
7283 try:
7284 if self._conveners:
7285 pass
7286 except AttributeError:
7287 self._conveners = []
7288 if self._conveners == []:
7289 return self.getSession().getConvenerList()
7290 return self._conveners
7292 def addConvener(self,newConv):
7293 if newConv in self._conveners:
7294 return
7295 try:
7296 if self._convenerGen:
7297 pass
7298 except AttributeError:
7299 self._convenerGen=Counter()
7300 id = newConv.getId()
7301 if id == "":
7302 id=int(self._convenerGen.newCount())
7303 newConv.includeInSlot(self,id)
7304 self._conveners.append(newConv)
7305 self.notifyModification()
7307 def removeConvener(self,conv):
7308 if conv not in self._conveners:
7309 return
7310 self._conveners.remove(conv)
7311 conv.delete()
7312 self.notifyModification()
7314 def recoverConvener(self, con):
7315 self.addConvener(con)
7316 con.recover()
7318 def getConvenerById(self,id):
7319 id=int(id)
7320 for conv in self._conveners:
7321 if conv.getId()==id:
7322 return conv
7323 return None
7325 def getOwnConvenerList(self):
7326 try:
7327 if self._conveners:
7328 pass
7329 except AttributeError:
7330 self._conveners = []
7331 return self._conveners
7333 def clearConvenerList(self):
7334 while len(self.getOwnConvenerList()) > 0:
7335 self._conveners.pop()
7336 self.notifyModification()
7338 def getColor(self):
7339 res=""
7340 if self.getSession() is not None:
7341 res=self.getSession().getColor()
7342 return res
7344 def getTextColor(self):
7345 res=""
7346 if self.getSession() is not None:
7347 res=self.getSession().getTextColor()
7348 return res
7350 def getAllMaterialList(self):
7351 return self.getSession().getAllMaterialList()
7354 class ContributionParticipation(Persistent, Fossilizable):
7356 fossilizes(IContributionParticipationFossil, IContributionParticipationMinimalFossil,\
7357 IContributionParticipationTTDisplayFossil,\
7358 IContributionParticipationTTMgmtFossil)
7360 def __init__( self ):
7361 self._contrib = None
7362 self._id = ""
7363 self._firstName = ""
7364 self._surName = ""
7365 self._email = ""
7366 self._affiliation = ""
7367 self._address = ""
7368 self._phone = ""
7369 self._title = ""
7370 self._fax = ""
7372 def _notifyModification( self ):
7373 if self._contrib != None:
7374 self._contrib.notifyModification()
7376 def setValues(self, data):
7377 self.setFirstName(data.get("firstName", ""))
7378 self.setFamilyName(data.get("familyName",""))
7379 self.setAffiliation(data.get("affilation",""))
7380 self.setAddress(data.get("address",""))
7381 self.setEmail(data.get("email",""))
7382 self.setFax(data.get("fax",""))
7383 self.setTitle(data.get("title",""))
7384 self.setPhone(data.get("phone",""))
7385 self._notifyModification()
7387 def getValues(self):
7388 data={}
7389 data["firstName"]=self.getFirstName()
7390 data["familyName"]=self.getFamilyName()
7391 data["affilation"]=self.getAffiliation()
7392 data["address"]=self.getAddress()
7393 data["email"]=self.getEmail()
7394 data["fax"]=self.getFax()
7395 data["title"]=self.getTitle()
7396 data["phone"]=self.getPhone()
7397 return data
7399 def clone(self):
7400 part = ContributionParticipation()
7401 part.setValues(self.getValues())
7402 return part
7404 def setDataFromAvatar(self,av):
7405 # av is an Avatar object.
7406 if av is None:
7407 return
7408 self.setFirstName(av.getName())
7409 self.setFamilyName(av.getSurName())
7410 self.setEmail(av.getEmail())
7411 self.setAffiliation(av.getOrganisation())
7412 self.setAddress(av.getAddress())
7413 self.setPhone(av.getTelephone())
7414 self.setTitle(av.getTitle())
7415 self.setFax(av.getFax())
7416 self._notifyModification()
7418 def setDataFromOtherCP(self,cp):
7419 # cp is a ContributionParticipation object.
7420 if cp is None:
7421 return
7422 self.setFirstName(cp.getFirstName())
7423 self.setFamilyName(cp.getFamilyName())
7424 self.setEmail(cp.getEmail())
7425 self.setAffiliation(cp.getAffiliation())
7426 self.setAddress(cp.getAddress())
7427 self.setPhone(cp.getPhone())
7428 self.setTitle(cp.getTitle())
7429 self.setFax(cp.getFax())
7430 self._notifyModification()
7432 def includeInContribution( self, contrib, id ):
7433 if self.getContribution() == contrib and self.getId()==id.strip():
7434 return
7435 self._contrib = contrib
7436 self._id = id
7438 def delete( self ):
7439 self._contrib = None
7440 TrashCanManager().add(self)
7442 def recover(self):
7443 TrashCanManager().remove(self)
7445 def setId(self, newId):
7446 self._id = newId
7448 def getId( self ):
7449 return self._id
7451 def getContribution( self ):
7452 return self._contrib
7454 def getConference(self):
7455 return self._contrib.getConference()
7457 def getLocator(self):
7458 if self.getContribution() is None:
7459 return None
7460 loc=self.getContribution().getLocator()
7461 loc["authId"]=self.getId()
7462 return loc
7464 def _unindex(self):
7465 contrib=self.getContribution()
7466 if contrib is not None:
7467 conf=contrib.getConference()
7468 if conf is not None:
7469 conf.unindexAuthor(self)
7470 conf.unindexSpeaker(self)
7472 def _index(self):
7473 contrib=self.getContribution()
7474 if contrib is not None:
7475 conf=contrib.getConference()
7476 if conf is not None:
7477 conf.indexAuthor(self)
7478 conf.indexSpeaker(self)
7480 @Updates ('MaKaC.conference.ContributionParticipation', 'firstName')
7481 def setFirstName( self, newName ):
7482 tmp=newName.strip()
7483 if tmp==self._firstName:
7484 return
7485 self._unindex()
7486 self._firstName=tmp
7487 self._index()
7488 self._notifyModification()
7490 def getFirstName( self ):
7491 return self._firstName
7493 def getName( self ):
7494 return self._firstName
7497 @Updates ('MaKaC.conference.ContributionParticipation', 'familyName')
7498 def setFamilyName( self, newName ):
7499 tmp=newName.strip()
7500 if tmp==self._surName:
7501 return
7502 self._unindex()
7503 self._surName=tmp
7504 self._index()
7505 self._notifyModification()
7507 def getFamilyName( self ):
7508 return self._surName
7510 def getSurName( self ):
7511 return self._surName
7514 @Updates ('MaKaC.conference.ContributionParticipation', 'email')
7515 def setEmail( self, newMail ):
7516 tmp=newMail.strip()
7517 if tmp==self._email:
7518 return
7519 self._unindex()
7520 self._email=newMail.strip()
7521 self._index()
7522 self._notifyModification()
7524 def getEmail( self ):
7525 return self._email
7527 @Updates ('MaKaC.conference.ContributionParticipation', 'affiliation')
7528 def setAffiliation( self, newAffil ):
7529 self._affiliation = newAffil.strip()
7530 self._notifyModification()
7532 def getAffiliation( self ):
7533 if self._affiliation.lower() == "unknown":
7534 return ""
7535 return self._affiliation
7537 @Updates ('MaKaC.conference.ContributionParticipation', 'address')
7538 def setAddress( self, newAddr ):
7539 self._address = newAddr.strip()
7540 self._notifyModification()
7542 def getAddress( self ):
7543 return self._address
7545 @Updates ('MaKaC.conference.ContributionParticipation', 'telephone')
7546 def setPhone( self, newPhone ):
7547 self._phone = newPhone.strip()
7548 self._notifyModification()
7550 def getPhone( self ):
7551 return self._phone
7553 @Updates ('MaKaC.conference.ContributionParticipation', 'title')
7554 def setTitle( self, newTitle ):
7555 self._title = newTitle.strip()
7556 self._notifyModification()
7558 def getTitle( self ):
7559 return self._title
7561 @Updates ('MaKaC.conference.ContributionParticipation', 'fax')
7562 def setFax( self, newFax ):
7563 self._fax = newFax.strip()
7564 self._notifyModification()
7566 def getFax( self ):
7567 try:
7568 if self._fax:
7569 pass
7570 except AttributeError:
7571 self._fax=""
7572 return self._fax
7574 def getDirectFullName( self ):
7575 res = self.getDirectFullNameNoTitle()
7576 if self.getTitle() != "":
7577 res = "%s %s"%( self.getTitle(), res )
7578 return res
7580 def getDirectFullNameNoTitle( self, upper = True ):
7581 return ("%s %s"%(self.getFirstName(), self.getFamilyName().upper() if upper else self.getFamilyName())).strip()
7583 def getFullName( self ):
7584 res = self.getFullNameNoTitle()
7585 if self.getTitle() != "":
7586 res = "%s %s"%( self.getTitle(), res )
7587 return res
7589 def getFullNameNoTitle( self ):
7590 res = self.getFamilyName().decode('utf-8').upper().encode('utf-8')
7591 if self.getFirstName() != "":
7592 if res.strip() != "":
7593 res = "%s, %s"%( res, self.getFirstName() )
7594 else:
7595 res = self.getFirstName()
7596 return res
7598 def getAbrName(self):
7599 res = self.getFamilyName()
7600 if self.getFirstName() != "":
7601 if res != "":
7602 res = "%s, "%res
7603 res = "%s%s."%(res, self.getFirstName()[0].upper())
7604 return res
7607 def isPendingSubmitter(self):
7608 if self.getContribution() is None:
7609 return False
7610 if self.getContribution().getConference() is None:
7611 return False
7612 return self.getContribution().getConference().getPendingQueuesMgr().isPendingSubmitter(self)
7614 def _cmpFamilyName( cp1, cp2 ):
7615 o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName())
7616 o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName())
7617 o1=o1.lower().strip()
7618 o2=o2.lower().strip()
7619 return cmp( o1, o2 )
7620 _cmpFamilyName=staticmethod(_cmpFamilyName)
7623 class AuthorIndex(Persistent):
7625 def __init__(self):
7626 self._idx=OOBTree()
7628 def _getKey(self,author):
7629 k = "%s %s %s"%(author.getFamilyName().lower(),author.getFirstName().lower(),author.getEmail().lower())
7630 return k.strip()
7632 def index(self,author):
7633 key=self._getKey(author)
7634 if not self._idx.has_key(key):
7635 self._idx[key]=[]
7636 l = self._idx[key]
7637 l.append(author)
7638 self._idx[key] = l
7639 self.notifyModification()
7641 def unindex(self,author):
7642 key=self._getKey(author)
7643 if self._idx.has_key(key):
7644 if author in self._idx[key]:
7645 l = self._idx[key]
7646 l.remove(author)
7647 self._idx[key] = l
7648 if len(self._idx[key])<=0:
7649 del self._idx[key]
7650 self.notifyModification()
7652 def getParticipations(self):
7653 return self._idx.values()
7655 def getById(self, id):
7656 return self._idx.get(id,None)
7658 def getByAuthorObj(self, auth):
7659 return self.getById(self._getKey(auth))
7661 def getParticipationKeys(self):
7662 return self._idx.keys()
7664 def notifyModification(self):
7665 self._idx._p_changed = 1
7666 self._p_changed = 1
7668 def iteritems(self):
7669 return self._idx.iteritems()
7671 def match(self, criteria, exact=0):
7672 self._options = ['organisation', 'surName', 'name', 'email']
7673 l = []
7674 for item in self.getParticipations():
7675 if len(item)>0:
7676 ok = []
7677 for f,v in criteria.items():
7678 if f == 'organisation' and v != '':
7679 if (exact == 0 and item[0].getAffiliation().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getAffiliation().lower() != v.lower()):
7680 ok.append(False)
7681 else:
7682 ok.append(True)
7683 if f == 'surName' and v!= '':
7684 if (exact == 0 and item[0].getSurName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getSurName().lower() != v.lower()):
7685 ok.append(False)
7686 else:
7687 ok.append(True)
7688 if f == 'name' and v!= '':
7689 if (exact == 0 and item[0].getName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getName().lower() != v.lower()):
7690 ok.append(False)
7691 else:
7692 ok.append(True)
7693 if f == 'email' and v!= '':
7694 if (exact == 0 and item[0].getEmail().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getEmail().lower() != v.lower()):
7695 ok.append(False)
7696 else:
7697 ok.append(True)
7698 if len(ok) > 0 and not False in ok:
7699 l.append(item[0])
7700 return l
7702 class _AuthIdx(Persistent):
7704 def __init__(self,conf):
7705 self._conf=conf
7706 self._idx=OOBTree()
7708 def _getKey(self,auth):
7709 return "%s %s"%(auth.getFamilyName().lower(),auth.getFirstName().lower())
7711 def index(self,auth):
7712 if auth.getContribution() is None:
7713 raise MaKaCError( _("Cannot index an author of a contribution which has not been included in a Conference"), _("Author Index"))
7714 if auth.getContribution().getConference()!=self._conf:
7715 raise MaKaCError( _("cannot index an author of a contribution which does not belong to this Conference"), _("Author Index"))
7716 key=self._getKey(auth)
7717 contribId=str(auth.getContribution().getId())
7718 if not self._idx.has_key(key):
7719 self._idx[key]=OIBTree()
7720 if not self._idx[key].has_key(contribId):
7721 self._idx[key][contribId]=0
7722 self._idx[key][contribId]+=1
7724 def unindex(self,auth):
7725 if auth.getContribution() is None:
7726 raise MaKaCError( _("Cannot unindex an author of a contribution which is not included in a conference"), _("Author Index"))
7727 if auth.getContribution().getConference()!=self._conf:
7728 raise MaKaCError( _("Cannot unindex an author of a contribution which does not belong to this conference"), _("Author Index"))
7729 key=self._getKey(auth)
7730 if not self._idx.has_key(key):
7731 return
7732 contribId=str(auth.getContribution().getId())
7733 self._idx[key][contribId]-=1
7734 if self._idx[key][contribId]<=0:
7735 del self._idx[key][contribId]
7736 if len(self._idx[key])<=0:
7737 del self._idx[key]
7739 def match(self,query):
7740 query=query.lower().strip()
7741 res=OISet()
7742 for k in self._idx.keys():
7743 if k.find(query)!=-1:
7744 res=union(res,self._idx[k])
7745 return res
7748 class _PrimAuthIdx(_AuthIdx):
7750 def __init__(self,conf):
7751 _AuthIdx.__init__(self,conf)
7752 for contrib in self._conf.getContributionList():
7753 for auth in contrib.getPrimaryAuthorList():
7754 self.index(auth)
7756 class Contribution(CommonObjectBase, Locatable):
7757 """This class implements a conference contribution, being the concrete
7758 contributes of the conference participants. The class contains
7759 necessary attributes to store contribution basic meta data and provides
7760 the useful operations to access and manage them. A contribution can be
7761 attached either to a session or to a conference.
7764 fossilizes(IContributionFossil, IContributionWithSpeakersFossil,\
7765 IContributionWithSubContribsFossil)
7767 def __init__(self,**contribData):
7768 self.parent = None
7769 self._session=None
7770 self.id = ""
7771 self.title = ""
7772 self._fields = {}
7773 self.description = ""
7774 self.startDate=None
7775 self.duration = timedelta(0)
7776 self.speakers = []
7777 self.speakerText = ""
7778 self.place = None
7779 self.room = None
7780 self._boardNumber=""
7781 self._resetSchEntry()
7782 self.__ac = AccessController(self)
7783 self.materials = {}
7784 self.__materialGenerator = Counter()
7785 self._subConts = []
7786 self.__subContGenerator = Counter()
7787 self.paper = None
7788 self.slides = None
7789 self.video = None
7790 self.poster = None
7791 self.minutes = None
7792 self.reviewing = None
7793 self._authorGen = Counter()
7794 self._authors = OOBTree()
7795 self._primaryAuthors = []
7796 self._coAuthors = []
7797 self._speakers = []
7798 self._track = None
7799 self._type = None
7800 self._status=ContribStatusNotSch(self)
7801 #List of allowed users to submit material
7802 self._submitters=[]
7803 self._submittersEmail=[]
7804 self._modificationDS = nowutc()
7805 self._keywords = ""
7806 self._reviewManager = ReviewManager(self)
7808 def __str__(self):
7809 if self.parent:
7810 parentId = self.parent.getId()
7811 else:
7812 parentId = None
7813 return "<Contribution %s:%s@%s>" % (parentId, self.getId(), hex(id(self)))
7815 def getTimezone( self ):
7816 return self.getConference().getTimezone()
7818 def getReviewManager(self):
7819 if not hasattr(self, "_reviewManager"):
7820 self._reviewManager = ReviewManager(self)
7821 return self._reviewManager
7823 def isFullyPublic( self ):
7824 if hasattr(self, "_fullyPublic"):
7825 return self._fullyPublic
7826 else:
7827 self.setFullyPublic()
7828 return self._fullyPublic
7830 def setFullyPublic( self ):
7831 if self.isProtected():
7832 self._fullyPublic = False
7833 self._p_changed = 1
7834 return
7835 for res in self.getAllMaterialList():
7836 if not res.isFullyPublic():
7837 self._fullyPublic = False
7838 self._p_changed = 1
7839 return
7840 for res in self.getSubContributionList():
7841 if not res.isFullyPublic():
7842 self._fullyPublic = False
7843 self._p_changed = 1
7844 return
7845 self._fullyPublic = True
7846 self._p_changed = 1
7848 def updateFullyPublic( self ):
7849 self.setFullyPublic()
7850 self.getOwner().updateFullyPublic()
7852 def getKeywords(self):
7853 try:
7854 return self._keywords
7855 except:
7856 self._keywords = ""
7857 return ""
7859 def setKeywords(self, keywords):
7860 if type(keywords) is list:
7861 self._keywords = keywords[0]
7862 else:
7863 self._keywords = keywords
7864 self.notifyModification()
7866 def getFields( self ):
7867 try:
7868 return self._fields
7869 except:
7870 self._fields = {}
7871 try:
7872 if self.summary != "":
7873 self._fields["summary"] = self.summary
7874 del self.summary
7875 except:
7876 pass
7877 return self._fields
7879 def removeField( self, field ):
7880 if self.getFields().has_key(field):
7881 del self.getFields()[field]
7882 self.notifyModification()
7884 def setField( self, field, value ):
7885 try:
7886 self.getFields()[field] = value
7887 self.notifyModification()
7888 except:
7889 pass
7891 def getField( self, field ):
7892 if self.getFields().has_key(field):
7893 value = self.getFields()[field]
7894 if type(value) is list:
7895 return "".join(value)
7896 elif value is None:
7897 return ""
7898 else:
7899 return value
7900 else:
7901 return ""
7903 def getLogInfo(self):
7904 data = {}
7905 data["subject"] = self.getTitle()
7906 data["id"] = self.id
7907 data["title"] = self.title
7908 data["parent title"] = self.parent.getTitle()
7909 if self._session is not None :
7910 data["session title"] = self._session.getTitle()
7911 data["description"] = self.description
7912 if self.getConference():
7913 afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr()
7914 for f in afm.getFields():
7915 id = f.getId()
7916 data[id] = self.getField(id)
7917 data["start date"] = "%s"%self.startDate
7918 data["duration"] = "%s"%self.duration
7919 if self._track is not None :
7920 data["track"] = self._track.getTitle()
7921 if self._type is not None :
7922 data["type"] = self._type
7923 data["speaker text"] = self.speakerText
7924 if self.place is not None :
7925 data["place"] = self.place.getName()
7926 if self.room is not None :
7927 data["room"] = self.room.getName()
7928 data["board number"] = self._boardNumber
7929 for sc in self.getSubContributionList() :
7930 data["subcontribution %s"%sc.getId()] = sc.getTitle()
7931 for pa in self._primaryAuthors :
7932 data["primary author %s"%pa.getId()] = pa.getFullName()
7933 for ca in self._coAuthors :
7934 data["co-author %s"%ca.getId()] = ca.getFullName()
7935 for sp in self._speakers :
7936 data["speaker %s"%sp.getId()] = sp.getFullName()
7937 for s in self._submitters :
7938 if isinstance(s, MaKaC.user.Avatar):
7939 data["submitter"] = s.getFullName()
7940 else:
7941 data["submitter"] = s.getName()
7942 return data
7945 def setValues( self, data, check=2, moveEntriesBelow=0):
7946 """Sets all the values of the current contribution object from a
7947 dictionary containing the following key-value pairs:
7948 title-(str)
7949 description-(str)
7950 locationName-(str) => name of the location, if not specified
7951 it will be set to the parent location name.
7952 locationAddress-(str)
7953 roomName-(str) => name of the room, if not specified it will
7954 be set to the parent room name.
7955 year, month, day, sHour, sMinute - (str) => components of the
7956 starting date of the session, if not specified it will
7957 be set to now.
7958 durationHours, durationMinutes - (str)
7959 speakers - (str)
7960 check parameter:
7961 0: no check at all
7962 1: check and raise error in case of problem
7963 2: check and adapt the owner dates
7964 moveEntries:
7965 0: no move
7966 1: moveEntries below the contribution
7967 Please, note that this method sets ALL values which means that if
7968 the given dictionary doesn't contain any of the keys the value
7969 will set to a default value.
7972 # In order to move the entries below, it is needed to know the diff (we have to move them)
7973 # and the list of entries to move. It's is needed to take those datas in advance because they
7974 # are going to be modified before the moving.
7975 if moveEntriesBelow == 1:
7976 oldStartDate=copy.copy(self.getStartDate())
7977 oldDuration=copy.copy(self.getDuration())
7978 i=self.getSchEntry().getSchedule().getEntries().index(self.getSchEntry())+1
7979 entriesList = self.getSchEntry().getSchedule().getEntries()[i:]
7980 if data.has_key("title"):
7981 self.setTitle(data["title"])
7982 if data.has_key("keywords"):
7983 self.setKeywords(data["keywords"])
7984 if data.has_key("description"):
7985 self.setDescription(data["description"])
7986 if data.has_key("type") and self.getConference():
7987 self.setType(self.getConference().getContribTypeById(data["type"]))
7988 if self.getConference():
7989 afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr()
7990 for f in afm.getFields():
7991 id = f.getId()
7992 if data.has_key("f_%s"%id):
7993 self.setField(id, data["f_%s"%id])
7995 if "locationName" in data:
7996 loc=self.getOwnLocation()
7997 if not loc:
7998 loc=CustomLocation()
7999 self.setLocation(loc)
8000 loc.setName(data["locationName"])
8001 loc.setAddress(data.get("locationAddress", ""))
8002 else:
8003 self.setLocation(None)
8005 #same as for the location
8006 if "roomName" in data:
8007 room=self.getOwnRoom()
8008 if not room:
8009 room=CustomRoom()
8010 self.setRoom(room)
8011 room.setName(data["roomName"])
8012 room.retrieveFullName(data.get("locationName", ""))
8013 else:
8014 self.setRoom(None)
8016 tz = 'UTC'
8017 if self.getConference():
8018 tz = self.getConference().getTimezone()
8019 if data.get("targetDay","")!="" and data.get("sHour","")!="" and data.get("sMinute","")!="" and check==2:
8020 ############################################
8021 # Fermi timezone awareness #
8022 ############################################
8023 me = timezone(tz).localize(datetime(int(data["targetDay"][0:4]), \
8024 int(data["targetDay"][5:7]),int(data["targetDay"][8:])))
8025 sdate = timezone(tz).localize(datetime(me.year,me.month, \
8026 me.day,int(data["sHour"]),int(data["sMinute"])))
8027 self.setStartDate(sdate.astimezone(timezone('UTC')),check=2)
8028 if data.get("sYear","")!="" and data.get("sMonth","")!="" and \
8029 data.get("sDay","")!="" and data.get("sHour","")!="" and \
8030 data.get("sMinute","")!="":
8031 self.setStartDate(timezone(tz).localize(datetime(int(data["sYear"]),
8032 int(data["sMonth"]), int(data["sDay"]),
8033 int(data["sHour"]), int(data["sMinute"]))).astimezone(timezone('UTC')),
8034 check=2)
8035 ############################################
8036 # Fermi timezone awareness(end) #
8037 ############################################
8038 if data.get("durTimedelta", "") != "":
8039 self.setDuration(check=check, dur=data["durTimedelta"])
8040 elif data.get("durHours","")!="" and data.get("durMins","")!="":
8041 self.setDuration(data["durHours"],data["durMins"],check)
8042 else:
8043 h=data.get("durHours","").strip()
8044 m=data.get("durMins","").strip()
8045 if h!="" or m!="":
8046 h=h or "0"
8047 m=m or "0"
8048 if h!="0" or m!="0":
8049 self.setDuration(int(h), int(m),check)
8050 if data.has_key("boardNumber"):
8051 self.setBoardNumber(data.get("boardNumber",""))
8052 if moveEntriesBelow == 1:
8053 diff = (self.getStartDate() - oldStartDate) + (self.getDuration() - oldDuration)
8054 self.getConference().getSchedule().moveEntriesBelow(diff, entriesList)
8055 self.notifyModification()
8057 def clone(self, parent, options, deltaTime = 0):
8058 cont = Contribution()
8059 parent.addContribution(cont)
8060 cont.setTitle( self.getTitle() )
8061 cont.setDescription( self.getDescription() )
8062 for k in self.getFields().keys():
8063 cont.setField(k, self.getField(k))
8064 cont.setKeywords( self.getKeywords() )
8065 if deltaTime == 0 :
8066 deltaTime = parent.getStartDate() - self.getOwner().getStartDate()
8068 startDate = None
8069 if self.startDate is not None :
8070 startDate = self.getStartDate() + deltaTime
8071 cont.setStartDate( startDate )
8073 cont.setDuration( dur=self.getDuration() )
8075 if self.getOwnLocation() is not None:
8076 cont.setLocation(self.getOwnLocation().clone())
8077 if self.getOwnRoom() is not None:
8078 cont.setRoom(self.getOwnRoom().clone())
8079 cont.setBoardNumber(self.getBoardNumber())
8080 cont.setReportNumberHolder(self.getReportNumberHolder().clone(self))
8082 cont.setStatus(self.getCurrentStatus())
8084 if self.getType() is not None :
8085 for ct in cont.getConference().getContribTypeList() :
8086 if ct.getName() == self.getType().getName() :
8087 cont.setType(ct)
8088 break
8090 if options.get("tracks", False) :
8091 if self.getTrack() is not None :
8092 for tr in cont.getConference().getTrackList() :
8093 if tr.getTitle() == self.getTrack().getTitle() :
8094 cont.setTrack(tr)
8095 break
8096 else :
8097 cont.setTrack(None)
8099 if options.get("access", False) :
8100 cont.setProtection(self.getAccessController()._getAccessProtection())
8101 for u in self.getAllowedToAccessList() :
8102 cont.grantAccess(u)
8103 for mgr in self.getManagerList() :
8104 cont.grantModification(mgr)
8105 for sub in self.getSubmitterList() :
8106 cont.grantSubmission(sub)
8107 for domain in self.getDomainList():
8108 cont.requireDomain(domain)
8110 if options.get("authors", False) :
8111 for a in self.getPrimaryAuthorList() :
8112 cont.addPrimaryAuthor(a.clone())
8113 for ca in self.getCoAuthorList() :
8114 cont.addCoAuthor(ca.clone())
8115 for sp in self.getSpeakerList():
8116 cont.newSpeaker(sp.clone())
8117 cont.setSpeakerText(self.getSpeakerText())
8119 if options.get("materials", False) :
8120 for m in self.getMaterialList() :
8121 cont.addMaterial(m.clone(cont))
8122 if self.getPaper() is not None:
8123 cont.setPaper(self.getPaper().clone(cont))
8124 if self.getSlides() is not None:
8125 cont.setSlides(self.getSlides().clone(cont))
8126 if self.getVideo() is not None:
8127 cont.setVideo(self.getVideo().clone(cont))
8128 if self.getPoster() is not None:
8129 cont.setPoster(self.getPoster().clone(cont))
8130 if self.getMinutes() is not None:
8131 cont.setMinutes(self.getMinutes().clone(cont))
8132 if self.getReviewing() is not None:
8133 cont.setReviewing(self.getReviewing().clone(cont))
8135 if options.get("subcontribs", False) :
8136 for sc in self.getSubContributionList() :
8137 cont.addSubContribution(sc.clone(cont, self, options))
8138 return cont
8140 def notifyModification( self, date = None, raiseEvent = True):
8142 self.setModificationDate(date)
8144 if raiseEvent:
8145 self._notify('infoChanged')
8147 parent = self.getParent()
8148 if parent:
8149 parent.setModificationDate()
8150 self._p_changed = 1
8152 def getCategoriesPath(self):
8153 return self.getConference().getCategoriesPath()
8155 def getModifKey( self ):
8156 return self.getConference().getModifKey()
8158 def getAccessKey( self ):
8159 return self.getConference().getAccessKey()
8161 def getLocator( self ):
8162 """Gives back a globaly unique identification encapsulated in a Locator
8163 object for the contribution instance
8165 if self.getConference() == None:
8166 return Locator()
8167 lconf = self.getConference().getLocator()
8168 if self.getSession() is not None:
8169 lconf["sessionId"] = self.getSession().getId()
8170 lconf["contribId"] = self.getId()
8171 return lconf
8173 def _setConference( self, conf ):
8174 self.parent = conf
8176 def _setId( self, id ):
8177 self.id = id
8179 def includeInConference( self, conf, id ):
8180 """sets the conference of a contribution
8182 if self.getConference() is not None:
8183 #raise MaKaCError("the contribution is already included in a conference")
8184 pass
8185 else:
8186 self._setConference( conf )
8187 self._setId( id )
8189 def delete( self ):
8190 """deletes a contribution and all of its subitems
8193 oldParent = self.getConference()
8195 if oldParent != None:
8196 self._notify('deleted', oldParent)
8198 self.setTrack(None)
8199 self.setSession(None)
8200 for mat in self.getMaterialList():
8201 self.removeMaterial(mat)
8202 self.removePaper()
8203 self.removeSlides()
8204 self.removeVideo()
8205 self.removePoster()
8206 self.removeMinutes()
8207 self.removeReviewing()
8209 while len(self.getSubContributionList()) > 0:
8211 sc = self.getSubContributionList()[0]
8213 self.removeSubContribution(sc)
8216 # delete it from parent session (if it exists)
8217 if self.getOwner() != self.getConference():
8219 self.getOwner().removeContribution( self )
8221 # (always) delete it from the parent conference
8222 self.getConference().removeContribution( self, callDelete=False )
8224 self._setConference( None )
8226 self.setStatus(ContribStatusNone(self))
8227 TrashCanManager().add(self)
8229 def recover(self):
8230 TrashCanManager().remove(self)
8232 def setId( self, newId ):
8233 self._setId(newId)
8235 def getId( self ):
8236 return self.id
8238 def getUniqueId( self ):
8239 """returns (string) the unique identifier of the item"""
8240 """used mainly in the web session access key table"""
8241 return "%st%s" % (self.getConference().getUniqueId(),self.id)
8243 def setTitle( self, newTitle, notify = True ):
8244 oldTitle = self.title
8245 self.title = newTitle.strip()
8247 if notify:
8248 self._notify('contributionTitleChanged', oldTitle, newTitle)
8249 self.notifyModification()
8251 def getTitle( self ):
8252 if self.title.strip() == "":
8253 return "(no title)"
8254 return self.title
8256 #def setDescription( self, newDesc ):
8257 # self.description = newDesc.strip()
8258 # self.notifyModification()
8260 #def getDescription( self ):
8261 # return self.description
8263 def getDescription(self):
8264 return self.getField("content")
8266 def setDescription(self, desc):
8267 self.setField("content", desc)
8269 def setParent(self,parent):
8270 self.parent=parent
8271 self.notifyModification()
8272 if self.parent==None:
8273 return
8275 def getParent( self ):
8276 if self.getSession() is not None:
8277 return self.getSession()
8278 return self.getConference()
8280 def getOwner( self ):
8281 return self.getParent()
8283 def setOwner(self, owner):
8284 self.setParent(owner)
8286 def getConference( self ):
8287 return self.parent
8289 def getSession( self ):
8290 try:
8291 if self._session:
8292 pass
8293 except AttributeError:
8294 self._session=None
8295 return self._session
8297 def setSession(self,session):
8298 if self.getSession()==session:
8299 return
8300 if self.isScheduled():
8301 schEntry=self.getSchEntry()
8302 schEntry.getSchedule().removeEntry(schEntry)
8303 oldSession=self.getSession()
8304 if oldSession is not None:
8305 oldSession.removeContribution(self)
8306 self._session=session
8307 if session is not None:
8308 session.addContribution(self)
8310 def getContribution(self):
8311 return self
8313 def _resetSchEntry(self):
8314 self.__schEntry=ContribSchEntry(self)
8316 def getSchEntry(self):
8317 if self.__schEntry is None or \
8318 not isinstance(self.__schEntry,ContribSchEntry):
8319 self._resetSchEntry()
8320 return self.__schEntry
8322 def isScheduled(self):
8323 #For the moment we do it like this
8324 return self.getSchEntry().getSchedule() is not None
8326 def isWithdrawn(self):
8327 return isinstance(self.getCurrentStatus(), ContribStatusWithdrawn)
8329 def getLocationParent( self ):
8331 Returns the object from which the room/location
8332 information should be inherited
8334 if not self.getConference().getEnableSessionSlots() and self.getSession():
8335 return self.getSession()
8336 if self.isScheduled():
8337 return self.getSchEntry().getSchedule().getOwner()
8338 return self.getOwner()
8340 def getOwnLocation( self ):
8341 return self.place
8343 def setLocation( self, newLocation ):
8344 oldLocation = self.place
8345 self.place = newLocation
8346 self._notify('locationChanged', oldLocation, newLocation)
8347 self.notifyModification()
8349 def getOwnRoom( self ):
8350 return self.room
8352 def setRoom( self, newRoom ):
8353 oldRoom = self.room
8354 self.room = newRoom
8355 self._notify('roomChanged', oldRoom, newRoom)
8356 self.notifyModification()
8358 def setBoardNumber(self,newBoardNum):
8359 self._boardNumber=str(newBoardNum).strip()
8361 def getBoardNumber(self):
8362 try:
8363 if self._boardNumber:
8364 pass
8365 except AttributeError:
8366 self._boardNumber=""
8367 return self._boardNumber
8369 def verifyStartDate(self, sDate, check=2):
8370 """check parameter:
8371 0: no check at all
8372 1: check and raise error in case of problem
8373 2: check and adapt the owner dates"""
8375 tz = timezone(self.getConference().getTimezone())
8376 if self.getSchEntry().getSchedule():
8377 owner = self.getSchEntry().getSchedule().getOwner()
8378 else:
8379 owner = self.getOwner()
8380 if sDate < owner.getStartDate():
8381 if check == 1:
8382 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start before (%s) its parent (%s)") %\
8383 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8384 owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8385 _("Contribution"))
8386 if check == 2:
8387 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
8388 owner, sDate.astimezone(tz)))
8389 owner.setDates(sDate,owner.getEndDate(), check)
8390 if sDate > owner.getEndDate():
8391 if check == 1:
8392 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start after (%s) its parent end date(%s)") %\
8393 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8394 owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8395 _("Contribution"))
8396 if check == 2:
8397 owner.setEndDate(sDate+self.getDuration(),check)
8398 # Check that after modifying the start date, the end date is still within the limits of the slot
8399 if self.getDuration() and sDate + self.getDuration() > owner.getEndDate():
8400 if check==1:
8401 raise ParentTimingError("The contribution cannot end after (%s) its parent ends (%s)"%\
8402 ((sDate + self.getDuration()).astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8403 owner.getAdjustedEndDate().strftime('%Y-%m-%d %H:%M')),\
8404 _("Contribution"))
8405 elif check==2:
8406 # update the schedule
8407 owner.setEndDate(sDate + self.getDuration(),check)
8408 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
8409 owner, owner.getAdjustedEndDate()))
8411 def setStartDate(self, newDate, check=2, moveEntries=0):
8412 """check parameter:
8413 0: no check at all
8414 1: check and raise error in case of problem
8415 2: check and adapt the owner dates"""
8416 if newDate == None:
8417 self.startDate=None
8418 return
8419 if not newDate.tzname():
8420 raise MaKaCError("date should be timezone aware")
8422 if newDate != None and check != 0:
8423 self.verifyStartDate(newDate, check)
8424 self._notify("contributionUnscheduled")
8425 self.startDate=copy.copy(newDate)
8426 self._notify("contributionScheduled")
8427 self.getSchEntry().synchro()
8428 self.notifyModification()
8430 def getStartDate( self ):
8431 return self.startDate
8433 def getAdjustedStartDate(self,tz=None):
8434 if self.getStartDate() is None:
8435 return None
8436 if not tz:
8437 tz = self.getConference().getTimezone()
8438 if tz not in all_timezones:
8439 tz = 'UTC'
8440 return self.getStartDate().astimezone(timezone(tz))
8442 def getEndDate( self ):
8443 if self.getStartDate() is None:
8444 return None
8445 return self.getStartDate()+self.getDuration()
8447 def getAdjustedEndDate(self,tz=None):
8448 if not tz:
8449 tz = self.getConference().getTimezone()
8450 if tz not in all_timezones:
8451 tz = 'UTC'
8452 if self.getEndDate():
8453 return self.getEndDate().astimezone(timezone(tz))
8454 return None
8456 def getDuration( self ):
8457 return self.duration
8459 def verifyDuration(self, check=2):
8460 """check parameter:
8461 0: no check at all
8462 1: check and raise error in case of problem
8463 2: check and adapt the owner dates"""
8465 tz = timezone(self.getConference().getTimezone())
8467 endDate = self.getEndDate()
8469 if self.getSchEntry().getSchedule() is not None:
8470 owner = self.getSchEntry().getSchedule().getOwner()
8471 if endDate > owner.getEndDate():
8472 if check==1:
8473 raise ParentTimingError(_("The contribution \"%s\" ending date (%s) has to fit between its parent's dates (%s - %s)") %\
8474 (self.getTitle(), endDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8475 owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8476 owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8477 _("Contribution"))
8478 elif check==2:
8479 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
8480 owner, self.getAdjustedEndDate()))
8481 owner.setEndDate(endDate, check)
8483 def setDuration(self,hours=0,minutes=15,check=2,dur=0):
8484 """check parameter:
8485 0: no check at all
8486 1: check and raise error in case of problem
8487 2: check and adapt the owner dates"""
8489 if dur!=0:
8490 self.duration=dur
8491 else:
8492 self.duration=timedelta(hours=int(hours),minutes=int(minutes))
8493 if check != 0:
8494 self.verifyDuration(check)
8495 self.getSchEntry().synchro()
8496 self.notifyModification()
8498 def _addAuthor( self, part ):
8501 try:
8502 if self._authors:
8503 pass
8504 except AttributeError:
8505 self._authors = OOBTree()
8506 try:
8507 if self._authorGen:
8508 pass
8509 except AttributeError:
8510 self._authorGen=Counter()
8511 newId = part.getId()
8512 if newId == "":
8513 newId = str( self._authorGen.newCount() )
8514 self._authors[newId] = part
8515 part.includeInContribution( self, newId )
8517 def _removeAuthor( self, part ):
8520 try:
8521 if self._authors:
8522 pass
8523 except AttributeError:
8524 self._authors = OOBTree()
8525 if not self._authors.has_key( part.getId() ):
8526 return
8527 del self._authors[ part.getId() ]
8528 part.delete()
8530 def addPrimaryAuthor( self, part, index = None ):
8533 try:
8534 if self._primaryAuthors:
8535 pass
8536 except AttributeError:
8537 self._primaryAuthors = []
8538 self._addAuthor( part )
8539 if index is not None:
8540 self._primaryAuthors.insert(index, part)
8541 else:
8542 self._primaryAuthors.append( part )
8543 if self.getConference() is not None:
8544 self.getConference().indexAuthor(part)
8545 self.notifyModification()
8547 def removePrimaryAuthor( self, part, removeSpeaker=1, removePendingSubm=True):
8550 try:
8551 if self._primaryAuthors:
8552 pass
8553 except AttributeError:
8554 self._primaryAuthors = []
8555 if part not in self._primaryAuthors:
8556 return
8557 if self.getConference() is not None:
8558 self.getConference().unindexAuthor(part)
8559 self._primaryAuthors.remove( part )
8560 if removeSpeaker:
8561 self.removeSpeaker( part )
8562 self._removeAuthor( part )
8563 if removePendingSubm:
8564 #--Pending queue: remove pending participant waiting to became submitter if anything
8565 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8567 self.notifyModification()
8569 def recoverPrimaryAuthor(self, pa, isPendingSubmitter):
8570 self.addPrimaryAuthor(pa)
8571 pa.recover()
8572 if isPendingSubmitter:
8573 self.getConference().getPendingQueuesMgr().addPendingSubmitter(pa, False)
8575 def isPrimaryAuthor( self, part ):
8578 try:
8579 if self._primaryAuthors:
8580 pass
8581 except AttributeError:
8582 self._primaryAuthors = []
8583 return part in self._primaryAuthors
8585 def isCoAuthor(self, part):
8586 try:
8587 if self._coAuthors:
8588 pass
8589 except AttributeError:
8590 self._coAuthors = []
8591 return part in self._coAuthors
8593 def isPrimaryAuthorByEmail(self, email):
8594 for prAuthor in self.getPrimaryAuthorList():
8595 if prAuthor.getEmail() == email:
8596 return True
8597 return False
8599 def isCoAuthorByEmail(self, email):
8600 for coAuthor in self.getCoAuthorList():
8601 if coAuthor.getEmail() == email:
8602 return True
8603 return False
8605 def isSpeakerByEmail(self, email):
8606 for speaker in self.getSpeakerList():
8607 if speaker.getEmail() == email:
8608 return True
8609 return False
8611 def changePosPrimaryAuthor(self,part,index):
8614 try:
8615 if self._primaryAuthors:
8616 pass
8617 except AttributeError:
8618 self._primaryAuthors=[]
8619 if not part in self._primaryAuthors:
8620 return
8621 self._primaryAuthors.remove(part)
8622 self._primaryAuthors.insert(index,part)
8623 self.notifyModification()
8625 def upPrimaryAuthor(self,part):
8628 try:
8629 if self._primaryAuthors:
8630 pass
8631 except AttributeError:
8632 self._primaryAuthors=[]
8633 try:
8634 idx=self._primaryAuthors.index(part)
8635 except ValueError:
8636 return
8637 if idx==0:
8638 return
8639 self._primaryAuthors.remove(part)
8640 self._primaryAuthors.insert(idx-1,part)
8641 self.notifyModification()
8643 def downPrimaryAuthor(self,part):
8646 try:
8647 if self._primaryAuthors:
8648 pass
8649 except AttributeError:
8650 self._primaryAuthors=[]
8651 try:
8652 idx=self._primaryAuthors.index(part)
8653 except ValueError:
8654 return
8655 if idx>len(self._primaryAuthors):
8656 return
8657 self._primaryAuthors.remove(part)
8658 self._primaryAuthors.insert(idx+1,part)
8659 self.notifyModification()
8661 def newAuthorsList(self, prAuthors, coAuthors):
8662 ''' calculate new lists of both kind of authors, because something has
8663 been changed the position by drag and drop '''
8664 newPrList = self.calculateNewAuthorList(prAuthors, "prAuthor")
8665 newCoList = self.calculateNewAuthorList(coAuthors, "coAuthor")
8666 self.setPrimaryAuthorList(newPrList)
8667 self.setCoAuthorList(newCoList)
8669 def calculateNewAuthorList(self, list, kind):
8670 result = []
8671 if kind == "prAuthor":
8672 for auth in list:
8673 author = self.getPrimaryAuthorById(auth['id'])
8674 if author:
8675 result.append(author)
8676 else:
8677 author = self.getCoAuthorById(auth['id'])
8678 if author:
8679 result.append(author)
8681 elif kind == "coAuthor":
8682 for auth in list:
8683 author = self.getCoAuthorById(auth['id'])
8684 if author:
8685 result.append(author)
8686 else:
8687 author = self.getPrimaryAuthorById(auth['id'])
8688 if author:
8689 result.append(author)
8690 return result
8693 def getPrimaryAuthorById(self, authorId):
8694 for author in self.getPrimaryAuthorList():
8695 if authorId == author.getId():
8696 return author
8697 return None
8699 def getCoAuthorById(self, authorId):
8700 for author in self.getCoAuthorList():
8701 if authorId == author.getId():
8702 return author
8703 return None
8705 def setPrimaryAuthorList(self, l):
8706 self._primaryAuthors = l
8707 self.notifyModification()
8709 def setCoAuthorList(self, l):
8710 self._coAuthors = l
8711 self.notifyModification()
8713 def changePosCoAuthor(self, part, index):
8716 try:
8717 if self._coAuthors:
8718 pass
8719 except AttributeError:
8720 self._coAuthors=[]
8721 if not part in self._coAuthors:
8722 return
8723 self._coAuthors.remove(part)
8724 self._coAuthors.insert(index,part)
8725 self.notifyModification()
8728 def upCoAuthor(self,part):
8731 try:
8732 if self._coAuthors:
8733 pass
8734 except AttributeError:
8735 self._coAuthors=[]
8736 try:
8737 idx=self._coAuthors.index(part)
8738 except ValueError:
8739 return
8740 if idx==0:
8741 return
8742 self._coAuthors.remove(part)
8743 self._coAuthors.insert(idx-1,part)
8744 self.notifyModification()
8746 def downCoAuthor(self,part):
8749 try:
8750 if self._coAuthors:
8751 pass
8752 except AttributeError:
8753 self._coAuthors=[]
8754 try:
8755 idx=self._coAuthors.index(part)
8756 except ValueError:
8757 return
8758 if idx>len(self._coAuthors):
8759 return
8760 self._coAuthors.remove(part)
8761 self._coAuthors.insert(idx+1,part)
8762 self.notifyModification()
8764 def getPrimaryAuthorList( self ):
8767 try:
8768 if self._primaryAuthors:
8769 pass
8770 except AttributeError:
8771 self._primaryAuthors = []
8772 return self._primaryAuthors
8774 getPrimaryAuthorsList = getPrimaryAuthorList
8776 def getAuthorList( self ):
8779 try:
8780 if self._authors:
8781 pass
8782 except AttributeError:
8783 self._authors = OOBTree()
8784 return self._authors.values()
8786 def getAllAuthors(self):
8787 """ This method returns a list composed by the primary authors
8788 and co-authors. The different with getAuthorList() is the type
8789 of the output.
8791 return self.getPrimaryAuthorList() + self.getCoAuthorList()
8793 def addCoAuthor( self, part, index=None ):
8796 try:
8797 if self._coAuthors:
8798 pass
8799 except AttributeError:
8800 self._coAuthors = []
8801 self._addAuthor( part )
8802 if index is not None:
8803 self._coAuthors.insert(index, part)
8804 else:
8805 self._coAuthors.append( part )
8806 if self.getConference() is not None:
8807 self.getConference().indexAuthor(part)
8808 self.notifyModification()
8810 def removeCoAuthor( self, part, removeSpeaker=1, removePendingSubm=True):
8813 try:
8814 if self._coAuthors:
8815 pass
8816 except AttributeError:
8817 self._coAuthors = []
8818 if part not in self._coAuthors:
8819 return
8820 if self.getConference() is not None:
8821 self.getConference().unindexAuthor(part)
8822 self._coAuthors.remove( part )
8823 if removeSpeaker:
8824 self.removeSpeaker( part )
8825 self._removeAuthor( part )
8826 if removePendingSubm:
8827 #--Pending queue: remove pending participant waiting to became submitter if anything
8828 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8830 self.notifyModification()
8832 def recoverCoAuthor(self, ca, isPendingSubmitter):
8833 self.addCoAuthor(ca)
8834 ca.recover()
8835 if isPendingSubmitter:
8836 self.getConference().getPendingQueuesMgr().addPendingSubmitter(ca, False)
8838 def getCoAuthorList( self ):
8841 try:
8842 if self._coAuthors:
8843 pass
8844 except AttributeError:
8845 self._coAuthors = []
8846 return self._coAuthors
8848 def getAuthorById( self, authorId ):
8851 try:
8852 if self._authors:
8853 pass
8854 except AttributeError:
8855 self._authors = OOBTree()
8856 return self._authors.get( authorId.strip(), None )
8858 def isAuthor( self, part ):
8861 try:
8862 if self._authors:
8863 pass
8864 except AttributeError:
8865 self._authors = OOBTree()
8866 return self._authors.has_key( part.getId() )
8868 def getSpeakerById( self, authorId ):
8871 try:
8872 if self._speakers:
8873 pass
8874 except AttributeError:
8875 self._speakers = []
8876 for spk in self._speakers:
8877 if spk.getId() == authorId:
8878 return spk
8879 return None
8881 def changePosSpeaker(self,part,index):
8884 try:
8885 if self._speakers:
8886 pass
8887 except AttributeError:
8888 self._speakers = []
8889 if not part in self._speakers:
8890 return
8891 self._speakers.remove(part)
8892 self._speakers.insert(index,part)
8893 self.notifyModification()
8895 def addSpeaker( self, part, index=None ):
8897 Adds a speaker (ContributionParticipation object) to the contribution
8898 forcing it to be one of the authors of the contribution
8900 try:
8901 if self._speakers:
8902 pass
8903 except AttributeError:
8904 self._speakers = []
8905 if not self.isAuthor( part ):
8906 raise MaKaCError( _("The Specified speaker is not the Author"), _("Contribution"))
8907 if index is not None:
8908 self._speakers.insert(index, part)
8909 else:
8910 self._speakers.append( part )
8911 if self.getConference() is not None:
8912 self.getConference().indexSpeaker(part)
8913 self.notifyModification()
8915 def newSpeaker( self, part ):
8917 Adds a new speaker (ContributionParticipation object) to the contribution
8918 setting the speakers ID and the fact it belongs to that contribution
8920 try:
8921 if self._speakers:
8922 pass
8923 except AttributeError:
8924 self._speakers = []
8925 try:
8926 if self._authorGen:
8927 pass
8928 except AttributeError:
8929 self._authorGen=Counter()
8930 self._speakers.append( part )
8931 newId = part.getId()
8932 if newId == "":
8933 newId = str( self._authorGen.newCount() )
8934 part.includeInContribution(self, newId)
8935 if self.getConference() is not None:
8936 self.getConference().indexSpeaker(part)
8937 self.notifyModification()
8939 def removeSpeaker( self, part ):
8942 try:
8943 if self._speakers:
8944 pass
8945 except AttributeError:
8946 self._speakers = []
8947 if part not in self._speakers:
8948 return
8949 self._speakers.remove( part )
8950 if self.getConference() is not None:
8951 self.getConference().unindexSpeaker(part)
8952 if part not in self.getAuthorList():
8953 part.delete()
8954 #--Pending queue: remove pending participant waiting to became submitter if anything
8955 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8957 self.notifyModification()
8959 def recoverSpeaker(self, spk, isPendingSubmitter):
8960 self.newSpeaker(spk)
8961 spk.recover()
8962 if isPendingSubmitter:
8963 self.getConference().getPendingQueuesMgr().addPendingSubmitter(spk, False)
8965 def isSpeaker( self, part ):
8968 try:
8969 if self._speakers:
8970 pass
8971 except AttributeError:
8972 self._speakers = []
8973 return part in self._speakers
8975 def getSpeakerList ( self ):
8978 try:
8979 if self._speakers:
8980 pass
8981 except AttributeError:
8982 self._speakers = []
8983 return self._speakers
8985 def getSpeakerText( self ):
8986 #to be removed
8987 try:
8988 if self.speakerText:
8989 pass
8990 except AttributeError, e:
8991 self.speakerText = ""
8992 return self.speakerText
8994 def setSpeakerText( self, newText ):
8995 self.speakerText = newText.strip()
8997 def appendSpeakerText( self, newText ):
8998 self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) )
9000 def canIPAccess( self, ip ):
9001 if not self.__ac.canIPAccess( ip ):
9002 return False
9003 if self.getOwner() != None:
9004 return self.getOwner().canIPAccess(ip)
9005 return True
9007 def isProtected( self ):
9008 # tells if a contribution is protected or not
9009 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
9011 def getAccessProtectionLevel( self ):
9012 return self.__ac.getAccessProtectionLevel()
9014 def isItselfProtected( self ):
9015 return self.__ac.isItselfProtected()
9017 def hasAnyProtection( self ):
9018 """Tells whether a contribution has any kind of protection over it:
9019 access or domain protection.
9021 if self.__ac.isProtected():
9022 return True
9023 if self.getDomainList():
9024 return True
9025 if self.getAccessProtectionLevel() == -1:
9026 return False
9027 if self.getOwner():
9028 return self.getOwner().hasAnyProtection()
9029 else:
9030 return False
9032 def hasProtectedOwner( self ):
9033 if self.getOwner() != None:
9034 return self.getOwner().isProtected()
9035 return False
9037 def setProtection( self, private ):
9039 oldValue = 1 if self.isProtected() else -1
9041 self.__ac.setProtection( private )
9042 self.updateFullyPublic()
9044 if oldValue != private:
9045 # notify listeners
9046 self._notify('protectionChanged', oldValue, private)
9048 def grantAccess( self, prin ):
9049 self.__ac.grantAccess( prin )
9050 if isinstance(prin, MaKaC.user.Avatar):
9051 prin.linkTo(self, "access")
9053 def revokeAccess( self, prin ):
9054 self.__ac.revokeAccess( prin )
9055 if isinstance(prin, MaKaC.user.Avatar):
9056 prin.unlinkTo(self, "access")
9058 def canView( self, aw ):
9059 """tells whether the specified user has access to the current object
9060 or any of its sub-objects
9062 if self.canAccess( aw ):
9063 return True
9064 ### TODO: Replace this code when plugins allow extension points+notifications ##################
9065 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
9066 if RCCollaborationAdmin.hasRights(user=aw.getUser()) or \
9067 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
9068 return True
9069 ################################################################################################
9070 for sc in self.getSubContributionList():
9071 if sc.canView( aw ):
9072 return True
9073 return False
9075 def isAllowedToAccess( self, user ):
9076 if not user:
9077 return False
9078 return (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or\
9079 self.__ac.canUserAccess( user ) or\
9080 self.canUserModify( user ) or \
9081 self.canUserSubmit(user)
9083 def canAccess( self, aw ):
9084 # Allow harvesters (Invenio, offline cache) to access
9085 # protected pages
9086 if self.__ac.isHarvesterIP(aw.getIP()):
9087 return True
9088 #####################################################
9090 if self.canModify(aw):
9091 return True
9093 if not self.canIPAccess(aw.getIP()) and not self.isAllowedToAccess( aw.getUser() ):
9094 return False
9095 if not self.isProtected():
9096 return True
9097 flag = self.isAllowedToAccess( aw.getUser() )
9098 return flag or self.getConference().canKeyAccess(aw)
9100 def grantModification( self, prin ):
9101 self.__ac.grantModification( prin )
9102 if isinstance(prin, MaKaC.user.Avatar):
9103 prin.linkTo(self, "manager")
9105 def revokeModification( self, prin ):
9106 self.__ac.revokeModification( prin )
9107 if isinstance(prin, MaKaC.user.Avatar):
9108 prin.unlinkTo(self, "manager")
9110 def canModify( self, aw ):
9111 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
9113 def canUserModify( self, av ):
9114 """Tells whether a user is allowed to modify the current contribution:
9115 only if the user is granted to modify the contribution or the user
9116 can modify any of its upper objects (i.e. conference or session).
9118 return self.getParent().canUserModify( av ) or self.__ac.canModify( av )
9120 def getManagerList( self ):
9121 return self.__ac.getModifierList()
9123 def getAllowedToAccessList( self ):
9124 return self.__ac.getAccessList()
9126 def addMaterial( self, newMat ):
9127 newMat.setId( str(self.__materialGenerator.newCount()) )
9128 newMat.setOwner( self )
9129 self.materials[ newMat.getId() ] = newMat
9130 self.notifyModification()
9132 def removeMaterial( self, mat ):
9133 if mat.getId() in self.materials.keys():
9134 self.materials[mat.getId()].setOwner(None)
9135 del self.materials[ mat.getId() ]
9136 mat.delete()
9137 self.notifyModification()
9138 elif mat.getId().lower() == 'paper':
9139 self.removePaper()
9140 self.notifyModification()
9141 elif mat.getId().lower() == 'slides':
9142 self.removeSlides()
9143 self.notifyModification()
9144 elif mat.getId().lower() == 'minutes':
9145 self.removeMinutes()
9146 self.notifyModification()
9147 elif mat.getId().lower() == 'video':
9148 self.removeVideo()
9149 self.notifyModification()
9150 elif mat.getId().lower() == 'poster':
9151 self.removePoster()
9152 self.notifyModification()
9154 def recoverMaterial(self, recMat):
9155 # Id must already be set in recMat.
9156 recMat.setOwner( self )
9157 self.materials[ recMat.getId() ] = recMat
9158 recMat.recover()
9159 self.notifyModification()
9161 def getMaterialRegistry(self):
9163 Return the correct material registry for this type
9165 from MaKaC.webinterface.materialFactories import ContribMFRegistry
9166 return ContribMFRegistry
9168 def getMaterialById( self, matId ):
9169 if matId.lower() == 'paper':
9170 return self.getPaper()
9171 elif matId.lower() == 'slides':
9172 return self.getSlides()
9173 elif matId.lower() == 'video':
9174 return self.getVideo()
9175 elif matId.lower() == 'poster':
9176 return self.getPoster()
9177 elif matId.lower() == 'minutes':
9178 return self.getMinutes()
9179 elif self.materials.has_key(matId):
9180 return self.materials[ matId ]
9181 return None
9183 def getMaterialList( self ):
9184 return self.materials.values()
9186 def getAllMaterialList( self ):
9187 l = self.getMaterialList()
9188 if self.getPaper():
9189 l.append( self.getPaper() )
9190 if self.getSlides():
9191 l.append( self.getSlides() )
9192 if self.getVideo():
9193 l.append( self.getVideo() )
9194 if self.getPoster():
9195 l.append( self.getPoster() )
9196 if self.getMinutes():
9197 l.append( self.getMinutes() )
9198 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
9199 return l
9201 def newSubContribution(self):
9202 newSub = SubContribution()
9203 self.addSubContribution(newSub)
9204 newSub._notify('created', self)
9205 return newSub
9207 def addSubContribution( self, newSubCont ):
9208 newSubCont.setId(str( self.__subContGenerator.newCount()) )
9209 newSubCont.setOwner( self )
9210 self._subConts.append( newSubCont )
9211 self.notifyModification()
9213 def removeSubContribution( self, subCont ):
9214 if subCont in self._subConts:
9215 subCont.delete()
9216 subCont.setOwner(None)
9217 self._subConts.remove(subCont)
9218 self.notifyModification()
9220 def recoverSubContribution( self, recSubCont ):
9221 # Id must already be set in recSubCont.
9222 recSubCont.setOwner( self )
9223 self._subConts.append( recSubCont )
9224 recSubCont.recover()
9225 self.notifyModification()
9227 def getSubContributionById(self, SCId):
9228 for sb in self._subConts:
9229 if sb.getId() == SCId:
9230 return sb
9232 def getSubContributionList(self):
9233 return self._subConts
9235 def iterSubContributions(self):
9236 return iter(self._subConts)
9238 def getNumberOfSubcontributions(self):
9239 return len(self._subConts)
9241 def upSubContribution(self, subcont):
9242 if subcont in self._subConts:
9243 if self._subConts.index(subcont) != 0:
9244 index = self._subConts.index(subcont)
9245 sb = self._subConts.pop(index)
9246 self._subConts.insert(index-1, sb)
9247 self.notifyModification()
9249 def downSubContribution(self, subCont):
9250 if subCont in self._subConts:
9251 if self._subConts.index(subCont) < len(self._subConts)-1:
9252 index = self._subConts.index(subCont)
9253 sb = self._subConts.pop(index)
9254 self._subConts.insert(index+1, sb)
9255 self.notifyModification()
9257 def setPaper( self, newPaper ):
9258 if self.getPaper() != None:
9259 raise MaKaCError( _("The paper for this contribution has already been set"), _("Contribution"))
9260 self.paper=newPaper
9261 self.paper.setOwner( self )
9262 self.notifyModification()
9264 def removePaper( self ):
9265 if self.paper is None:
9266 return
9267 self.paper.delete()
9268 self.paper.setOwner(None)
9269 self.paper = None
9270 self.notifyModification()
9272 def recoverPaper(self, p):
9273 self.setPaper(p)
9274 p.recover()
9276 def getPaper( self ):
9277 return self.paper
9279 def setSlides( self, newSlides ):
9280 if self.getSlides() != None:
9281 raise MaKaCError( _("The slides for this contribution have already been set"), _("contribution"))
9282 self.slides=newSlides
9283 self.slides.setOwner( self )
9284 self.notifyModification()
9286 def removeSlides( self ):
9287 if self.slides is None:
9288 return
9289 self.slides.delete()
9290 self.slides.setOwner( None )
9291 self.slides= None
9292 self.notifyModification()
9294 def recoverSlides(self, s):
9295 self.setSlides(s)
9296 s.recover()
9298 def getSlides( self ):
9299 return self.slides
9301 def setVideo( self, newVideo ):
9302 if self.getVideo() != None:
9303 raise MaKaCError( _("the video for this contribution has already been set"))
9304 self.video=newVideo
9305 self.video.setOwner( self )
9306 self.notifyModification()
9308 def removeVideo( self ):
9309 if self.getVideo() is None:
9310 return
9311 self.video.delete()
9312 self.video.setOwner(None)
9313 self.video = None
9314 self.notifyModification()
9316 def recoverVideo(self, v):
9317 self.setVideo(v)
9318 v.recover()
9320 def getVideo( self ):
9321 try:
9322 if self.video:
9323 pass
9324 except AttributeError:
9325 self.video = None
9326 return self.video
9328 def setPoster( self, newPoster ):
9329 if self.getPoster() != None:
9330 raise MaKaCError( _("the poster for this contribution has already been set"))
9331 self.poster=newPoster
9332 self.poster.setOwner( self )
9333 self.notifyModification()
9335 def removePoster( self ):
9336 if self.getPoster() is None:
9337 return
9338 self.poster.delete()
9339 self.poster.setOwner(None)
9340 self.poster = None
9341 self.notifyModification()
9343 def recoverPoster(self, p):
9344 self.setPoster(p)
9345 p.recover()
9347 def getPoster( self ):
9348 try:
9349 if self.poster:
9350 pass
9351 except AttributeError:
9352 self.poster = None
9353 return self.poster
9355 def setMinutes( self, newMinutes ):
9356 if self.getMinutes() != None:
9357 raise MaKaCError( _("the Minutes for this contribution has already been set"))
9358 self.minutes=newMinutes
9359 self.minutes.setOwner( self )
9360 self.notifyModification()
9362 def createMinutes( self ):
9363 if self.getMinutes() != None:
9364 raise MaKaCError( _("The minutes for this contribution have already been created"), _("Contribution"))
9365 self.minutes = Minutes()
9366 self.minutes.setOwner( self )
9367 self.notifyModification()
9368 return self.minutes
9370 def removeMinutes( self ):
9371 if self.getMinutes() is None:
9372 return
9373 self.minutes.delete()
9374 self.minutes.setOwner( None )
9375 self.minutes = None
9376 self.notifyModification()
9378 def recoverMinutes(self, min):
9379 self.removeMinutes() # To ensure that the current minutes are put in
9380 # the trash can.
9381 self.minutes = min
9382 self.minutes.setOwner( self )
9383 min.recover()
9384 self.notifyModification()
9385 return self.minutes
9387 def getMinutes( self ):
9388 #To be removed
9389 try:
9390 if self.minutes:
9391 pass
9392 except AttributeError, e:
9393 self.minutes = None
9394 return self.minutes
9396 def setReviewing( self, newReviewing ):
9397 if self.getReviewing() != None:
9398 raise MaKaCError( _("The reviewing maretial for this contribution has already been set"), _("Contribution"))
9399 self.reviewing=newReviewing
9400 self.reviewing.setOwner( self )
9401 self.notifyModification()
9403 def removeReviewing( self ):
9404 if self.getReviewing() is None:
9405 return
9406 self.reviewing.delete()
9407 self.reviewing.setOwner(None)
9408 self.reviewing = None
9409 self.notifyModification()
9411 def recoverReviewing(self, p):
9412 self.setReviewing(p)
9413 p.recover()
9415 def getReviewing( self ):
9416 try:
9417 if self.reviewing:
9418 pass
9419 except AttributeError, e:
9420 self.reviewing = None
9421 return self.reviewing
9423 def getMasterSchedule( self ):
9424 return self.getOwner().getSchedule()
9426 def requireDomain( self, dom ):
9427 self.__ac.requireDomain( dom )
9428 self._notify('domainAdded', dom)
9430 def freeDomain( self, dom ):
9431 self.__ac.freeDomain( dom )
9432 self._notify('domainRemoved', dom)
9434 def getDomainList( self ):
9435 return self.__ac.getRequiredDomainList()
9437 def getTrack( self ):
9438 try:
9439 if self._track:
9440 pass
9441 except AttributeError:
9442 self._track = None
9443 return self._track
9445 def setTrack( self, newTrack ):
9446 currentTrack = self.getTrack()
9447 if newTrack == currentTrack:
9448 return
9449 if currentTrack:
9450 currentTrack.removeContribution( self )
9451 self._track = newTrack
9452 if self._track:
9453 self._track.addContribution( self )
9455 def removeTrack(self, track):
9456 if track == self._track:
9457 self._track = None
9459 def setType( self, newType ):
9460 self._type = newType
9462 def getType( self ):
9463 try:
9464 if self._type:
9465 pass
9466 except AttributeError:
9467 self._type = None
9468 return self._type
9470 def getModificationDate( self ):
9471 """Returns the date in which the contribution was last modified"""
9472 try:
9473 return self._modificationDS
9474 except:
9475 if self.getConference():
9476 self._modificationDS = self.getConference().getModificationDate()
9477 else:
9478 self._modificationDS = nowutc()
9479 return self._modificationDS
9481 def getCurrentStatus(self):
9482 try:
9483 if self._status:
9484 pass
9485 except AttributeError:
9486 self._status=ContribStatusNotSch(self)
9487 return self._status
9488 getStatus = getCurrentStatus
9490 def setStatus(self,newStatus):
9493 self._status=newStatus
9495 def withdraw(self,resp,comment):
9496 """ Remove or put a contribution in a conference
9499 if self.isWithdrawn():
9500 #put back the authors in the author index
9501 for auth in self.getAuthorList():
9502 self.getConference().getAuthorIndex().index(auth)
9503 for spk in self.getSpeakerList():
9504 self.getConference().getSpeakerIndex().index(spk)
9505 #change the status of the contribution
9506 self._status=ContribStatusNotSch(self)
9508 else:
9509 #remove the authors from the author index
9510 if self.getConference() is not None:
9511 for auth in self.getAuthorList():
9512 self.getConference().getAuthorIndex().unindex(auth)
9513 for spk in self.getSpeakerList():
9514 self.getConference().unindexSpeaker(spk)
9515 #remove the contribution from any schedule it is included
9516 if self.isScheduled():
9517 self.getSchEntry().getSchedule().removeEntry(self.getSchEntry())
9518 self.getCurrentStatus().withdraw(resp,comment)
9521 def _initSubmissionPrivileges(self):
9522 """Initialises submission privileges list for a contribution.
9524 This is a temporary function used for creating the attribute in the
9525 case it does not exist into the DB
9527 try:
9528 if self._submitters:
9529 pass
9530 except AttributeError:
9531 self._submitters=[] #create the attribute
9532 self.notifyModification(raiseEvent = False)
9534 def _grantSubmission(self,av):
9535 if av not in self._submitters:
9536 self._submitters.append(av)
9537 if self.getConference() is not None:
9538 self.getConference().addContribSubmitter(self,av)
9539 if isinstance(av, MaKaC.user.Avatar):
9540 av.linkTo(self, "submission")
9541 self.notifyModification(raiseEvent = False)
9543 def _grantSubmissionEmail(self, email):
9545 Returns True if submission email was granted. False if email was already in the list.
9547 if not email.lower() in map(lambda x: x.lower(), self.getSubmitterEmailList()):
9548 self.getSubmitterEmailList().append(email)
9549 return True
9550 return False
9552 def revokeSubmissionEmail(self, email):
9553 if email in self.getSubmitterEmailList():
9554 self.getSubmitterEmailList().remove(email)
9555 self._p_changed=1
9557 def grantSubmission(self,sb, sendEmail=True):
9558 """Grants a user with submission privileges for the contribution
9559 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9561 self._initSubmissionPrivileges()
9562 if isinstance(sb, ContributionParticipation) or isinstance(sb, SubContribParticipation):
9563 ah = AvatarHolder()
9564 results=ah.match({"email":sb.getEmail()}, exact=1, forceWithoutExtAuth=True)
9565 if not results:
9566 results=ah.match({"email":sb.getEmail()}, exact=1)
9567 r=None
9568 for i in results:
9569 if i.hasEmail(sb.getEmail()):
9571 break
9572 if r is not None and r.isActivated():
9573 self._grantSubmission(r)
9574 elif sb.getEmail() != "":
9575 self.getConference().getPendingQueuesMgr().addPendingSubmitter(sb, False)
9576 submissionEmailGranted = self._grantSubmissionEmail(sb.getEmail())
9577 if submissionEmailGranted and sendEmail:
9578 notif = pendingQueues._PendingSubmitterNotification( [sb] )
9579 mail.GenericMailer.sendAndLog( notif, self.getConference() )
9580 if self.getConference() is not None:
9581 self.getConference()._getSubmitterIdx().indexEmail(sb.getEmail(),self)
9582 else:
9583 self._grantSubmission(sb)
9585 def _revokeSubmission(self,av):
9586 if av in self._submitters:
9587 self._submitters.remove(av)
9588 if self.getConference() is not None:
9589 self.getConference().removeContribSubmitter(self,av)
9590 if isinstance(av, MaKaC.user.Avatar):
9591 av.unlinkTo(self, "submission")
9592 self.notifyModification(raiseEvent = False)
9594 def revokeSubmission(self,av):
9595 """Removes submission privileges for the specified user
9597 self._initSubmissionPrivileges()
9598 self._revokeSubmission(av)
9600 def revokeAllSubmitters(self):
9601 self._submitters=[]
9602 self.notifyModification(raiseEvent = False)
9604 def getSubmitterList(self):
9605 """Gives the list of users granted with submission privileges
9607 self._initSubmissionPrivileges()
9608 return self._submitters
9610 def getSubmitterEmailList(self):
9611 try:
9612 return self._submittersEmail
9613 except:
9614 self._submittersEmail = []
9615 return self._submittersEmail
9617 def canUserSubmit(self,av):
9618 """Tells whether a user can submit material for the current contribution
9620 if av is None:
9621 return False
9622 self._initSubmissionPrivileges()
9623 for principal in self._submitters:
9624 if principal != None and principal.containsUser( av ):
9625 return True
9626 ret = False
9627 #TODO: Remove this and use pending list
9628 if isinstance(av, MaKaC.user.Avatar):
9629 for email in av.getEmails():
9630 if email.lower() in self.getSubmitterEmailList():
9631 self.grantSubmission(av)
9632 self.revokeSubmissionEmail(email)
9633 ret = True
9634 return ret
9636 def getAccessController(self):
9637 return self.__ac
9639 def getReportNumberHolder(self):
9640 try:
9641 if self._reportNumberHolder:
9642 pass
9643 except AttributeError, e:
9644 self._reportNumberHolder=ReportNumberHolder(self)
9645 return self._reportNumberHolder
9647 def setReportNumberHolder(self, rnh):
9648 self._reportNumberHolder=rnh
9650 @classmethod
9651 def contributionStartDateForSort(cls, contribution):
9652 """ Function that can be used as "key" argument to sort a list of contributions by start date
9653 The contributions with no start date will be at the end with this sort
9655 if contribution.getStartDate():
9656 return contribution.getStartDate()
9657 else:
9658 return maxDatetime()
9660 def getColor(self):
9661 res=""
9662 if self.getSession() is not None:
9663 res=self.getSession().getColor()
9664 return res
9666 def getTextColor(self):
9667 res=""
9668 if self.getSession() is not None:
9669 res=self.getSession().getTextColor()
9670 return res
9672 def getCSBookingManager(self):
9673 return self.getConference().getCSBookingManager()
9675 class AcceptedContribution( Contribution ):
9676 """This class represents a contribution which has been created from an
9677 abstract
9680 def __init__(self,abstract):
9681 Contribution.__init__(self)
9682 abstract.getConference().addContribution(self,abstract.getId())
9683 self._abstract = abstract
9684 self.setTitle( abstract.getTitle() )
9685 #self.setDescription(abstract.getField("content"))
9686 for key in abstract.getFields().keys():
9687 #if key != "content":
9688 self.setField(key, abstract.getField(key))
9689 if isinstance( abstract.getCurrentStatus(),review.AbstractStatusAccepted ):
9690 self.setTrack( abstract.getCurrentStatus().getTrack() )
9691 self.setType( abstract.getCurrentStatus().getType() )
9692 for auth in abstract.getAuthorList():
9693 c_auth = ContributionParticipation()
9694 self._setAuthorValuesFromAbstract( c_auth, auth )
9695 if abstract.isPrimaryAuthor( auth ):
9696 self.addPrimaryAuthor( c_auth )
9697 else:
9698 self.addCoAuthor( c_auth )
9699 if abstract.isSpeaker( auth ):
9700 self.addSpeaker( c_auth )
9701 self._grantSubmission(self.getAbstract().getSubmitter().getUser())
9703 def _setAuthorValuesFromAbstract( self, cAuth, aAuth ):
9704 cAuth.setTitle( aAuth.getTitle() )
9705 cAuth.setFirstName( aAuth.getFirstName() )
9706 cAuth.setFamilyName( aAuth.getSurName() )
9707 cAuth.setEmail( aAuth.getEmail() )
9708 cAuth.setAffiliation( aAuth.getAffiliation() )
9709 cAuth.setAddress( aAuth.getAddress() )
9710 cAuth.setPhone( aAuth.getTelephone() )
9712 def getAbstract( self ):
9713 return self._abstract
9715 def setAbstract(self, abs):
9716 self._abstract = abs
9718 def _initSubmissionPrivileges(self):
9719 """Initialises submission privileges list for a contribution.
9721 In the case of an AcceptedContribution, the list of submitters
9722 must be initialised with the abstract's one.
9724 This is a temporary function used for creating the attribute in the
9725 case it does not exist into the DB
9727 try:
9728 if self._submitters:
9729 pass
9730 except AttributeError:
9731 self._submitters=[]#create the attribute
9732 self._grantSubmission(self.getAbstract().getSubmitter().getUser())
9734 def delete( self ):
9735 """deletes a contribution and all of their subitems
9737 abs = self.getAbstract()
9738 if abs:
9739 cs=abs.getCurrentStatus()
9740 if isinstance(cs, review.AbstractStatusAccepted):
9741 if cs.getTrack() is not None:
9742 abs.addTrack(cs.getTrack())
9743 abs.setCurrentStatus(review.AbstractStatusSubmitted(abs))
9744 abs._setContribution(None)
9745 self.setAbstract(None)
9746 Contribution.delete(self)
9750 class ContribStatus(Persistent):
9754 def __init__(self,contribution,responsible):
9755 self._setContrib(contribution)
9756 self._setResponsible(responsible)
9757 self._setDate()
9759 def clone(self, contribution, responsible):
9760 cs = ContribStatus(contribution, responsible)
9761 cs.setDate(self.getDate())
9762 return cs
9764 def _setContrib(self,newContrib):
9765 self._contrib=newContrib
9767 def getContrib(self):
9768 return self._contrib
9770 def _setResponsible(self,newResp):
9771 self._responsible=newResp
9773 def getResponsible(self):
9774 return self._responsible
9776 def _setDate(self):
9777 self._date=nowutc()
9779 def setDate(self, date):
9780 self._date = date
9782 def getDate(self):
9783 return self._date
9785 def withdraw(self,resp,comments=""):
9786 self._contrib.setStatus(ContribStatusWithdrawn(self.getContrib(),resp,comments))
9788 class ContribStatusNotSch(ContribStatus):
9791 def __init__(self,contrib):
9792 ContribStatus.__init__(self,contrib,None)
9794 def clone(self, contribution):
9795 csns = ContribStatusNotSch(contribution)
9796 csns.setDate(self.getDate())
9797 return csns
9799 ContribStatusSubmitted=ContribStatusNotSch
9801 class ContribStatusSch(ContribStatus):
9804 def __init__(self,contrib):
9805 ContribStatus.__init__(self,contrib,None)
9807 def clone(self, contribution):
9808 css = ContribStatusSch(contribution)
9809 css.setDate(self.getDate())
9810 return css
9812 class ContribStatusWithdrawn(ContribStatus):
9815 def __init__(self,contrib,resp,comments):
9816 ContribStatus.__init__(self,contrib,resp)
9817 self._setComment(comments)
9819 def clone(self, contribution):
9820 csw = ContribStatusWithdrawn(contribution)
9821 csw.setDate(self.getDate())
9822 csw.setComment(self.getComment())
9823 return csw
9825 def _setComment(self,text):
9826 self._comment=text.strip()
9828 def getComment(self):
9829 return self._comment
9831 class ContribStatusNone(ContribStatus):
9832 # This is a special status we assign to contributions that are put in the trash can.
9834 def __init__(self,contrib):
9835 ContribStatus.__init__(self,contrib,None)
9837 def clone(self, contribution):
9838 csn = ContribStatusNone(contribution)
9839 csn.setDate(self.getDate())
9840 return csn
9842 class SubContribParticipation(Persistent, Fossilizable):
9844 fossilizes(ISubContribParticipationFossil, ISubContribParticipationFullFossil)
9846 def __init__( self ):
9847 self._subContrib = None
9848 self._id = ""
9849 self._firstName = ""
9850 self._surName = ""
9851 self._email = ""
9852 self._affiliation = ""
9853 self._address = ""
9854 self._phone = ""
9855 self._title = ""
9856 self._fax = ""
9858 def getConference(self):
9859 if self._subContrib is not None:
9860 return self._subContrib.getConference()
9861 return None
9863 def _notifyModification( self ):
9864 if self._subContrib != None:
9865 self._subContrib.notifyModification()
9867 def setValues(self, data):
9868 self.setFirstName(data.get("firstName", ""))
9869 self.setFamilyName(data.get("familyName",""))
9870 self.setAffiliation(data.get("affilation",""))
9871 self.setAddress(data.get("address",""))
9872 self.setEmail(data.get("email",""))
9873 self.setFax(data.get("fax",""))
9874 self.setTitle(data.get("title",""))
9875 self.setPhone(data.get("phone",""))
9876 self._notifyModification()
9878 def getValues(self):
9879 data={}
9880 data["firstName"]=self.getFirstName()
9881 data["familyName"]=self.getFamilyName()
9882 data["affilation"]=self.getAffiliation()
9883 data["address"]=self.getAddress()
9884 data["email"]=self.getEmail()
9885 data["fax"]=self.getFax()
9886 data["title"]=self.getTitle()
9887 data["phone"]=self.getPhone()
9888 return data
9890 def clone(self):
9891 part = SubContribParticipation()
9892 part.setValues(self.getValues())
9893 return part
9895 def setDataFromAvatar(self,av):
9896 # av is an Avatar object.
9897 if av is None:
9898 return
9899 self.setFirstName(av.getName())
9900 self.setFamilyName(av.getSurName())
9901 self.setEmail(av.getEmail())
9902 self.setAffiliation(av.getOrganisation())
9903 self.setAddress(av.getAddress())
9904 self.setPhone(av.getTelephone())
9905 self.setTitle(av.getTitle())
9906 self.setFax(av.getFax())
9907 self._notifyModification()
9909 def setDataFromAuthor(self,au):
9910 # au is a ContributionParticipation object.
9911 if au is None:
9912 return
9913 self.setFirstName(au.getFirstName())
9914 self.setFamilyName(au.getFamilyName())
9915 self.setEmail(au.getEmail())
9916 self.setAffiliation(au.getAffiliation())
9917 self.setAddress(au.getAddress())
9918 self.setPhone(au.getPhone())
9919 self.setTitle(au.getTitle())
9920 self.setFax(au.getFax())
9921 self._notifyModification()
9923 def setDataFromSpeaker(self,spk):
9924 # spk is a SubContribParticipation object.
9925 if spk is None:
9926 return
9927 self.setFirstName(spk.getFirstName())
9928 self.setFamilyName(spk.getFamilyName())
9929 self.setEmail(spk.getEmail())
9930 self.setAffiliation(spk.getAffiliation())
9931 self.setAddress(spk.getAddress())
9932 self.setPhone(spk.getPhone())
9933 self.setTitle(spk.getTitle())
9934 self.setFax(spk.getFax())
9935 self._notifyModification()
9937 def includeInSubContrib( self, subcontrib, id ):
9938 if self.getSubContrib() == subcontrib and self.getId()==id.strip():
9939 return
9940 self._subContrib = subcontrib
9941 self._id = id
9943 def delete( self ):
9944 self._subContrib = None
9945 TrashCanManager().add(self)
9947 def recover(self):
9948 TrashCanManager().remove(self)
9950 @Updates ('MaKaC.conference.SubContribParticipation', 'id')
9951 def setId(self, newId):
9952 self._id = newId
9954 def getId( self ):
9955 return self._id
9957 def getSubContrib( self ):
9958 return self._subContrib
9960 def getContribution( self ):
9961 if self._subContrib is not None:
9962 return self._subContrib.getContribution()
9963 return None
9965 # def getLocator(self):
9966 # if self.getSubContrib() is None:
9967 # return None
9968 # loc=self.getSubContrib().getLocator()
9969 # loc["authId"]=self.getId()
9970 # return loc
9972 def _unindex(self):
9973 contrib=self.getContribution()
9974 if contrib is not None:
9975 conf=contrib.getConference()
9976 if conf is not None:
9977 conf.unindexAuthor(self)
9978 conf.unindexSpeaker(self)
9980 def _index(self):
9981 contrib=self.getContribution()
9982 if contrib is not None:
9983 conf=contrib.getConference()
9984 if conf is not None:
9985 conf.indexAuthor(self)
9986 conf.indexSpeaker(self)
9988 @Updates ('MaKaC.conference.SubContribParticipation', 'firstName')
9989 def setFirstName( self, newName ):
9990 tmp=newName.strip()
9991 if tmp==self._firstName:
9992 return
9993 self._unindex()
9994 self._firstName=tmp
9995 self._index()
9996 self._notifyModification()
9998 def getFirstName( self ):
9999 return self._firstName
10001 def getName( self ):
10002 return self._firstName
10004 @Updates ('MaKaC.conference.SubContribParticipation', 'familyName')
10005 def setFamilyName( self, newName ):
10006 tmp=newName.strip()
10007 if tmp==self._surName:
10008 return
10009 self._unindex()
10010 self._surName=tmp
10011 self._index()
10012 self._notifyModification()
10014 def getFamilyName( self ):
10015 return self._surName
10017 def getSurName( self ):
10018 return self._surName
10020 @Updates ('MaKaC.conference.SubContribParticipation', 'email')
10021 def setEmail( self, newMail ):
10022 tmp=newMail.strip()
10023 if tmp==self._email:
10024 return
10025 self._unindex()
10026 self._email=newMail.strip()
10027 self._index()
10028 self._notifyModification()
10030 def getEmail( self ):
10031 return self._email
10033 @Updates ('MaKaC.conference.SubContribParticipation', 'affiliation')
10034 def setAffiliation( self, newAffil ):
10035 self._affiliation = newAffil.strip()
10036 self._notifyModification()
10038 def getAffiliation( self ):
10039 return self._affiliation
10041 @Updates ('MaKaC.conference.SubContribParticipation', 'address')
10042 def setAddress( self, newAddr ):
10043 self._address = newAddr.strip()
10044 self._notifyModification()
10046 def getAddress( self ):
10047 return self._address
10049 @Updates ('MaKaC.conference.SubContribParticipation', 'phone')
10050 def setPhone( self, newPhone ):
10051 self._phone = newPhone.strip()
10052 self._notifyModification()
10054 def getPhone( self ):
10055 return self._phone
10057 @Updates ('MaKaC.conference.SubContribParticipation', 'title')
10058 def setTitle( self, newTitle ):
10059 self._title = newTitle.strip()
10060 self._notifyModification()
10062 def getTitle( self ):
10063 return self._title
10065 def setFax( self, newFax ):
10066 self._fax = newFax.strip()
10067 self._notifyModification()
10069 def getFax( self ):
10070 try:
10071 if self._fax:
10072 pass
10073 except AttributeError:
10074 self._fax=""
10075 return self._fax
10077 def getFullName( self ):
10078 res = self.getFullNameNoTitle()
10079 if self.getTitle() != "":
10080 res = "%s %s"%( self.getTitle(), res )
10081 return res
10083 def getFullNameNoTitle( self ):
10084 res = self.getFamilyName().decode('utf-8').upper().encode('utf-8')
10085 if self.getFirstName() != "":
10086 if res.strip() != "":
10087 res = "%s, %s"%( res, self.getFirstName() )
10088 else:
10089 res = self.getFirstName()
10090 return res
10092 def getAbrName(self):
10093 res = self.getFamilyName()
10094 if self.getFirstName() != "":
10095 if res != "":
10096 res = "%s, "%res
10097 res = "%s%s."%(res, self.getFirstName()[0].upper())
10098 return res
10100 def getDirectFullName( self ):
10101 res = self.getDirectFullNameNoTitle()
10102 if self.getTitle() != "":
10103 res = "%s %s"%( self.getTitle(), res )
10104 return res
10106 def getDirectFullNameNoTitle( self, upper = True ):
10107 return ("%s %s"%(self.getFirstName(), self.getFamilyName().upper() if upper else self.getFamilyName())).strip()
10109 class SubContribution(CommonObjectBase, Locatable):
10113 fossilizes(ISubContributionFossil, ISubContributionWithSpeakersFossil)
10115 def __init__( self, **subContData ):
10116 self.parent = None
10117 self.id = ""
10118 self.title = ""
10119 self.description = ""
10120 self.__schEntry = None
10121 self.duration = timedelta( minutes=15 )
10122 self.speakers = []
10123 self.speakerText = ""
10125 self.materials = {}
10126 self.__materialGenerator = Counter() # Provides material unique
10127 # identifiers whithin the current
10128 self.poster = None # contribution
10129 self.paper = None
10130 self.slides = None
10131 self.video = None
10132 self.poster = None
10133 self.minutes = None
10134 self._authorGen = Counter()
10135 self._keywords = ""
10137 def __str__(self):
10138 if self.parent:
10139 parentId = self.parent.getId()
10140 if self.getConference():
10141 grandpaId = self.getConference().getId()
10142 else:
10143 grandpaId = None
10144 else:
10145 parentId = None
10146 grandpaId = None
10147 return "<SubCont %s:%s:%s@%s>" % (grandpaId, parentId, self.getId(), hex(id(self)))
10149 def isFullyPublic( self ):
10150 if hasattr(self, "_fullyPublic"):
10151 return self._fullyPublic
10152 else:
10153 self.setFullyPublic()
10154 return self._fullyPublic
10156 def setFullyPublic( self ):
10157 for res in self.getAllMaterialList():
10158 if not res.isFullyPublic():
10159 self._fullyPublic = False
10160 self._p_changed = 1
10161 return
10162 self._fullyPublic = True
10163 self._p_changed = 1
10165 def updateFullyPublic( self ):
10166 self.setFullyPublic()
10167 self.getOwner().updateFullyPublic()
10169 def getAccessController(self):
10170 return self.getOwner().getAccessController()
10172 def getKeywords(self):
10173 try:
10174 return self._keywords
10175 except:
10176 self._keywords = ""
10177 return ""
10179 def setKeywords(self, keywords):
10180 self._keywords = keywords
10182 def getLogInfo(self):
10183 data = {}
10185 data["subject"] = self.getTitle()
10186 data["id"] = self.id
10187 data["title"] = self.title
10188 data["parent title"] = self.getParent().getTitle()
10189 data["description"] = self.description
10190 data["duration"] = "%s"%self.duration
10191 data["minutes"] = self.minutes
10193 for sp in self.speakers :
10194 data["speaker %s"%sp.getId()] = sp.getFullName()
10196 return data
10199 def clone(self, deltaTime, parent, options):
10200 sCont = SubContribution()
10201 sCont.setParent(parent)
10202 sCont.setTitle(self.getTitle())
10203 sCont.setDescription(self.getDescription())
10204 sCont.setKeywords(self.getKeywords())
10205 dur = self.getDuration()
10206 hours = dur.seconds / 3600
10207 minutes = (dur.seconds % 3600) / 60
10208 sCont.setDuration(hours, minutes)
10209 sCont.setReportNumberHolder(self.getReportNumberHolder().clone(self))
10211 # There is no _order attribute in this class
10213 if options.get("authors", False) :
10214 for s in self.getSpeakerList() :
10215 sCont.newSpeaker(s.clone())
10216 sCont.setSpeakerText(self.getSpeakerText())
10218 if options.get("materials", False) :
10219 for m in self.getMaterialList() :
10220 sCont.addMaterial(m.clone(sCont))
10221 if self.getPaper() is not None:
10222 sCont.setPaper(self.getPaper().clone(sCont))
10223 if self.getSlides() is not None:
10224 sCont.setSlides(self.getSlides().clone(sCont))
10225 if self.getVideo() is not None:
10226 sCont.setVideo(self.getVideo().clone(sCont))
10227 if self.getPoster() is not None:
10228 sCont.setPoster(self.getPoster().clone(sCont))
10229 if self.getMinutes() is not None:
10230 sCont.setMinutes(self.getMinutes().clone(sCont))
10233 sCont.notifyModification()
10234 return sCont
10236 def notifyModification( self ):
10237 parent = self.getParent()
10238 if parent:
10239 parent.setModificationDate()
10240 self._notify('infoChanged')
10241 self._p_changed = 1
10243 def getCategoriesPath(self):
10244 return self.getConference().getCategoriesPath()
10246 def getLocator( self ):
10247 """Gives back a globaly unique identification encapsulated in a Locator
10248 object for the contribution instance
10251 lconf = self.getOwner().getLocator()
10252 lconf["subContId"] = self.getId()
10253 return lconf
10256 def setId( self, newId ):
10257 self.id = newId
10259 def getId( self ):
10260 return self.id
10262 def getUniqueId( self ):
10263 """returns (string) the unique identifier of the item"""
10264 """used mainly in the web session access key table"""
10265 return "%ssc%s" % (self.getParent().getUniqueId(),self.id)
10267 def setTitle( self, newTitle ):
10268 self.title = newTitle.strip()
10269 self.notifyModification()
10271 def getTitle( self ):
10272 if self.title.strip() == "":
10273 return "(no title)"
10274 return self.title
10276 def setDescription( self, newDesc ):
10277 self.description = newDesc.strip()
10278 self.notifyModification()
10280 def getDescription( self ):
10281 return self.description
10283 def setParent(self,parent):
10284 self.parent = parent
10285 if self.parent == None:
10286 return
10288 def getParent( self ):
10289 return self.parent
10291 def setOwner(self, owner):
10292 self.setParent(owner)
10294 def getOwner( self ):
10295 return self.getParent()
10297 def getConference( self ):
10298 return self.parent.getConference()
10300 def getSession( self ):
10301 return self.parent.getSession()
10303 def getContribution(self):
10304 return self.parent
10306 def getDuration( self ):
10307 return self.duration
10309 def setDuration( self, hours, minutes=0, dur=0 ):
10310 if dur!=0:
10311 self.duration=dur
10312 else:
10313 hours = int( hours )
10314 minutes = int( minutes )
10315 self.duration = timedelta(hours=hours,minutes=minutes )
10316 self.notifyModification()
10318 def getLocation( self ):
10319 return self.getOwner().getLocation()
10321 def getRoom( self ):
10322 return self.getOwner().getRoom()
10324 def getSpeakerById( self, id ):
10327 for spk in self.speakers:
10328 if spk.getId() == id:
10329 return spk
10330 return None
10332 def newSpeaker( self, spk ):
10335 self.speakers.append( spk )
10336 try:
10337 if self._authorGen:
10338 pass
10339 except AttributeError:
10340 self._authorGen=Counter()
10341 newId = spk.getId()
10342 if newId == "":
10343 newId = str( self._authorGen.newCount() )
10344 spk.includeInSubContrib(self, newId)
10345 if self.getConference() is not None:
10346 self.getConference().indexSpeaker(spk)
10347 self.notifyModification()
10349 def removeSpeaker( self, spk ):
10352 if spk not in self.speakers:
10353 return
10354 self.speakers.remove( spk )
10355 if self.getConference() is not None:
10356 self.getConference().unindexSpeaker(spk)
10357 spk.delete()
10358 self.notifyModification()
10360 def recoverSpeaker(self, spk):
10361 self.newSpeaker(spk)
10362 spk.recover()
10364 def isSpeaker( self, spk):
10367 return spk in self._speakers
10369 def getSpeakerList ( self ):
10372 return self.speakers
10374 def getSpeakerText( self ):
10375 #to be removed
10376 try:
10377 if self.speakerText:
10378 pass
10379 except AttributeError, e:
10380 self.speakerText = ""
10381 return self.speakerText
10383 def setSpeakerText( self, newText ):
10384 self.speakerText = newText.strip()
10386 def appendSpeakerText( self, newText ):
10387 self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) )
10389 # """
10390 # There is no _order attribute in this class -
10391 # the methods below are either obsolate or the feature has not been implemented
10392 # """
10393 # def setOrder( self, order ):
10394 # self._order = order
10395 # self.notifyModification()
10397 # def getOrder(self):
10398 # return self._order
10400 def canIPAccess( self, ip ):
10401 return self.getOwner().canIPAccess(ip)
10403 def isProtected( self ):
10404 return self.hasProtectedOwner()
10406 def getAccessProtectionLevel( self ):
10407 return self.getOwner().getAccessProtectionLevel()
10409 def hasAnyProtection( self ):
10410 """Tells whether a subContribution has any kind of protection over it:
10411 access or domain protection.
10413 return self.getOwner().hasAnyProtection()
10415 def getManagerList( self ):
10416 return self.parent.getManagerList()
10418 def hasProtectedOwner( self ):
10419 if self.getOwner() != None:
10420 return self.getOwner().isProtected()
10421 return False
10423 def getAccessKey( self ):
10424 return self.getOwner().getAccessKey()
10426 def getModifKey( self ):
10427 return self.getConference().getModifKey()
10429 def canView( self, aw ):
10430 """tells whether the specified user has access to the current object
10431 or any of its sub-objects
10433 if self.canAccess( aw ):
10434 return True
10435 return False
10437 def isAllowedToAccess( self, user ):
10438 return self.parent.isAllowedToAccess( user )
10440 def canAccess( self, aw ):
10441 return self.getOwner().canAccess(aw)
10443 def canModify( self, aw ):
10444 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
10446 def canUserModify( self, av ):
10447 """Tells whether a user is allowed to modify the current contribution:
10448 only if the user is granted to modify the contribution or the user
10449 can modify any of its upper objects (i.e. conference or session).
10451 return self.getParent().canUserModify( av )
10453 def canUserSubmit( self, av ):
10454 return self.getOwner().canUserSubmit( av )
10456 def getAllowedToAccessList( self ):
10457 """Currently the SubContribution class has no access list.
10458 But instead of returning the owner Contribution's access list,
10459 I am returning an empty list. Methods such as getRecursiveAllowedToAccess()
10460 will call the owner Contribution anyway.
10462 return []
10464 def addMaterial( self, newMat ):
10465 newMat.setId( str(self.__materialGenerator.newCount()) )
10466 newMat.setOwner( self )
10467 self.materials[ newMat.getId() ] = newMat
10468 self.notifyModification()
10470 def removeMaterial( self, mat):
10471 if mat.getId() in self.materials.keys():
10472 self.materials[mat.getId()].setOwner(None)
10473 del self.materials[ mat.getId() ]
10474 mat.delete()
10475 self.notifyModification()
10476 elif mat.getId().lower() == 'paper':
10477 self.removePaper()
10478 self.notifyModification()
10479 elif mat.getId().lower() == 'slides':
10480 self.removeSlides()
10481 self.notifyModification()
10482 elif mat.getId().lower() == 'minutes':
10483 self.removeMinutes()
10484 self.notifyModification()
10485 elif mat.getId().lower() == 'video':
10486 self.removeVideo()
10487 self.notifyModification()
10488 elif mat.getId().lower() == 'poster':
10489 self.removePoster()
10490 self.notifyModification()
10492 def recoverMaterial(self, recMat):
10493 # Id must already be set in recMat.
10494 recMat.setOwner( self )
10495 self.materials[ recMat.getId() ] = recMat
10496 recMat.recover()
10497 self.notifyModification()
10499 def getMaterialRegistry(self):
10501 Return the correct material registry for this type
10503 from MaKaC.webinterface.materialFactories import SubContributionMFRegistry
10504 return SubContributionMFRegistry
10506 def getMaterialById( self, matId ):
10507 if matId.lower() == 'paper':
10508 return self.getPaper()
10509 elif matId.lower() == 'slides':
10510 return self.getSlides()
10511 elif matId.lower() == 'video':
10512 return self.getVideo()
10513 elif matId.lower() == 'poster':
10514 return self.getPoster()
10515 elif matId.lower() == 'minutes':
10516 return self.getMinutes()
10517 elif self.materials.has_key(matId):
10518 return self.materials[ matId ]
10519 return None
10521 def getMaterialList( self ):
10522 return self.materials.values()
10524 def getAllMaterialList( self ):
10525 l = self.getMaterialList()
10526 if self.getPaper():
10527 l.append( self.getPaper() )
10528 if self.getSlides():
10529 l.append( self.getSlides() )
10530 if self.getVideo():
10531 l.append( self.getVideo() )
10532 if self.getMinutes():
10533 l.append( self.getMinutes() )
10534 if self.getPoster():
10535 l.append( self.getPoster() )
10536 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
10537 return l
10539 def setPaper( self, newPaper ):
10540 if self.getPaper() != None:
10541 raise MaKaCError( _("The paper for this subcontribution has already been set"), _("Contribution"))
10542 self.paper=newPaper
10543 self.paper.setOwner( self )
10544 self.notifyModification()
10546 def removePaper( self ):
10547 if self.getPaper() is None:
10548 return
10549 self.paper.delete()
10550 self.paper.setOwner(None)
10551 self.paper = None
10552 self.notifyModification()
10554 def recoverPaper(self, p):
10555 self.setPaper(p)
10556 p.recover()
10558 def getPaper( self ):
10559 return self.paper
10561 def setSlides( self, newSlides ):
10562 if self.getSlides() != None:
10563 raise MaKaCError( _("The slides for this subcontribution have already been set"), _("Contribution"))
10564 self.slides=newSlides
10565 self.slides.setOwner( self )
10566 self.notifyModification()
10568 def removeSlides( self ):
10569 if self.getSlides() is None:
10570 return
10571 self.slides.delete()
10572 self.slides.setOwner( None )
10573 self.slides = None
10574 self.notifyModification()
10576 def recoverSlides(self, s):
10577 self.setSlides(s)
10578 s.recover()
10580 def getSlides( self ):
10581 return self.slides
10583 def setVideo( self, newVideo ):
10584 if self.getVideo() != None:
10585 raise MaKaCError( _("the video for this subcontribution has already been set"))
10586 self.video=newVideo
10587 self.video.setOwner( self )
10588 self.notifyModification()
10590 def removeVideo( self ):
10591 if self.getVideo() is None:
10592 return
10593 self.video.delete()
10594 self.video.setOwner(None)
10595 self.video = None
10596 self.notifyModification()
10598 def recoverVideo(self, v):
10599 self.setVideo(v)
10600 v.recover()
10602 def getVideo( self ):
10603 try:
10604 if self.video:
10605 pass
10606 except AttributeError:
10607 self.video = None
10608 return self.video
10610 def setPoster( self, newPoster ):
10611 if self.getPoster() != None:
10612 raise MaKaCError( _("the poster for this subcontribution has already been set"))
10613 self.poster=newPoster
10614 self.poster.setOwner( self )
10615 self.notifyModification()
10617 def removePoster( self ):
10618 if self.getPoster() is None:
10619 return
10620 self.poster.delete()
10621 self.poster.setOwner(None)
10622 self.poster = None
10623 self.notifyModification()
10625 def recoverPoster(self, p):
10626 self.setPoster(p)
10627 p.recover()
10629 def getPoster( self ):
10630 try:
10631 if self.poster:
10632 pass
10633 except AttributeError:
10634 self.poster = None
10635 return self.poster
10637 def setMinutes( self, newMinutes ):
10638 if self.getMinutes() != None:
10639 raise MaKaCError( _("the Minutes for this subcontribution has already been set"))
10640 self.minutes=newMinutes
10641 self.minutes.setOwner( self )
10642 self.notifyModification()
10644 def createMinutes( self ):
10645 if self.getMinutes() != None:
10646 raise MaKaCError( _("The minutes for this subcontribution have already been created"), _("Sub Contribution"))
10647 self.minutes = Minutes()
10648 self.minutes.setOwner( self )
10649 self.notifyModification()
10650 return self.minutes
10652 def removeMinutes( self ):
10653 if self.getMinutes() is None:
10654 return
10655 self.minutes.delete()
10656 self.minutes.setOwner( None )
10657 self.minutes = None
10658 self.notifyModification()
10660 def recoverMinutes(self, min):
10661 self.removeMinutes() # To ensure that the current minutes are put in
10662 # the trash can.
10663 self.minutes = min
10664 self.minutes.setOwner( self )
10665 min.recover()
10666 self.notifyModification()
10667 return self.minutes
10669 def getMinutes( self ):
10670 #To be removed
10671 try:
10672 if self.minutes:
10673 pass
10674 except AttributeError, e:
10675 self.minutes = None
10676 return self.minutes
10678 def getMasterSchedule( self ):
10679 return self.getOwner().getSchedule()
10681 def delete(self):
10683 self._notify('deleted', self.getOwner())
10685 while len(self.getSpeakerList()) > 0:
10686 self.removeSpeaker(self.getSpeakerList()[0])
10687 for mat in self.getMaterialList():
10688 self.removeMaterial(mat)
10689 self.removePaper()
10690 self.removeSlides()
10691 self.removeVideo()
10692 self.removePoster()
10693 self.removeMinutes()
10694 TrashCanManager().add(self)
10696 #self.unindex()
10698 def recover(self):
10699 TrashCanManager().remove(self)
10701 def getReportNumberHolder(self):
10702 try:
10703 if self._reportNumberHolder:
10704 pass
10705 except AttributeError, e:
10706 self._reportNumberHolder=ReportNumberHolder(self)
10707 return self._reportNumberHolder
10709 def setReportNumberHolder(self, rnh):
10710 self._reportNumberHolder=rnh
10712 class Material(CommonObjectBase):
10713 """This class represents a set of electronic documents (resources) which can
10714 be attached to a conference, a session or a contribution.
10715 A material can be of several types (achieved by specialising this class)
10716 and is like a container of files which have some relation among them.
10717 It contains the minimal set of attributes to store basic meta data and
10718 provides useful operations to access and manage it.
10719 Attributes:
10720 owner -- (Conference, Session or Contribution) Object to which the
10721 material is attached to
10722 id -- (string) Material unique identifier. Normally used to uniquely
10723 identify a material within a conference, session or contribution
10724 title -- (string) Material denomination
10725 description -- (string) Longer text describing in more detail material
10726 intentions
10727 type -- (string) String identifying the material classification
10728 resources -- (PMapping) Collection of resouces grouped within the
10729 material. Dictionary of references to Resource objects indexed
10730 by their unique relative id.
10733 fossilizes(IMaterialMinimalFossil, IMaterialFossil)
10735 def __init__( self, materialData=None ):
10736 self.id = "not assigned"
10737 self.__resources = {}
10738 self.__resourcesIdGen = Counter()
10739 self.title = ""
10740 self.description = ""
10741 self.type = ""
10742 self.owner = None
10743 self.__ac = AccessController(self)
10744 self._mainResource = None
10746 def isFullyPublic( self ):
10747 if hasattr(self, "_fullyPublic"):
10748 return self._fullyPublic
10749 else:
10750 self.setFullyPublic()
10751 return self._fullyPublic
10753 def setFullyPublic( self ):
10754 if self.isProtected():
10755 self._fullyPublic = False
10756 self._p_changed = 1
10757 return
10758 for res in self.getResourceList():
10759 if res.isProtected():
10760 self._fullyPublic = False
10761 self._p_changed = 1
10762 return
10763 self._fullyPublic = True
10764 self._p_changed = 1
10766 def updateFullyPublic( self ):
10767 self.setFullyPublic()
10768 self.getOwner().updateFullyPublic()
10770 def setValues( self, params ):
10771 """Sets all the values of the current material object from a diccionary
10772 containing the following key-value pairs:
10773 title-(str)
10774 description-(str)
10775 Please, note that this method sets ALL values which means that if
10776 the given dictionary doesn't contain any of the keys the value
10777 will set to a default value.
10779 self.setTitle(params.get("title", "NO TITLE ASSIGNED"))
10780 self.setDescription( params.get( "description", "" ) )
10781 self.notifyModification()
10783 def clone ( self, owner):
10784 mat = type(self)()
10785 mat.setTitle(self.getTitle())
10786 mat.setDescription(self.getDescription())
10787 mat.notifyModification()
10789 mat.setId(self.getId())
10790 mat.setOwner(owner)
10791 mat.setType(self.getType())
10793 mat.setProtection(self.getAccessController()._getAccessProtection())
10794 mat.setAccessKey(self.getAccessKey())
10795 rlist = self.getResourceList()
10796 for r in rlist:
10797 newres = r.clone(mat)
10798 mat.addResource(newres)
10800 mat.setMainResource(self.getMainResource())
10802 return mat
10804 def notifyModification( self ):
10805 parent = self.getOwner()
10806 if parent:
10807 parent.setModificationDate()
10808 self._p_changed = 1
10810 def getLocator( self ):
10811 if self.owner == None:
10812 return Locator()
10813 lconf = self.owner.getLocator()
10814 lconf["materialId"] = self.getId()
10815 return lconf
10817 def setId( self, newId ):
10818 self.id = str(newId).strip()
10820 def getId( self ):
10821 return self.id
10823 def getUniqueId( self ):
10824 """returns (string) the unique identifier of the item"""
10825 """used mainly in the web session access key table"""
10826 return "%sm%s" % (self.getOwner().getUniqueId(),self.id)
10828 def setOwner( self, newOwner ):
10829 self.owner = newOwner
10831 def getOwner( self ):
10832 return self.owner
10834 def getCategory( self ):
10835 if isinstance(self.getOwner(), Category):
10836 return self.getOwner()
10837 return None
10839 def getConference( self ):
10840 if type(self.getOwner()) is Conference:
10841 return self.getOwner()
10842 if type(self.getOwner()) is Category:
10843 return None
10844 return self.getOwner().getConference()
10846 def getSession( self ):
10847 if self.getContribution():
10848 return self.getContribution().getSession()
10849 if isinstance(self.getOwner(), Session):
10850 return self.getOwner()
10851 if isinstance(self.getOwner(), SubContribution):
10852 return self.getOwner().getSession()
10853 return None
10855 def getContribution( self ):
10856 if self.getSubContribution():
10857 return self.getSubContribution().getContribution()
10858 if isinstance(self.getOwner(), Contribution):
10859 return self.getOwner()
10860 return None
10862 def getSubContribution( self ):
10863 if isinstance(self.getOwner(), SubContribution):
10864 return self.getOwner()
10865 return None
10867 @Updates (['MaKaC.conference.Material',
10868 'MaKaC.conference.Minutes',
10869 'MaKaC.conference.Paper',
10870 'MaKaC.conference.Slides',
10871 'MaKaC.conference.Video',
10872 'MaKaC.conference.Poster',
10873 'MaKaC.conference.Reviewing'],'title')
10874 def setTitle( self, newTitle ):
10875 self.title = newTitle.strip()
10876 self.notifyModification()
10878 def getTitle( self ):
10879 return self.title
10881 @Updates (['MaKaC.conference.Material',
10882 'MaKaC.conference.Minutes',
10883 'MaKaC.conference.Paper',
10884 'MaKaC.conference.Slides',
10885 'MaKaC.conference.Video',
10886 'MaKaC.conference.Poster',
10887 'MaKaC.conference.Reviewing'], 'description')
10888 def setDescription( self, newDescription ):
10889 self.description = newDescription.strip()
10890 self.notifyModification()
10892 def getDescription( self ):
10893 return self.description
10895 def setType( self, newType ):
10896 self.type = newType.strip()
10897 self.notifyModification()
10899 def getType( self ):
10900 return self.type
10902 def getReviewingState(self):
10903 """ Returns the reviewing state of a material.
10904 The state is represented by an integer:
10905 0 : there's no reviewing state because the material does not belong to a contribution, or the conference
10906 has not reviewing module enabled, or the module is enabled but the mode is "no reviewing"
10907 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
10908 2 : the material is subject to reviewing, but has not been submitted yet by the author
10909 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
10910 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
10911 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
10913 if isinstance(self.owner, Contribution):
10914 conference = self.owner.getConference()
10915 if conference.getConfPaperReview().getChoice() == ConferencePaperReview.NO_REVIEWING: #conference has no reviewing process
10916 return 0
10917 else: #conference has reviewing
10918 #if self.id in reviewableMaterials: #material is reviewable
10919 if isinstance(self, Reviewing): #material is reviewable
10920 lastReview = self.owner.getReviewManager().getLastReview()
10921 if lastReview.isAuthorSubmitted(): #author has submitted
10922 refereeJudgement = lastReview.getRefereeJudgement()
10923 if refereeJudgement.isSubmitted(): #referee has submitted judgement
10924 if refereeJudgement.getJudgement() == "Accept":
10925 return 4
10926 elif refereeJudgement.getJudgement() == "Reject":
10927 return 5
10928 else:
10929 #we should never arrive here because referee judgements that are 'To be corrected'
10930 #or a custom state should imply a new review being created, so the state is back to 2
10931 raise MaKaCError("RefereeJudgement should be 'Accept' or 'Reject' in this method")
10932 else: #referee has not submitted judgement
10933 return 3
10934 else: #author has not submitted
10935 return 2
10936 else: #material is not reviewable
10937 return 1
10938 else: #material does not belong to a contribution
10939 return 0
10941 def _getRepository( self ):
10942 dbRoot = DBMgr.getInstance().getDBConnection().root()
10943 try:
10944 fr = dbRoot["local_repositories"]["main"]
10945 except KeyError, e:
10946 fr = fileRepository.MaterialLocalRepository()
10947 dbRoot["local_repositories"] = OOBTree()
10948 dbRoot["local_repositories"]["main"] = fr
10949 return fr
10951 def hasFile( self, name ):
10952 for f in self.getResourceList():
10953 if f.getName() == name:
10954 return True
10955 return False
10957 def addResource( self, newRes, forcedFileId = None ):
10958 newRes.setOwner( self )
10959 newRes.setId( str( self.__resourcesIdGen.newCount() ) )
10960 newRes.archive( self._getRepository(), forcedFileId = forcedFileId )
10961 self.__resources[newRes.getId()] = newRes
10962 self.notifyModification()
10963 Logger.get('storage').debug("Finished storing resource %s for material %s" % (newRes.getId(), self.getLocator()))
10965 def getResourceList( self ):
10966 list = self.__resources.values()
10967 list.sort(utils.sortFilesByName)
10968 return list
10970 def getNbResources(self ):
10971 return len(self.__resources)
10973 def getResourceById( self, id ):
10974 return self.__resources[id]
10976 def removeResource( self, res ):
10977 if res.getId() in self.__resources.keys():
10978 del self.__resources[ res.getId() ]
10979 res.delete()
10980 self.notifyModification()
10981 if self.getMainResource() is not None and \
10982 self._mainResource.getId() == res.getId():
10983 self._mainResource = None
10985 def recoverResource(self, recRes):
10986 recRes.setOwner(self)
10987 self.__resources[recRes.getId()] = recRes
10988 recRes.recover()
10989 self.notifyModification()
10991 def getMainResource(self):
10992 try:
10993 if self._mainResource:
10994 pass
10995 except AttributeError:
10996 self._mainResource = None
10997 return self._mainResource
10999 def setMainResource(self, mr):
11000 self._mainResource = mr
11002 def delete( self ):
11003 for res in self.getResourceList():
11004 self.removeResource( res )
11005 TrashCanManager().add(self)
11007 def recover(self):
11008 TrashCanManager().remove(self)
11010 def canIPAccess( self, ip ):
11011 if not self.__ac.canIPAccess( ip ):
11012 return False
11013 if self.getOwner() != None:
11014 return self.getOwner().canIPAccess(ip)
11015 return True
11017 def isProtected( self ):
11018 # tells if a material is protected or not
11019 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
11021 def getAccessProtectionLevel( self ):
11022 return self.__ac.getAccessProtectionLevel()
11024 def isItselfProtected( self ):
11025 return self.__ac.isItselfProtected()
11028 def hasProtectedOwner( self ):
11029 if self.getOwner() != None:
11030 return self.getOwner().isProtected()
11031 return False
11034 @Updates (['MaKaC.conference.Material',
11035 'MaKaC.conference.Minutes',
11036 'MaKaC.conference.Paper',
11037 'MaKaC.conference.Slides',
11038 'MaKaC.conference.Video',
11039 'MaKaC.conference.Poster',
11040 'MaKaC.conference.Reviewing'], 'protection', lambda(x): int(x))
11042 def setProtection( self, private ):
11043 self.__ac.setProtection( private )
11044 self.updateFullyPublic()
11045 self._p_changed = 1
11047 def isHidden( self ):
11048 return self.__ac.isHidden()
11050 @Updates (['MaKaC.conference.Material',
11051 'MaKaC.conference.Minutes',
11052 'MaKaC.conference.Paper',
11053 'MaKaC.conference.Slides',
11054 'MaKaC.conference.Video',
11055 'MaKaC.conference.Poster',
11056 'MaKaC.conference.Reviewing'], 'hidden')
11057 def setHidden( self, hidden ):
11058 self.__ac.setHidden( hidden )
11059 self._p_changed = 1
11062 @Updates (['MaKaC.conference.Material',
11063 'MaKaC.conference.Minutes',
11064 'MaKaC.conference.Paper',
11065 'MaKaC.conference.Slides',
11066 'MaKaC.conference.Video',
11067 'MaKaC.conference.Poster',
11068 'MaKaC.conference.Reviewing'], 'accessKey')
11070 def setAccessKey( self, pwd="" ):
11071 self.__ac.setAccessKey(pwd)
11072 self._p_changed = 1
11074 def getAccessKey( self ):
11075 return self.__ac.getAccessKey()
11077 def grantAccess( self, prin ):
11078 self.__ac.grantAccess( prin )
11079 if isinstance(prin, MaKaC.user.Avatar):
11080 prin.linkTo(self, "access")
11081 self._p_changed = 1
11083 def revokeAccess( self, prin ):
11084 self.__ac.revokeAccess( prin )
11085 if isinstance(prin, MaKaC.user.Avatar):
11086 prin.unlinkTo(self, "access")
11087 self._p_changed = 1
11089 def canView( self, aw ):
11090 """tells whether the specified user has access to the current object
11091 or any of its sub-objects
11093 if self.isHidden() and not self.canAccess( aw ):
11094 return False
11095 else:
11096 return True
11098 def isAllowedToAccess( self, user ):
11099 return (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or self.__ac.canUserAccess( user ) or self.canUserModify(user)
11101 def canAccess( self, aw ):
11103 # Allow harvesters (Invenio, offline cache) to access
11104 # protected pages
11105 if self.__ac.isHarvesterIP(aw.getIP()):
11106 return True
11107 #####################################################
11109 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
11110 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
11111 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
11112 return True
11114 canUserAccess = self.isAllowedToAccess( aw.getUser() )
11115 canIPAccess = self.canIPAccess( aw.getIP() )
11116 if not self.isProtected():
11117 return canUserAccess or canIPAccess
11118 else:
11119 canKeyAccess = self.canKeyAccess(aw)
11120 return canUserAccess or canKeyAccess
11122 def canKeyAccess( self, aw ):
11123 sess = aw.getSession()
11124 if not sess:
11125 return False
11126 keys = sess.getVar("accessKeys")
11127 if keys != None:
11128 key = keys.get(self.getUniqueId(),"")
11129 if self.getAccessKey() != "":
11130 return self.__ac.canKeyAccess(key)
11131 elif self.getConference() != None:
11132 return self.getConference().canKeyAccess(aw, key)
11133 return False
11135 def grantModification( self, prin ):
11136 self.__ac.grantModification( prin )
11137 if isinstance(prin, MaKaC.user.Avatar):
11138 prin.linkTo(self, "manager")
11139 self._p_changed = 1
11141 def revokeModification( self, prin ):
11142 self.__ac.revokeModification( prin )
11143 if isinstance(prin, MaKaC.user.Avatar):
11144 prin.unlinkTo(self, "manager")
11145 self._p_changed = 1
11147 def canModify( self, aw ):
11148 return self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw ))
11150 def canUserModify( self, user ):
11151 """Tells whether a user is allowed to modify the current contribution:
11152 only if the user is granted to modify the contribution or the user
11153 can modify any of its upper objects (i.e. conference or session).
11155 return self.getOwner().canUserModify( user )
11157 def getModifKey( self ):
11158 return self.getConference().getModifKey()
11160 def getManagerList( self ):
11161 return self.__ac.getModifierList()
11163 def getAllowedToAccessList( self ):
11164 return self.__ac.getAccessList()
11166 def requireDomain( self, dom ):
11167 self.__ac.requireDomain( dom )
11168 self._p_changed = 1
11170 def freeDomain( self, dom ):
11171 self.__ac.freeDomain( dom )
11172 self._p_changed = 1
11174 def getDomainList( self ):
11175 return self.__ac.getRequiredDomainList()
11177 def getAccessController(self):
11178 return self.__ac
11180 def isBuiltin(self):
11181 return False
11183 class BuiltinMaterial(Material):
11185 Non-customizable material types
11187 def isBuiltin(self):
11188 return True
11191 class Reviewing(BuiltinMaterial):
11193 def __init__( self, materialData = None ):
11194 Material.__init__( self, materialData )
11195 self.id = "reviewing"
11197 def setId( self, newId ):
11198 return
11200 def getContribution(self):
11201 if isinstance(self.getOwner(), Review):
11202 return self.getOwner().getContribution()
11203 return Material.getContribution(self)
11205 class Paper(BuiltinMaterial):
11207 def __init__( self, materialData = None ):
11208 Material.__init__( self, materialData )
11209 self.id = "paper"
11211 def setId( self, newId ):
11212 return
11216 class Slides(BuiltinMaterial):
11218 def __init__( self, materialData = None ):
11219 Material.__init__( self, materialData )
11220 self.id = "slides"
11222 def setId( self, newId ):
11223 return
11227 class Video(BuiltinMaterial):
11229 def __init__( self, materialData = None ):
11230 Material.__init__( self, materialData )
11231 self.id = "video"
11233 def setId( self, newId ):
11234 return
11236 class Poster(BuiltinMaterial):
11238 def __init__( self, materialData = None ):
11239 Material.__init__( self, materialData )
11240 self.id = "poster"
11242 def setId( self, newId ):
11243 return
11245 class Minutes(BuiltinMaterial):
11247 def __init__( self, materialData = None ):
11248 Material.__init__( self, materialData )
11249 self.id = "minutes"
11250 self.title = "Minutes"
11251 self.file = None
11253 def clone ( self, owner):
11254 mat = Minutes()
11255 mat.setTitle(self.getTitle())
11256 mat.setDescription(self.getDescription())
11257 mat.notifyModification()
11259 mat.setId(self.getId())
11260 mat.setOwner(owner)
11261 mat.setType(self.getType())
11263 mat.setProtection(self.getAccessController()._getAccessProtection())
11264 mat.setAccessKey(self.getAccessKey())
11265 lrep = self._getRepository()
11266 flist = lrep.getFiles()
11267 rlist = self.getResourceList()
11268 for r in rlist :
11269 if r.getId()=="minutes":
11270 mat.setText(self.getText())
11271 elif isinstance(r,Link):
11272 newlink = Link()
11273 newlink.setOwner(mat)
11274 newlink.setName(r.getName())
11275 newlink.setDescription(r.getDescription())
11276 newlink.setURL(r.getURL())
11277 mat.addResource(newlink)
11278 elif isinstance(r,LocalFile):
11279 newfile = LocalFile()
11280 newfile.setOwner(mat)
11281 newfile.setName(r.getName())
11282 newfile.setDescription(r.getDescription())
11283 newfile.setFilePath(r.getFilePath())
11284 newfile.setFileName(r.getFileName())
11285 mat.addResource(newfile)
11286 else :
11287 raise Exception( _("Unexpected object type in Resource List : ")+str(type(r)))
11289 mat.setMainResource(self.getMainResource())
11291 return mat
11293 def setId( self, newId ):
11294 return
11296 def setTitle( self, newTitle ):
11297 self.title = newTitle.strip()
11298 self.notifyModification()
11300 def _setFile( self, forcedFileId = None ):
11301 #XXX: unsafe; it must be changed by mkstemp when migrating to python 2.3
11302 tmpFileName = tempfile.mktemp()
11303 fh = open(tmpFileName, "w")
11304 fh.write(" ")
11305 fh.close()
11306 self.file = LocalFile()
11307 self.file.setId("minutes")
11308 self.file.setName("minutes")
11309 self.file.setFilePath(tmpFileName)
11310 self.file.setFileName("minutes.txt")
11311 self.file.setOwner(self)
11312 self.file.archive(self._getRepository(), forcedFileId = forcedFileId)
11314 def setText( self, text, forcedFileId = None ):
11315 if self.file:
11316 self.file.delete()
11317 self._setFile(forcedFileId = forcedFileId)
11318 self.file.replaceContent( text )
11319 self.getOwner().notifyModification()
11321 def getText( self ):
11322 if not self.file:
11323 return ""
11324 return self.file.readBin()
11326 def getResourceList( self ):
11327 res = Material.getResourceList( self )
11328 if self.file:
11329 res.insert(0, self.file)
11330 return res
11332 def getResourceById( self, id ):
11333 if id.strip() == "minutes":
11334 return self.file
11335 return Material.getResourceById( self, id )
11337 def removeResource(self, res):
11338 Material.removeResource(self, res)
11339 if self.file is not None and res.getId().strip() == "minutes":
11340 self.file = None
11341 res.delete()
11342 self.notifyModification()
11344 def recoverResource(self, recRes):
11345 if recRes.getId() == "minutes":
11346 recRes.setOwner(self)
11347 self.file = recRes
11348 recRes.recover()
11349 self.notifyModification()
11350 else:
11351 Material.recoverResource(self, recRes)
11354 class Resource(CommonObjectBase):
11355 """This is the base class for representing individual resources which can
11356 be included in material containers for lately being attached to
11357 conference objects (i.e. conferences, sessions or contributions). This
11358 class provides basic data and operations to handle this resources.
11359 Resources can be of serveral types (files, links, ...) which means
11360 different specialisations of this class.
11361 Attributes:
11362 id -- (string) Allows to assign the resource a unique identifier. It
11363 is normally used to uniquely identify the resource among other
11364 resources included in a certain material.
11365 name -- (string) Short description about the purpose or the contents
11366 of the resource.
11367 description - (string) detailed and varied information about the
11368 resource.
11369 __owner - (Material) reference to the material object in which the
11370 current resource is included.
11373 fossilizes(IResourceMinimalFossil, IResourceFossil)
11375 def __init__( self, resData = None ):
11376 self.id = "not assigned"
11377 self.name = ""
11378 self.description = ""
11379 self._owner = None
11380 self.__ac = AccessController(self)
11381 self.pdfConversionRequestDate = None
11383 def clone( self, conf, protection=True ):
11384 res = self.__class__()
11385 res.setName(self.getName())
11386 res.setDescription(self.getDescription())
11387 res.setOwner(conf)
11388 res.notifyModification()
11389 res.setId(self.getId())
11391 if protection:
11392 res.setProtection(self.getAccessController()._getAccessProtection())
11393 #res.__ac = self.getAccessController()
11395 return res
11397 def notifyModification( self ):
11398 parent = self.getOwner()
11399 if parent:
11400 parent.setModificationDate()
11401 self._p_changed = 1
11403 def getLocator( self ):
11404 if self._owner == None:
11405 return Locator()
11406 lconf = self._owner.getLocator()
11407 lconf["resId"] = self.getId()
11408 return lconf
11410 def setId( self, newId ):
11411 self.id = newId.strip()
11413 def getId( self ):
11414 return self.id
11416 def getUniqueId( self ):
11417 """returns (string) the unique identifier of the item
11418 used mainly in the web session access key table
11419 for resources, it is the same as the father material since
11420 only the material can be protected with an access key"""
11421 return self.getOwner().getUniqueId()
11423 def setOwner( self, newOwner ):
11424 self._owner = newOwner
11426 def getOwner( self ):
11427 return self._owner
11429 def getCategory( self ):
11430 #raise "%s:%s:%s"%(self.getOwner(), Material, isinstance(self.getOwner, Material))
11432 if isinstance(self.getOwner(), Category):
11433 return self.getOwner()
11434 if isinstance(self.getOwner(), Material):
11435 return self.getOwner().getCategory()
11436 return None
11438 def getConference( self ):
11439 # this check owes itself to the fact that some
11440 # protection checking functions call getConference()
11441 # directly on resources, without caring whether they
11442 # are owned by Conferences or Categories
11443 if isinstance(self._owner, Category):
11444 return None
11445 else:
11446 return self._owner.getConference()
11448 def getSession( self ):
11449 return self._owner.getSession()
11451 def getContribution( self ):
11452 return self._owner.getContribution()
11454 def getSubContribution( self ):
11455 return self._owner.getSubContribution()
11457 @Updates (['MaKaC.conference.Link',
11458 'MaKaC.conference.LocalFile'], 'name')
11459 def setName( self, newName ):
11460 self.name = newName.strip()
11461 self.notifyModification()
11463 def getName( self ):
11464 return self.name
11466 @Updates (['MaKaC.conference.Link',
11467 'MaKaC.conference.LocalFile'], 'description')
11468 def setDescription( self, newDesc ):
11469 self.description = newDesc.strip()
11470 self.notifyModification()
11472 def getDescription( self ):
11473 return self.description
11475 def archive( self, repository = None, forcedFileId = None ):
11476 """performs necessary operations to ensure the archiving of the
11477 resource. By default is doing nothing as the persistence of the
11478 system already ensures the archiving of the basic resource data"""
11479 return
11481 def delete( self ):
11482 if self._owner != None:
11483 self._owner.removeResource( self )
11484 self._owner = None
11485 TrashCanManager().add(self)
11487 def recover(self):
11488 TrashCanManager().remove(self)
11490 def canIPAccess( self, ip ):
11491 if not self.__ac.canIPAccess( ip ):
11492 return False
11493 if self.getOwner() != None:
11494 return self.getOwner().canIPAccess(ip)
11495 return True
11497 def isProtected( self ):
11498 # tells if a resource is protected or not
11499 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
11501 def getAccessProtectionLevel( self ):
11502 return self.__ac.getAccessProtectionLevel()
11504 def isItselfProtected( self ):
11505 return self.__ac.isItselfProtected()
11507 def hasProtectedOwner( self ):
11508 if self.getOwner() != None:
11509 return self.getOwner().isProtected()
11510 return False
11512 @Updates (['MaKaC.conference.Link',
11513 'MaKaC.conference.LocalFile'],'protection', lambda(x): int(x))
11514 def setProtection( self, private ):
11515 self.__ac.setProtection( private )
11516 self.getOwner().updateFullyPublic()
11518 def grantAccess( self, prin ):
11519 self.__ac.grantAccess( prin )
11520 if isinstance(prin, MaKaC.user.Avatar):
11521 prin.linkTo(self, "access")
11523 def revokeAccess( self, prin ):
11524 self.__ac.revokeAccess( prin )
11525 if isinstance(prin, MaKaC.user.Avatar):
11526 prin.unlinkTo(self, "access")
11528 def canView( self, aw ):
11529 """tells whether the specified user has access to the current object
11530 or any of its sub-objects
11532 return self.canAccess( aw )
11534 def isAllowedToAccess( self, user ):
11535 return self.__ac.canUserAccess( user ) or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user ))
11537 def canAccess( self, aw ):
11538 # Allow harvesters (Invenio, offline cache) to access
11539 # protected pages
11540 if self.__ac.isHarvesterIP(aw.getIP()):
11541 return True
11542 #####################################################
11544 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
11545 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
11546 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
11547 return True
11549 if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ):
11550 return False
11551 if not self.isProtected():
11552 return True
11553 flag = self.isAllowedToAccess( aw.getUser() )
11554 return flag or self.canKeyAccess(aw) or self.getOwner().canKeyAccess(aw) or \
11555 (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == "") or \
11556 (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == self.getConference().getAccessKey())
11558 def grantModification( self, prin ):
11559 self.__ac.grantModification( prin )
11561 def revokeModification( self, prin ):
11562 self.__ac.revokeModification( prin )
11564 def canModify( self, aw ):
11565 return self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw ))
11567 def canUserModify( self, user ):
11568 """Tells whether a user is allowed to modify the current contribution:
11569 only if the user is granted to modify the contribution or the user
11570 can modify any of its upper objects (i.e. conference or session).
11572 return self.getOwner().canUserModify( user )
11574 def getModifKey( self ):
11575 return self.getConference().getModifKey()
11577 def getManagerList( self ):
11578 return self.__ac.getModifierList()
11580 def getAllowedToAccessList( self ):
11581 return self.__ac.getAccessList()
11583 def getURL( self ):
11584 return ""
11586 def requireDomain( self, dom ):
11587 self.__ac.requireDomain( dom )
11589 def freeDomain( self, dom ):
11590 self.__ac.freeDomain( dom )
11592 def getDomainList( self ):
11593 return self.__ac.getRequiredDomainList()
11595 def getAccessController(self):
11596 return self.__ac
11598 def getAccessKey(self):
11599 if self.getOwner() is not None:
11600 return self.getOwner().getAccessKey()
11601 return ""
11603 def canKeyAccess( self, aw ):
11604 sess = aw.getSession()
11605 if not sess:
11606 return False
11607 accessKey = self.getAccessKey()
11608 keys = sess.getVar("accessKeys")
11609 if keys != None:
11610 if keys.has_key(self.getUniqueId()):
11611 if (accessKey != "" and keys[self.getUniqueId()] == accessKey) or (accessKey == "" and self.getConference().getAccessKey() != "" and keys[self.getUniqueId()] == self.getConference().getAccessKey()):
11612 return True
11613 return False
11615 def getReviewingState(self):
11616 """ Returns the reviewing state of a resource, which is the reviewing state of the material to which it belongs.
11617 The state is represented by an integer:
11618 0 : there's no reviewing state because the resource doesn't belong to a material,
11619 the material does not belong to a contribution, or the conference does not have reviewing.
11620 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
11621 2 : the material is subject to reviewing, but has not been submitted yet by the author
11622 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
11623 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
11624 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
11626 if isinstance(self.getOwner(), Material):
11627 return self.getOwner().getReviewingState()
11628 else: #ressource does not belong to a material
11629 return 0
11631 def setPDFConversionRequestDate( self, newPdfConversionRequestDate ):
11632 self.pdfConversionRequestDate = newPdfConversionRequestDate
11634 def getPDFConversionStatus(self):
11636 if not hasattr(self, "pdfConversionRequestDate"):
11637 self.pdfConversionRequestDate = None
11639 if self.pdfConversionRequestDate is not None and self.pdfConversionRequestDate + timedelta(seconds=50) > nowutc() :
11640 return 'converting'
11641 return None
11644 class Link(Resource):
11645 """Specialises Resource class in order to represent web links. Objects of
11646 this class will contain necessary information to include in a conference
11647 object links to internet resources through a URL.
11648 Params:
11649 url -- (string) Contains the URL to the internet target resource.
11652 fossilizes(ILinkMinimalFossil, ILinkFossil)
11654 def __init__( self, resData = None ):
11655 Resource.__init__( self, resData )
11656 self.url = ""
11658 def clone( self, conf ):
11659 link = Resource.clone(self, conf)
11660 link.setURL(self.getURL())
11661 return link
11663 @Updates ('MaKaC.conference.Link', 'url')
11664 def setURL( self, newURL ):
11665 self.url = newURL.strip()
11666 self.notifyModification()
11668 def getURL( self ):
11669 return self.url
11672 class LocalFile(Resource):
11673 """Specialises Resource class in order to represent files which can be
11674 stored in the system. The user can choose to use the system as an
11675 archive of electronic files so he may want to attach a file which is
11676 in his computer to a conference so it remains there and must be kept
11677 in the system. This object contains the file basic metadata and provides
11678 the necessary operations to ensure the corresponding file is archived
11679 (it uses one of the file repositories of the system to do so) and keeps
11680 the reference for being able to access it afterwards.
11681 Params:
11682 fileName -- (string) Name of the file. Normally the original name of
11683 the user submitted file is kept.
11684 filePath -- (string) If it is set, it contains a local path to the
11685 file submitted by the user and uploaded in the system. This
11686 attribute is only temporary used so it keeps a pointer to a
11687 temporary uploaded file.
11688 __repository -- (FileRep) Once a file is archived, it is kept in a
11689 FileRepository for long term. This attribute contains a pointer
11690 to the file repository where the file is kept.
11691 __archivedId -- (string) It contains a unique identifier for the file
11692 inside the repository where it is archived.
11695 fossilizes(ILocalFileMinimalFossil, ILocalFileFossil, ILocalFileExtendedFossil, ILocalFileAbstractMaterialFossil)
11697 def __init__( self, resData = None ):
11698 Resource.__init__( self, resData )
11699 self.fileName= ""
11700 self.fileType = ""
11701 self.filePath = ""
11702 self.__repository = None
11703 self.__archivedId = ""
11705 def clone( self, conf, protection=True ):
11706 localfile = Resource.clone(self, conf, protection)
11707 localfile.setFilePath(self.getFilePath())
11708 localfile.setFileName(self.getFileName())
11709 return localfile
11711 def setFileName( self, newFileName, checkArchive=True ):
11712 """While the file is not archived sets the file name of the current
11713 object to the one specified (if a full path is specified the
11714 base name is extracted) replacing on it blanks by underscores.
11716 if checkArchive and self.isArchived():
11717 raise MaKaCError( _("The file name of an archived file cannot be changed"), _("File Archiving"))
11718 #Using os.path.basename is not enough as it only extract filenames
11719 # correclty depending on the server platform. So we need to convert
11720 # to the server platform and apply the basename extraction. As I
11721 # couldn't find a python function for this this is done manually
11722 # although it can contain errors
11723 #On windows basename function seems to work properly with unix file
11724 # paths
11725 if newFileName.count("/"):
11726 #unix filepath
11727 newFileName = newFileName.split("/")[-1]
11728 else:
11729 #windows file path: there "/" is not allowed on windows paths
11730 newFileName = newFileName.split("\\")[-1]
11731 self.fileName = newFileName.strip().replace(" ", "_")
11733 def getFileName( self ):
11734 return self.fileName
11736 def getFileType( self ):
11737 fileExtension = os.path.splitext( self.getFileName() )[1]
11738 if fileExtension != "":
11739 fileExtension = fileExtension[1:]
11740 cfg = Config.getInstance()
11741 if cfg.getFileType( fileExtension ) != "":
11742 return cfg.getFileType( fileExtension )
11743 else:
11744 return fileExtension
11746 def setFilePath( self, filePath ):
11747 if self.isArchived():
11748 raise MaKaCError( _("The path of an archived file cannot be changed"), _("File Archiving"))
11749 if not os.access( filePath.strip(), os.F_OK ):
11750 raise Exception( _("File does not exist : %s")%filePath.strip())
11751 self.filePath = filePath.strip()
11753 def getCreationDate( self):
11754 return self.__repository.getCreationDate(self.__archivedId)
11756 def getFilePath( self ):
11757 if not self.isArchived():
11758 return self.filePath
11759 return self.__repository.getFilePath(self.__archivedId)
11761 def getSize( self ):
11762 if not self.isArchived():
11763 return int(os.stat(self.getFilePath())[stat.ST_SIZE])
11764 return self.__repository.getFileSize( self.__archivedId )
11766 def setArchivedId( self, rep, id ):
11767 self.__repository = rep
11768 self.__archivedId = id
11770 def getRepositoryId( self ):
11771 return self.__archivedId
11773 def setRepositoryId(self, id):
11774 self.__archivedId = id
11776 def isArchived( self ):
11777 return self.__repository != None and self.__archivedId != ""
11779 def readBin( self ):
11780 if not self.isArchived():
11781 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11782 return self.__repository.readFile( self.__archivedId )
11784 def replaceContent( self, newContent ):
11785 if not self.isArchived():
11786 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11787 self.__repository.replaceContent( self.__archivedId, newContent )
11789 def archive( self, repository=None, forcedFileId = None ):
11790 if self.isArchived():
11791 raise Exception( _("File is already archived"))
11792 if not repository:
11793 raise Exception( _("Destination repository not set"))
11794 if self.filePath == "":
11795 return _("Nothing to archive")
11796 repository.storeFile( self, forcedFileId = forcedFileId)
11797 self.filePath = ""
11798 self.notifyModification()
11800 def unArchive(self):
11801 # Not used.
11802 self.__repository = None
11803 self.__archivedId = ""
11805 def recover(self):
11806 if not self.isArchived():
11807 raise Exception( _("File is not archived, so it cannot be recovered."))
11808 if not self.__repository:
11809 raise Exception( _("Destination repository not set."))
11810 self.__repository.recoverFile(self)
11811 Resource.recover(self)
11812 self.notifyModification()
11814 def delete( self ):
11815 if not self.isArchived():
11816 os.remove( self.getFilePath() )
11817 try:
11818 self.__repository.retireFile( self )
11819 except AttributeError, e:
11820 pass
11821 Resource.delete( self )
11823 def getRepository(self):
11824 return self.__repository
11826 def __str__( self ):
11827 return self.getFileName()
11829 #getURL is removed at the moment from the LocalFile and the file access
11830 # is completely delegated to the web interface; the web interface will
11831 # have to access the files locally (using the getFilePath) or the readBin
11832 # function.
11833 #However, for the future it could be required to have several file
11834 # repositories so the file access will have to be reviewed.
11835 #def getURL( self ):
11836 # #XXX: Very bad!! We should find a better solution
11837 # c = Config.getInstance()
11838 # return c.getArchivedFileURL( self )
11841 class TCIndex( Persistent ):
11842 """Index for conference track coordinators.
11844 This class allows to index conference track coordinators so the owner
11845 can answer optimally to the query if a user is coordinating
11846 any conference track.
11847 It is implemented by simply using a BTree where the Avatar id is used
11848 as key (because it is unique and non variable) and a list of
11849 coordinated tracks is kept as keys. It is the responsability of the
11850 index owner (conference) to keep it up-to-date i.e. notify track
11851 coordinator additions and removals.
11854 def __init__( self ):
11855 self._idx = OOBTree()
11858 def getTracks( self, av ):
11859 """Gives a list with the tracks a user is coordinating.
11861 if av == None:
11862 return []
11863 return self._idx.get( av.getId(), [] )
11865 def indexCoordinator( self, av, track ):
11866 """Registers in the index a coordinator of a track.
11868 if av == None or track == None:
11869 return
11870 if not self._idx.has_key( av.getId() ):
11871 l = []
11872 else:
11873 l = self._idx[av.getId()]
11874 if track not in l:
11875 l.append(track)
11876 # necessary, otherwise ZODB won't know it needs to update the BTree
11877 self._idx[av.getId()] = l
11878 self.notifyModification()
11880 def unindexCoordinator( self, av, track ):
11881 if av == None or track == None:
11882 return
11883 l = self._idx.get( av.getId(), [] )
11884 if track in l:
11885 l.remove( track )
11886 self._idx[av.getId()] = l
11887 self.notifyModification()
11889 def notifyModification(self):
11890 self._p_changed = 1
11893 class Track(CoreObject):
11895 def __init__( self ):
11896 self.conference = None
11897 self.id = "not assigned"
11898 self.title = ""
11899 self.description = ""
11900 self.subTracks = {}
11901 self.__SubTrackGenerator = Counter()
11902 self._abstracts = OOBTree()
11903 self._coordinators = []
11904 self._contributions = OOBTree()
11905 self._code=""
11907 def clone(self, conference):
11908 tr = Track()
11909 tr.setConference(conference)
11910 tr.setTitle(self.getTitle())
11911 tr.setCode(self.getCode())
11912 tr.setDescription(self.getDescription())
11914 for co in self.getCoordinatorList() :
11915 tr.addCoordinator(co)
11917 for subtr in self.getSubTrackList() :
11918 tr.addSubTrack(subtr.clone())
11920 return tr
11923 def delete( self ):
11924 """Deletes a track from the system. All the associated abstracts will
11925 also be notified so the track is no longer associated to them.
11927 #XXX: Should we allow to delete a track when there are some abstracts
11928 # or contributions submitted for it?!?!?!?!
11930 # we must notify each abstract in the track about the deletion of the
11931 # track
11932 while len(self._abstracts)>0:
11933 k = self._abstracts.keys()[0]
11934 abstract = self._abstracts[k]
11935 del self._abstracts[k]
11936 abstract.removeTrack( self )
11938 # we must notify each contribution in the track about the deletion of the
11939 # track
11940 while len(self._contributions)>0:
11941 k = self._contributions.keys()[0]
11942 contrib = self._contributions[k]
11943 del self._contributions[k]
11944 contrib.removeTrack( self )
11946 # we must delete and unindex all the possible track coordinators
11947 while len(self._coordinators)>0:
11948 self.removeCoordinator(self._coordinators[0])
11950 # we must notify the conference about the track deletion
11951 if self.conference:
11952 conf = self.conference
11953 self.conference = None
11954 conf.removeTrack( self )
11956 TrashCanManager().add(self)
11958 def recover(self):
11959 TrashCanManager().remove(self)
11961 def canModify( self, aw ):
11962 return self.conference.canModify( aw )
11964 def canUserModify( self, av ):
11965 return self.conference.canUserModify( av )
11967 def canView( self, aw ):
11968 return self.conference.canView( aw )
11970 def notifyModification( self ):
11971 parent = self.getConference()
11972 if parent:
11973 parent.setModificationDate()
11974 self._p_changed = 1
11976 def getLocator( self ):
11977 """Gives back a globaly unique identification encapsulated in a Locator
11978 object for the track instance
11980 if self.conference == None:
11981 return Locator()
11982 lconf = self.conference.getLocator()
11983 lconf["trackId"] = self.getId()
11984 return lconf
11986 def setConference(self, conference):
11987 self.conference = conference
11989 def getConference( self ):
11990 return self.conference
11992 def getOwner( self ):
11993 return self.getConference()
11995 def setId( self, newId ):
11996 self.id = str(newId)
11998 def getId( self ):
11999 return self.id
12001 def setTitle( self, newTitle ):
12002 self.title = newTitle
12003 self.notifyModification()
12005 def getTitle( self ):
12006 return self.title
12008 def setDescription(self, newDescription ):
12009 self.description = newDescription
12010 self.notifyModification()
12012 def getDescription(self):
12013 return self.description
12015 def getCode(self):
12016 try:
12017 if self._code:
12018 pass
12019 except AttributeError:
12020 self._code=self.id
12021 return self._code
12023 def setCode(self,newCode):
12024 self._code=str(newCode).strip()
12026 def __generateNewSubTrackId( self ):
12027 return str(self.__SubTrackGenerator.newCount())
12029 def addSubTrack( self, newSubTrack ):
12030 """Registers the contribution passed as parameter within the session
12031 assigning it a unique id.
12033 if newSubTrack in self.subTracks.values():
12034 return
12035 subTrackId = newSubTrack.getId()
12036 if subTrackId == "not assigned":
12037 subTrackId = self.__generateNewSubTrackId()
12038 self.subTracks[subTrackId] = newSubTrack
12039 newSubTrack.setTrack( self )
12040 newSubTrack.setId( subTrackId )
12041 self.notifyModification()
12043 def removeSubTrack( self, subTrack ):
12044 """Removes the indicated contribution from the session
12046 if subTrack in self.subTracks.values():
12047 del self.subTracks[ subTrack.getId() ]
12048 subTrack.setTrack( None )
12049 subTrack.delete()
12050 self.notifyModification()
12052 def recoverSubTrack(self, subTrack):
12053 self.addSubTrack(subTrack)
12054 subTrack.recover()
12056 def newSubTrack( self ):
12057 st = SubTrack()
12058 self.addSubTrack( st )
12059 return st
12061 def getSubTrackById( self, id ):
12062 if self.subTracks.has_key( id ):
12063 return self.subTracks[ id ]
12064 return None
12066 def getSubTrackList( self ):
12067 return self.subTracks.values()
12069 def getAbstractList( self ):
12072 try:
12073 if self._abstracts:
12074 pass
12075 except AttributeError:
12076 self._abstracts = OOBTree()
12077 return self._abstracts.values()
12079 def getAbstractById( self, id ):
12080 try:
12081 if self._abstracts:
12082 pass
12083 except AttributeError:
12084 self._abstracts = OOBTree()
12085 return self._abstracts.get(str(id).strip())
12087 def hasAbstract( self, abstract ):
12090 try:
12091 if self._abstracts:
12092 pass
12093 except AttributeError:
12094 self._abstracts = OOBTree()
12095 return self._abstracts.has_key( abstract.getId() )
12097 def addAbstract( self, abstract ):
12098 """Adds an abstract to the track abstract list.
12100 Notice that this method doesn't notify the abstract about the track
12101 addition.
12103 if not self.hasAbstract( abstract ):
12104 self._abstracts[ abstract.getId() ] = abstract
12105 #abstract.addTrack( self )
12107 def removeAbstract( self, abstract ):
12108 """Removes an abstract from the track abstract list.
12110 Notice that this method doesn't notify the abstract about the track
12111 removal.
12113 if self.hasAbstract( abstract ):
12114 del self._abstracts[ abstract.getId() ]
12115 #abstract.removeTrack( self )
12117 def addCoordinator( self, av ):
12118 """Grants coordination privileges to user.
12120 Arguments:
12121 av -- (MaKaC.user.Avatar) the user to which
12122 coordination privileges must be granted.
12125 try:
12126 if self._coordinators:
12127 pass
12128 except AttributeError, e:
12129 self._coordinators = []
12130 self.notifyModification()
12132 if not (av in self._coordinators):
12133 self._coordinators.append( av )
12134 self.getConference().addTrackCoordinator( self, av )
12135 av.linkTo(self, "coordinator")
12136 self.notifyModification()
12138 def removeCoordinator( self, av ):
12139 """Revokes coordination privileges to user.
12141 Arguments:
12142 av -- (MaKaC.user.Avatar) user for which coordination privileges
12143 must be revoked
12145 try:
12146 if self._coordinators:
12147 pass
12148 except AttributeError, e:
12149 self._coordinators = []
12150 self.notifyModification()
12152 if av in self._coordinators:
12153 self._coordinators.remove( av )
12154 self.getConference().removeTrackCoordinator( self, av )
12155 av.linkTo(self, "coordinator")
12156 self.notifyModification()
12158 def isCoordinator( self, av ):
12159 """Tells whether the specified user is a coordinator of the track.
12161 Arguments:
12162 av -- (MaKaC.user.Avatar) user to be checke
12164 Return value: (boolean)
12166 try:
12167 if self._coordinators:
12168 pass
12169 except AttributeError, e:
12170 self._coordinators = []
12172 return av in self._coordinators
12174 def getCoordinatorList( self ):
12175 """Return all users which have privileges to coordinate the track.
12177 Return value: (list)
12179 try:
12180 if self._coordinators:
12181 pass
12182 except AttributeError, e:
12183 self._coordinators = []
12185 return self._coordinators
12187 def canCoordinate( self, aw ):
12188 """Tells if a user has coordination privileges.
12190 Only track coordinators have coordination privileges over a track.
12192 Params:
12193 aw -- (MaKaC.accessControl.AccessWrapper) User access
12194 information for which the coordination privileges must be
12195 checked.
12197 Return value: (boolean)
12199 return self.isCoordinator( aw.getUser() ) or self.canModify( aw )
12201 def addContribution( self, newContrib ):
12204 try:
12205 if self._contributions:
12206 pass
12207 except AttributeError:
12208 self._contributions = OOBTree()
12209 if self._contributions.has_key( newContrib.getId() ):
12210 return
12211 self._contributions[ newContrib.getId() ] = newContrib
12212 newContrib.setTrack( self )
12214 def getModifKey( self ):
12215 return self.getConference().getModifKey()
12217 def removeContribution( self, contrib ):
12220 try:
12221 if self._contributions:
12222 pass
12223 except AttributeError:
12224 self._contributions = OOBTree()
12225 if not self._contributions.has_key( contrib.getId() ):
12226 return
12227 del self._contributions[ contrib.getId() ]
12228 contrib.setTrack( None )
12230 def hasContribution( self, contrib ):
12231 try:
12232 if self._contributions:
12233 pass
12234 except AttributeError:
12235 self._contributions = OOBTree()
12236 return self._contributions.has_key( contrib.getId() )
12238 def getContributionList(self):
12239 try:
12240 if self._contributions:
12241 pass
12242 except AttributeError:
12243 self._contributions = OOBTree()
12244 return self._contributions.values()
12246 def canUserCoordinate( self, av ):
12247 return self.isCoordinator( av ) or self.canUserModify( av )
12250 class SubTrack(CoreObject):
12252 def __init__( self ):
12253 self.track = None
12254 self.id = "not assigned"
12255 self.title = ""
12256 self.description = ""
12258 def clone(self):
12259 sub = SubTrack()
12260 sub.setDescription(self.getDescription())
12261 sub.setTitle(self.getTitle())
12263 return sub
12266 def delete(self):
12267 TrashCanManager().add(self)
12269 def recover(self):
12270 TrashCanManager().remove(self)
12272 def canModify( self, aw ):
12273 return self.track.canModify( aw )
12275 def canView( self, aw ):
12276 return self.track.canView( aw )
12278 def notifyModification( self ):
12279 parent = self.getTrack()
12280 if parent:
12281 parent.setModificationDate()
12282 self._p_changed = 1
12284 def getLocator( self ):
12285 """Gives back a globaly unique identification encapsulated in a Locator
12286 object for the session instance
12288 if self.track == None:
12289 return Locator()
12290 lconf = self.track.getLocator()
12291 lconf["subTrackId"] = self.getId()
12292 return lconf
12294 def setTrack(self, track):
12295 self.track = track
12296 if track == None:
12297 return
12299 def getTrack( self ):
12300 return self.track
12302 def getOwner( self ):
12303 return self.getTrack()
12305 def setId( self, newId ):
12306 self.id = str(newId)
12308 def getId( self ):
12309 return self.id
12311 def setTitle( self, newTitle ):
12312 self.title = newTitle
12313 self.notifyModification()
12315 def getTitle( self ):
12316 return self.title
12318 def setDescription(self, newDescription ):
12319 self.description = newDescription
12320 self.notifyModification()
12322 def getDescription(self):
12323 return self.description
12326 class ContributionType(Persistent):
12328 def __init__(self, name, description, conference):
12329 self._id = ""
12330 self._name = name
12331 self._description = description
12332 self._conference = conference
12334 def getId(self):
12335 return self._id
12337 def setId(self, id):
12338 self._id = id
12340 def getName(self):
12341 return self._name
12343 def setName(self, name):
12344 self._name = name
12346 def getDescription(self):
12347 return self._description
12349 def setDescription(self, desc):
12350 self._description = desc
12352 def getConference(self):
12353 return self._conference
12355 def setConference(self, conf):
12356 self._conference = conf
12358 def getLocator( self ):
12359 if self._conference == None:
12360 return Locator()
12361 lconf = self._conference.getLocator()
12362 lconf["contribTypeId"] = self.getId()
12363 return lconf
12365 def canModify(self, aw):
12366 return self._conference.canModify(aw)
12368 def delete(self):
12369 self.setConference(None)
12370 TrashCanManager().add(self)
12372 def recover(self):
12373 TrashCanManager().remove(self)
12375 def clone(self, conference ):
12376 type = ContributionType(self.getName(), self.getDescription(),conference)
12377 return type
12380 class BOAConfig(Persistent):
12381 """Contains the configuration of the Book of Abstracts of a conference
12383 sortByTypes = {"number": L_("ID"),
12384 "name": L_("Title"),
12385 "sessionTitle": L_("Session title"),
12386 "speaker": L_("Presenter"),
12387 "schedule": L_("Schedule")}
12389 def __init__(self,conf):
12390 self._conf=conf
12391 self._text=""
12392 self._showIds= False
12393 self._sortBy = "number"
12394 self._modificationDS = nowutc()
12395 self._cache = False
12397 def getText(self):
12398 return self._text
12400 def setText(self,newText):
12401 self._text=newText.strip()
12402 self._notifyModification()
12404 def getShowIds(self):
12405 if not hasattr(self, "_showIds"):
12406 self._showIds=False
12407 return self._showIds
12409 def setShowIds(self,showIds):
12410 self._showIds=showIds
12411 self._notifyModification()
12413 def getSortBy(self):
12414 if not hasattr(self, "_sortBy"):
12415 self._sortBy="number"
12416 return self._sortBy
12418 def setSortBy(self,sortBy):
12419 self._sortBy=sortBy
12420 self._notifyModification()
12422 @staticmethod
12423 def getSortByTypes():
12424 return BOAConfig.sortByTypes
12426 def isCacheEnabled(self):
12427 if not hasattr(self, '_cache'):
12428 self._cache = False
12429 return self._cache
12431 def setCache(self, value):
12432 self._cache = value;
12434 def _notifyModification(self):
12435 self._modificationDS = nowutc()
12437 @property
12438 def lastChanged(self):
12439 if not hasattr(self, '_modificationDS'):
12440 self._modificationDS = nowutc()
12441 return self._modificationDS