[FIX] None value coming from getOwner()
[cds-indico.git] / indico / MaKaC / conference.py
blobb1d42785bcbd073be6c287d35476dd8475181dcc
1 # -*- coding: utf-8 -*-
2 ##
3 ##
4 ## This file is part of Indico.
5 ## Copyright (C) 2002 - 2013 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.common.timezoneUtils import datetimeToUnixTimeInt
22 from MaKaC.plugins import PluginsHolder, Observable
23 from MaKaC.common.utils import formatDateTime
24 from MaKaC.fossils.subcontribution import ISubContribParticipationFossil,\
25 ISubContribParticipationFullFossil, ISubContributionFossil, ISubContributionWithSpeakersFossil
26 from MaKaC.fossils.contribution import IContributionParticipationFossil,\
27 IContributionFossil, IContributionWithSpeakersFossil, IContributionParticipationMinimalFossil, \
28 IContributionWithSubContribsFossil,\
29 IContributionParticipationTTDisplayFossil, \
30 IContributionParticipationTTMgmtFossil
31 from MaKaC.fossils.conference import IConferenceMinimalFossil, \
32 IConferenceEventInfoFossil, IConferenceFossil,\
33 ISessionFossil, ISessionSlotFossil, IMaterialMinimalFossil,\
34 IMaterialFossil, IConferenceParticipationFossil,\
35 IResourceMinimalFossil, ILinkMinimalFossil, ILocalFileMinimalFossil,\
36 IResourceFossil, ILinkFossil, ILocalFileFossil,\
37 ILocalFileExtendedFossil, IConferenceParticipationMinimalFossil,\
38 ICategoryFossil, ILocalFileAbstractMaterialFossil
39 from MaKaC.common.fossilize import fossilizes, Fossilizable
40 from MaKaC.common.url import ShortURLMapper
41 from MaKaC.contributionReviewing import Review
42 from MaKaC.rb_location import CrossLocationQueries, CrossLocationDB
43 from indico.util.i18n import L_
46 import re, os
47 import tempfile
48 import copy
49 import stat
50 from datetime import datetime, timedelta, time
52 from MaKaC.contributionReviewing import ReviewManager
53 from MaKaC.paperReviewing import ConferencePaperReview as ConferencePaperReview
54 from MaKaC.abstractReviewing import ConferenceAbstractReview as ConferenceAbstractReview
56 from pytz import timezone
57 from pytz import all_timezones
59 from persistent import Persistent
60 from BTrees.OOBTree import OOBTree, OOTreeSet, OOSet
61 from BTrees.OIBTree import OIBTree,OISet,union
62 import MaKaC
63 import MaKaC.common.indexes as indexes
64 from MaKaC.common.timezoneUtils import nowutc, maxDatetime
65 import MaKaC.fileRepository as fileRepository
66 from MaKaC.schedule import ConferenceSchedule, SessionSchedule,SlotSchedule,\
67 PosterSlotSchedule, SlotSchTypeFactory, ContribSchEntry, \
68 LinkedTimeSchEntry, BreakTimeSchEntry
69 import MaKaC.review as review
70 from MaKaC.common import Config, DBMgr, utils
71 from MaKaC.common.Counter import Counter
72 from MaKaC.common.ObjectHolders import ObjectHolder
73 from MaKaC.common.Locators import Locator
74 from MaKaC.accessControl import AccessController, AdminList
75 from MaKaC.errors import MaKaCError, TimingError, ParentTimingError, EntryTimingError, NoReportError
76 from MaKaC import registration,epayment
77 from MaKaC.evaluation import Evaluation
78 from MaKaC.trashCan import TrashCanManager
79 from MaKaC.user import AvatarHolder
80 from MaKaC.common import pendingQueues
81 from MaKaC.common.info import HelperMaKaCInfo
82 from MaKaC.participant import Participation
83 from MaKaC.common.log import LogHandler
84 import MaKaC.common.info as info
85 from MaKaC.badge import BadgeTemplateManager
86 from MaKaC.poster import PosterTemplateManager
87 from MaKaC.common.cache import CategoryCache, EventCache
88 from MaKaC.common import mail
89 from MaKaC.common.utils import getHierarchicalId
90 from MaKaC.i18n import _
91 from MaKaC.common.PickleJar import Updates
92 from MaKaC.common.PickleJar import if_else
94 from MaKaC.webinterface import urlHandlers
96 from MaKaC.common.logger import Logger
97 from MaKaC.common.contextManager import ContextManager
98 from MaKaC.webinterface.common.tools import escape_html
99 import zope.interface
101 from indico.modules.scheduler import Client, tasks
102 from indico.util.date_time import utc_timestamp
103 from indico.core.index import IIndexableByStartDateTime, IUniqueIdProvider, Catalog
104 from indico.core.db.event import SupportInfo
105 from MaKaC.schedule import ScheduleToJson
107 from indico.util.redis import write_client as redis_write_client
108 import indico.util.redis.avatar_links as avatar_links
110 class CoreObject(Persistent):
112 CoreObjects are Persistent objects that are employed by Indico's core
115 zope.interface.implements(IUniqueIdProvider,
116 IIndexableByStartDateTime)
118 def setModificationDate(self, date = None):
120 Method called to notify the current object has been modified.
122 if not date:
123 date = nowutc()
124 self._modificationDS = date
126 def __conform__(self, proto):
128 if proto == IIndexableByStartDateTime:
129 return utc_timestamp(self.getStartDate())
130 else:
131 return None
134 class Locatable:
136 Inherited by objects that imply a physical location:
137 * Conferences
138 * Sessions
139 * SessionSlots
140 * Contributions
141 * SubContributions
144 def getLocationParent(self):
146 Returns the object the location info should be inherited from
147 (Overridden)
149 raise Exception("Unimplemented method")
151 def getLocation(self):
152 if self.getOwnLocation():
153 return self.getOwnLocation()
154 return self.getInheritedLocation()
156 def getOwnLocation(self):
157 if len(self.places) > 0:
158 return self.places[0]
159 return None
161 def getInheritedLocation(self):
162 return self.getLocationParent().getLocation()
164 def getOwnRoom(self):
165 if len(self.rooms) > 0:
166 return self.rooms[0]
167 return None
169 def getRoom(self):
170 if self.getOwnRoom():
171 return self.getOwnRoom()
172 return self.getInheritedRoom()
174 def getInheritedRoom(self):
175 return self.getLocationParent().getRoom()
177 def setLocation(self, newLocation):
178 oldLocation = self.getOwnLocation()
179 if newLocation == None:
180 if len(self.places) > 0:
181 del self.places[0]
182 elif len(self.places) > 0:
183 self.places[0] = newLocation
184 else:
185 self.places.append( newLocation )
186 self.notifyModification()
188 def setRoom(self, newRoom):
189 oldRoom = self.getOwnRoom()
190 if newRoom == None:
191 if len(self.rooms) > 0:
192 del self.rooms[0]
193 elif len(self.rooms) > 0:
194 self.rooms[0] = newRoom
195 else:
196 self.rooms.append( newRoom )
197 self.notifyModification()
200 class CommonObjectBase(CoreObject, Observable, Fossilizable):
202 This class is for holding commonly used methods that are used by several classes.
203 It is inherited by the following classes:
204 * Category
205 * Conference
206 * Session
207 * Contribution
208 * SubContribution
209 * Material
210 * Resource
213 def getRecursiveManagerList(self):
214 av_set = set()
216 # Get the AccessProtectionLevel for this
217 apl = self.getAccessProtectionLevel()
219 if apl == -1:
220 pass
221 elif apl == 1:
222 for av in self.getManagerList():
223 av_set.add(av)
224 for av in self.getOwner().getRecursiveManagerList():
225 av_set.add(av)
226 else:
227 for av in self.getManagerList():
228 av_set.add(av)
230 if self.getOwner():
231 for av in self.getOwner().getRecursiveManagerList():
232 av_set.add(av)
234 return list(av_set)
236 def getRecursiveAllowedToAccessList(self, onlyManagers=False):
237 """Returns a set of Avatar resp. CERNGroup objects for those people resp.
238 e-groups allowed to access this object as well as all parent objects.
241 # Initialize set of avatars/groups: this will hold those
242 # people/groups explicitly
243 # allowed to access this object
244 av_set = set()
246 # Get the AccessProtectionLevel for this
247 apl = self.getAccessProtectionLevel()
249 # If this object is "absolutely public", then return an empty set
250 if apl == -1:
251 pass
253 # If this object is protected "all by itself", then get the list of
254 # people/groups allowed to access it, plus managers of owner(s)
255 elif apl == 1:
256 al = self.getAllowedToAccessList() + self.getManagerList() + \
257 self.getOwner().getRecursiveManagerList()
258 if al is not None:
259 for av in al:
260 av_set.add(av)
262 # If access settings are inherited (and PRIVATE) from its owners, look at those.
263 elif apl == 0 and self.isProtected():
264 # If event is protected, then get list of people/groups allowed
265 # to access, and add that to the set of avatars.
266 al = self.getAllowedToAccessList() + self.getManagerList()
267 if al is not None:
268 for av in al:
269 av_set.add(av)
271 # Add list of avatars/groups allowed to access parents objects.
272 owner = self.getOwner()
273 if owner is not None:
274 owner_al = owner.getRecursiveAllowedToAccessList(onlyManagers=True)
275 if owner_al is not None:
276 for av in owner_al:
277 av_set.add(av)
279 # return set containing whatever avatars/groups we may have collected
280 return av_set
283 class CategoryManager( ObjectHolder ):
284 idxName = "categories"
285 counterName = "CATEGORY"
287 def add(self, category):
288 ObjectHolder.add(self, category)
289 # Add category to the name index
290 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
291 nameIdx.index(category.getId(), category.getTitle().decode('utf-8'))
293 def remove(self, category):
294 ObjectHolder.remove(self, category)
295 # remove category from the name index
296 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
297 nameIdx.unindex(category.getId())
298 Catalog.getIdx('categ_conf_sd').remove_category(category.getId())
300 def _newId( self ):
302 returns a new id for the category
303 the id must not already exist in the collection
305 id = ObjectHolder._newId( self )
306 while self.hasKey(id):
307 id = ObjectHolder._newId( self )
308 return id
310 def getRoot( self ):
311 root = DBMgr.getInstance().getDBConnection().root()
312 if not root.has_key("rootCategory"):
313 r = Category()
314 r.setName("Home")
315 self.add( r )
316 root["rootCategory"] = r
317 return root["rootCategory"]
319 def getDefaultConference( self ):
320 dconf = HelperMaKaCInfo.getMaKaCInfoInstance().getDefaultConference()
321 if dconf == None:
322 return HelperMaKaCInfo.getMaKaCInfoInstance().setDefaultConference(DefaultConference())
323 else:
324 return dconf
328 class Category(CommonObjectBase):
330 fossilizes(ICategoryFossil)
332 def __init__( self ):
334 self.id = ""
335 self.name = ""
336 self.description = ""
337 self.subcategories = {}
338 self.materials = {}
339 self.conferences = OOTreeSet()
340 self._numConferences = 0
341 self.owner = None
342 self._defaultStyle = { "simple_event":"","meeting":"" }
343 self._order = 0
344 self.__ac = AccessController(self)
345 self.__confCreationRestricted = 1
346 self.__confCreators = []
347 self._visibility = 999
348 self._statistics = {"events":None,"contributions":None,"resources":None,\
349 "updated":None}
350 self._icon=None
351 self.materials = {}
352 #self._materials = {}
353 #self.material ={}
354 self._tasksAllowed = False
355 self._tasks = {}
356 self._taskIdGenerator = 0
357 self._tasksPublic = True
358 self._tasksCommentPublic = True
359 self._tasksManagers = []
360 self._tasksCommentators = []
361 self._taskAccessList = []
362 self._timezone = ""
363 self.__materialGenerator = Counter()
364 self._notifyCreationList = ""
366 def __cmp__(self, other):
367 if type(self) is not type(other):
368 # This is actually dangerous and the ZODB manual says not to do this
369 # because it relies on memory order. However, this branch should never
370 # be taken anyway since we do not store different types in the same set
371 # or use them as keys.
372 return cmp(hash(self), hash(other))
373 return cmp(self.getId(), other.getId())
375 def __str__(self):
376 return "<Category %s@%s>" % (self.getId(), hex(id(self)))
378 def getAccessController(self):
379 return self.__ac
381 def updateNonInheritingChildren(self, elem, delete=False):
382 pass
384 def getNotifyCreationList( self ):
385 """ self._notifyCreationList is a string containing the list of
386 email addresses to send an email to when a new event is created"""
387 try:
388 return self._notifyCreationList
389 except:
390 self._notifyCreationList = ""
391 return self._notifyCreationList
393 def setNotifyCreationList( self, value ):
394 self._notifyCreationList = value
396 def getUniqueId( self ):
397 return "cat%s" % self.getId()
399 def setPaper( self, newPaper ):
400 if self.getPaper() != None:
401 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
402 self.paper=newPaper
403 self.paper.setOwner( self )
404 self.notifyModification()
406 def cleanCache( self ):
407 """ delete cache files of this category and its fathers
408 usually used when an object in the category has changed """
409 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
410 if minfo.isCacheActive():
411 for id in self.getCategoryPath():
412 cache = CategoryCache({"categId":id})
413 cache.cleanCache()
415 def clearCache( self ):
416 """ delete cache file of this category. usually used for
417 admin purposes """
418 cache = CategoryCache({"categId":self.getId()})
419 cache.cleanCache()
421 def clearConferenceCaches( self ):
422 """ delete cache files of all conferences in the category
423 usually used for admin purposes """
424 for conf in self.getConferenceList():
425 conf.cleanCache()
427 def removePaper( self ):
428 if self.paper is None:
429 return
430 self.paper.delete()
431 self.paper.setOwner(None)
432 self.paper = None
433 self.notifyModification()
435 def recoverPaper(self, p):
436 self.setPaper(p)
437 p.recover()
439 def getPaper( self ):
440 try:
441 if self.paper:
442 pass
443 except AttributeError:
444 self.paper = None
445 return self.paper
447 def setSlides( self, newSlides ):
448 if self.getSlides() != None:
449 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
450 self.slides=newSlides
451 self.slides.setOwner( self )
452 self.notifyModification()
454 def removeSlides( self ):
455 if self.slides is None:
456 return
457 self.slides.delete()
458 self.slides.setOwner( None )
459 self.slides= None
460 self.notifyModification()
462 def recoverSlides(self, s):
463 self.setSlides(s)
464 s.recover()
466 def getSlides( self ):
467 try:
468 if self.slides:
469 pass
470 except AttributeError:
471 self.slides = None
472 return self.slides
474 def setVideo( self, newVideo ):
475 if self.getVideo() != None:
476 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
477 self.video=newVideo
478 self.video.setOwner( self )
479 self.notifyModification()
481 def removeVideo( self ):
482 if self.getVideo() is None:
483 return
484 self.video.delete()
485 self.video.setOwner(None)
486 self.video = None
487 self.notifyModification()
489 def recoverVideo(self, v):
490 self.setVideo(v)
491 v.recover()
493 def getVideo( self ):
494 try:
495 if self.video:
496 pass
497 except AttributeError:
498 self.video = None
499 return self.video
501 def setPoster( self, newPoster ):
502 if self.getPoster() != None:
503 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
504 self.poster=newPoster
505 self.poster.setOwner( self )
506 self.notifyModification()
508 def removePoster( self ):
509 if self.getPoster() is None:
510 return
511 self.poster.delete()
512 self.poster.setOwner(None)
513 self.poster = None
514 self.notifyModification()
516 def recoverPoster(self, p):
517 self.setPoster(p)
518 p.recover()
520 def getPoster( self ):
521 try:
522 if self.poster:
523 pass
524 except AttributeError:
525 self.poster = None
526 return self.poster
528 def setMinutes( self, newMinutes ):
529 if self.getMinutes() != None:
530 raise MaKaCError( _("The Minutes for this conference has already been set"))
531 self.minutes=newMinutes
532 self.minutes.setOwner( self )
533 self.notifyModification()
535 def createMinutes( self ):
536 if self.getMinutes() != None:
537 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
538 self.minutes = Minutes()
539 self.minutes.setOwner( self )
540 self.notifyModification()
541 return self.minutes
543 def removeMinutes( self ):
544 if self.getMinutes() is None:
545 return
546 self.minutes.delete()
547 self.minutes.setOwner( None )
548 self.minutes = None
549 self.notifyModification()
551 def recoverMinutes(self, min):
552 self.removeMinutes() # To ensure that the current minutes are put in
553 # the trash can.
554 self.minutes = min
555 self.minutes.setOwner( self )
556 min.recover()
557 self.notifyModification()
558 return self.minutes
560 def getMinutes( self ):
561 #To be removed
562 try:
563 if self.minutes:
564 pass
565 except AttributeError, e:
566 self.minutes = None
567 return self.minutes
569 def addMaterial( self, newMat ):
570 try:
571 newMat.setId( str(self.__materialGenerator.newCount()) )
572 except:
573 self.__materialGenerator = Counter()
574 newMat.setId(self.__materialGenerator.newCount() )
575 newMat.setOwner( self )
576 self.materials[ newMat.getId() ] = newMat
577 self.notifyModification()
579 def removeMaterial( self, mat ):
580 if mat.getId() in self.materials.keys():
581 mat.delete()
582 self.materials[mat.getId()].setOwner(None)
583 del self.materials[ mat.getId() ]
584 self.notifyModification()
585 return "done: %s"%mat.getId()
586 elif mat.getId().lower() == 'minutes':
587 self.removeMinutes()
588 return "done: %s"%mat.getId()
589 elif mat.getId().lower() == 'paper':
590 self.removePaper()
591 return "done: %s"%mat.getId()
592 elif mat.getId().lower() == 'slides':
593 self.removeSlides()
594 return "done: %s"%mat.getId()
595 elif mat.getId().lower() == 'video':
596 self.removeVideo()
597 return "done: %s"%mat.getId()
598 elif mat.getId().lower() == 'poster':
599 self.removePoster()
600 return "done: %s"%mat.getId()
601 return "not done: %s"%mat.getId()
603 def recoverMaterial(self, recMat):
604 # Id must already be set in recMat.
605 recMat.setOwner( self )
606 self.materials[ recMat.getId() ] = recMat
607 recMat.recover()
608 self.notifyModification()
610 def getMaterialRegistry(self):
612 Return the correct material registry for this type
614 from MaKaC.webinterface.materialFactories import CategoryMFRegistry
615 return CategoryMFRegistry
617 def getMaterialById( self, matId ):
618 if matId.lower() == 'paper':
619 return self.getPaper()
620 elif matId.lower() == 'slides':
621 return self.getSlides()
622 elif matId.lower() == 'video':
623 return self.getVideo()
624 elif matId.lower() == 'poster':
625 return self.getPoster()
626 elif matId.lower() == 'minutes':
627 return self.getMinutes()
628 elif self.materials.has_key(matId):
629 return self.materials[ matId ]
630 return None
632 def getMaterialList( self ):
633 try:
634 return self.materials.values()
635 except:
636 self.materials={}
637 return self.materials.values()
639 def getAllMaterialList(self):
640 l = self.getMaterialList()
641 if self.getPaper():
642 l.append( self.getPaper() )
643 if self.getSlides():
644 l.append( self.getSlides() )
645 if self.getVideo():
646 l.append( self.getVideo() )
647 if self.getPoster():
648 l.append( self.getPoster() )
649 if self.getMinutes():
650 l.append( self.getMinutes() )
651 return l
653 def getTaskList(self):
654 try :
655 return self._tasks.values()
656 except :
657 self._tasks = {}
658 return self._tasks.values()
660 def getTitle(self):
661 return self.name
663 def getTasks(self):
664 try :
665 return self._tasks
666 except :
667 self._tasks = {}
668 return self._tasks
670 def getTask(self, taskId):
671 return self.getTasks().get(taskId,None)
673 def _getTasksAllowed(self):
674 try :
675 return self._tasksAllowed
676 except :
677 self._tasksAllowed = False
678 return self._tasksAllowed
680 def tasksAllowed(self):
681 if self.hasSubcategories():
682 return False
683 return self._getTasksAllowed()
685 def setTasksAllowed(self):
686 if self.hasSubcategories() :
687 return False
688 self._getTasksAllowed()
689 self._tasksAllowed = True
690 self.notifyModification()
691 return True
693 def setTasksForbidden(self):
694 if len(self.getTaskList()) > 0 :
695 return False
696 self._getTasksAllowed()
697 self._tasksAllowed = False
698 self.notifyModification()
699 return False
701 def _getNewTaskId(self):
702 try :
703 if self._taskIdGenerator :
704 pass
705 except :
706 self._taskIdGenerator = 0
707 self._taskIdGenerator = self._taskIdGenerator + 1
708 return self._taskIdGenerator
710 def newTask(self, user):
711 if user is None :
712 return None
713 newTask = task.Task(self, self._getNewTaskId(), user)
714 self.getTasks()["%s"%newTask.getId()] = newTask
715 self.notifyModification()
716 return newTask
718 def tasksPublic(self):
719 try :
720 return self._tasksPublic
721 except :
722 self._tasksPublic = True
723 return self._tasksPublic
725 def setTasksPublic(self):
726 self.tasksPublic()
727 self._tasksPublic = True
729 def setTasksPrivate(self):
730 self.tasksPublic()
731 self._tasksPublic = False
733 def tasksCommentPublic(self):
734 try :
735 return self._tasksCommentPublic
736 except :
737 self._tasksCommentPublic = True
738 return self._tasksCommentPublic
740 def setTasksCommentPublic(self):
741 self.tasksCommentPublic()
742 self._tasksCommentPublic = True
744 def setTasksCommentPrivate(self):
745 self.tasksCommentPublic()
746 self._tasksCommentPublic = False
748 def getTasksManagerList(self):
749 try :
750 return self._tasksManagers
751 except :
752 self._tasksManagers = []
753 self._p_changed = 1
754 return self._tasksManagers
756 def getTasksManager(self, index):
757 length = len(self.getTasksManagerList())
758 if index < 0 or index >= length :
759 return None
760 return self._tasksManagers[index]
762 def addTasksManager(self,user):
763 if user is None :
764 return False
765 self.getTasksManagerList().append(user)
766 self._p_changed = 1
767 return True
769 def removeTasksManager(self, index):
770 length = len(self.getTasksManagerList())
771 if index < 0 or index >= length :
772 return False
773 del self.getTasksManagerList()[index]
774 self._p_changed = 1
775 return True
777 def getTasksCommentatorList(self):
778 try :
779 return self._tasksCommentators
780 except :
781 self._tasksCommentators = []
782 self._p_changed = 1
783 return self._tasksCommentators
785 def getTasksCommentator(self, index):
786 length = len(self.getTasksCommentatorList())
787 if index < 0 or index >= length :
788 return None
789 return self._tasksCommentators[index]
791 def addTasksCommentator(self,user):
792 if user is None :
793 return False
794 self.getTasksCommentatorList().append(user)
795 self._p_changed = 1
796 return True
798 def removeTasksCommentator(self, index):
799 length = len(self.getTasksCommentatorList())
800 if index < 0 or index >= length :
801 return False
802 del self._tasksCommentators[index]
803 self._p_changed = 1
804 return True
807 def getTasksAccessList(self):
808 try :
809 return self._tasksAccessList
810 except :
811 self._tasksAccessList = []
812 self._p_changed = 1
813 return self._tasksAccessList
815 def getTasksAccessPerson(self, index):
816 length = len(self.getTasksAccessList())
817 if index < 0 or index >= length :
818 return None
819 return self._tasksAccessList[index]
821 def addTasksAccessPerson(self,user):
822 if user is None :
823 return False
824 self.getTasksAccessList().append(user)
825 self._p_changed = 1
826 return True
828 def removeTasksAccessPerson(self, index):
829 length = len(self.getTasksAccessList())
830 if index < 0 or index >= length :
831 return False
832 del self.getTasksAccessList()[index]
833 self._p_changed = 1
834 return True
836 def hasSubcategories(self):
837 return len(self.subcategories.values()) > 0
839 def getVisibility ( self ):
841 Returns category visibility, considering that it can be
842 restricted by parent categories
844 owner = self.getOwner()
845 visibility = int(self._visibility)
847 # visibility can be restricted by parent categories
848 if owner:
849 return max(0, min(visibility, owner.getVisibility() + 1))
850 else:
851 return visibility
853 def setVisibility( self, visibility=999 ):
854 self._visibility = int(visibility)
855 self._reindex()
857 def _reindex( self ):
858 catIdx = indexes.IndexesHolder().getIndex('category')
859 catIdx.reindexCateg(self)
860 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
861 catDateIdx.reindexCateg(self)
862 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
863 catDateAllIdx.reindexCateg(self)
865 def isRoot( self ):
866 #to be improved
867 return self.owner == None
869 def getDefaultStyle( self, type ):
870 try:
871 return self._defaultStyle[type]
872 except:
873 return ""
875 def setDefaultStyle( self, type, style, subcatsStyle=False ):
876 try:
877 self._defaultStyle[type] = style
878 except:
879 self._defaultStyle = { "simple_event":"","meeting":"" }
880 self._defaultStyle[type] = style
881 self.notifyModification()
882 #raise str(subcatsStyle)
883 if subcatsStyle:
885 categ=self.getSubCategoryList()
887 for cat in categ:
888 cat.setDefaultStyle(type, style, subcatsStyle )
890 ##################################
891 # Fermi timezone awareness #
892 ##################################
893 def getTimezone(self):
894 try:
895 if self._timezone not in all_timezones:
896 self.setTimezone('UTC')
897 return self._timezone
898 except:
899 self.setTimezone('UTC')
900 return 'UTC'
902 def setTimezone(self,tz):
903 self._timezone = tz
906 def changeConfTimezones(self, tz):
907 for conference in self.getConferenceList():
908 conference.moveToTimezone(tz)
910 ##################################
911 # Fermi timezone awareness(end) #
912 ##################################
914 def getOrder( self ):
915 try:
916 return self._order
917 except:
918 self._order = 0
919 return 0
921 def setOrder( self, order ):
922 self._order = order
924 def getId( self ):
925 return self.id
927 def setId( self, newId ):
928 self.id = str( newId.strip() )
930 def getLocator( self ):
931 """Gives back (Locator) a globaly unique identification encapsulated
932 in a Locator object for the category instance """
933 d = Locator()
934 d["categId"] = self.getId()
935 return d
937 def getCategory(self):
938 return self
940 def getOwner( self ):
941 return self.owner
943 def setOwner( self, newOwner ):
944 if self.getOwner() != None and newOwner != None and self.getOwner() != newOwner:
945 self.move( newOwner )
946 else:
947 self.owner = newOwner
949 def getCategoryPath(self):
950 if self.isRoot():
951 return [self.getId()]
952 else:
953 l = self.getOwner().getCategoryPath()
954 l.append(self.getId())
955 return l
957 def getCategoryPathTitles(self):
958 # Breadcrumbs
959 breadcrumbs = []
960 cat = self
961 while cat:
962 breadcrumbs.insert(0, cat.getTitle())
963 cat = cat.getOwner()
964 return breadcrumbs
966 def delete( self, deleteConferences=0 ):
967 """removes completely a category (and all its sub-items) from the
968 system"""
970 oldOwner = self.getOwner()
972 if self.isRoot():
973 raise MaKaCError( _("Root category cannot be deleted"), _("Category"))
974 if not deleteConferences:
975 if self.getNumConferences()>0:
976 raise MaKaCError( _("This category still contains some conferences, please remove them first"), _("Category"))
977 self.cleanCache()
978 for subcateg in self.getSubCategoryList():
979 subcateg.delete( deleteConferences )
980 for conference in self.getConferenceList():
981 self.removeConference( conference, delete = True )
982 self.getOwner()._removeSubCategory( self )
983 CategoryManager().remove(self)
984 for prin in self.__ac.getAccessList():
985 if isinstance(prin, MaKaC.user.Avatar):
986 prin.unlinkTo(self, "access")
987 for prin in self.__ac.getModifierList():
988 if isinstance(prin, MaKaC.user.Avatar):
989 prin.unlinkTo(self, "manager")
990 TrashCanManager().add(self)
992 self._notify('deleted', oldOwner)
994 return
996 def move( self, newOwner ):
997 oldOwner = self.getOwner()
998 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
999 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
1001 catDateIdx.unindexCateg(self)
1002 catDateAllIdx.unindexCateg(self)
1004 self.getOwner()._removeSubCategory( self )
1005 newOwner._addSubCategory( self )
1006 self._reindex()
1007 catDateIdx.indexCateg(self)
1008 catDateAllIdx.indexCateg(self)
1010 self._notify('moved', oldOwner, newOwner)
1012 def getName( self ):
1013 return self.name
1015 def setName( self, newName ):
1016 oldName = self.name
1017 self.name = newName.strip()
1019 # Reindex when name changes
1020 nameIdx = indexes.IndexesHolder().getIndex('categoryName')
1021 nameIdx.unindex(self.getId())
1022 nameIdx.index(self.getId(), self.getTitle().decode('utf-8'))
1024 self._notify('categoryTitleChanged', oldName, newName)
1026 self.cleanCache()
1028 def getDescription( self ):
1029 return self.description
1031 def setDescription( self, newDesc ):
1032 self.description = newDesc.strip()
1033 self.cleanCache()
1035 def moveConference(self, conf, toCateg):
1037 Moves a conference from this category to another one
1039 self.removeConference( conf )
1040 toCateg._addConference( conf )
1041 conf._notify('moved', self, toCateg)
1043 def _addSubCategory( self, newSc ):
1044 #categories can only contain either conferences either other categories
1045 # but can never contain both. For the moment an exception is raised
1046 # but this could be replaced by the following policy: if a
1047 # sub-category is to be added to a category already containing
1048 # conferences then the conferes are moved into the new sub-category
1049 # and it is added to target category.
1050 #first, check that the category is registered if not raise an exception
1051 if len(self.conferences)>0:
1052 for conf in self.getConferenceList():
1053 self.moveConference(conf, newSc)
1055 if len(self.conferences)>0:
1056 raise MaKaCError( _("Cannot add subcategory: the current category already contains events"), _("Category"))
1057 newSc.setOwner( self )
1058 self.subcategories[ newSc.getId() ] = newSc
1059 self._incNumConfs(newSc.getNumConferences())
1060 self.cleanCache()
1062 def _removeSubCategory( self, sc ):
1063 """if the given subcategory belongs to the current category it removes
1064 it from the subcategories list (don't use this method, use delete
1065 instead)
1067 if sc in self.getSubCategoryList():
1068 self._decNumConfs(sc.getNumConferences())
1069 del self.subcategories[ sc.getId() ]
1070 sc.setOwner( None )
1071 self.cleanCache()
1073 def newSubCategory(self, protection):
1074 cm = CategoryManager()
1075 sc = Category()
1076 cm.add( sc )
1078 # set the protection
1079 sc.setProtection(protection)
1081 Catalog.getIdx('categ_conf_sd').add_category(sc.getId())
1082 sc._notify('created', self)
1084 self._addSubCategory( sc )
1085 self.cleanCache()
1087 return sc
1089 def _incNumConfs(self, num=1):
1090 """Increases the number of conferences for the current category in a given number.
1091 WARNING: Only Categories must use this method!!!"""
1092 self._numConferences = self.getNumConferences()
1093 self._numConferences+=num
1094 if self.getOwner() is not None:
1095 self.getOwner()._incNumConfs(num)
1097 def _decNumConfs(self, num=1):
1098 """Decreases the number of conferences for the current category in a given number.
1099 WARNING: Only Categories must use this method!!!"""
1100 self._numConferences = self.getNumConferences()
1101 self._numConferences-=num
1102 if self.getOwner() is not None:
1103 self.getOwner()._decNumConfs(num)
1105 def _addConference( self, newConf ):
1106 if len(self.subcategories)>0:
1107 raise MaKaCError( _("Cannot add event: the current category already contains some sub-categories"), _("Category"))
1108 if newConf.getId() == "":
1109 raise MaKaCError( _("Cannot add to a category an event which is not registered"), _("Category"))
1110 self.conferences.insert(newConf)
1111 newConf.addOwner(self)
1112 self._incNumConfs(1)
1113 self.indexConf(newConf)
1114 self.cleanCache()
1116 def getAccessKey(self):
1117 return ""
1119 def getModifKey(self):
1120 return ""
1122 def indexConf( self, conf ):
1123 # Specific for category changes, calls Conference.indexConf()
1124 # (date-related indexes)
1125 catIdx = indexes.IndexesHolder().getIndex('category')
1126 catIdx.indexConf(conf)
1127 conf.indexConf()
1129 def unindexConf( self, conf ):
1130 catIdx = indexes.IndexesHolder().getIndex('category')
1131 catIdx.unindexConf(conf)
1132 conf.unindexConf()
1134 def newConference( self, creator, id="", creationDate=None, modificationDate=None ):
1135 conf = Conference( creator, id, creationDate, modificationDate )
1136 ConferenceHolder().add( conf )
1137 self._addConference( conf )
1138 conf.linkCreator()
1140 conf._notify('created', self)
1142 return conf
1144 def removeConference( self, conf, notify=True, delete = False ):
1145 if not (conf in self.conferences):
1146 return
1148 self.unindexConf( conf )
1150 self.conferences.remove(conf)
1151 if delete:
1152 conf.delete()
1153 conf.removeOwner( self, notify )
1154 self._decNumConfs(1)
1155 self.cleanCache()
1157 def getSubCategoryList( self ):
1158 subcategs = self.subcategories.values()
1159 cl = []
1160 for categ in subcategs:
1161 cl.append("%04s%s-%s" % (categ.getOrder(),categ.getName().replace("-",""),categ.getId()))
1162 cl.sort()
1163 res = []
1164 for c in cl:
1165 id = c.split("-")[1]
1166 res.append(self.subcategories[id])
1167 return res
1169 def iteritems(self, *args):
1170 return self.conferences.iteritems(*args)
1172 def itervalues(self, *args):
1173 return self.conferences.itervalues(*args)
1175 def getConferenceList( self, sortType=1 ):
1176 """returns the list of conferences included in the current category.
1177 Thanks to the used structure the list is sorted by date.
1178 We can choose other sorting types:
1180 sortType=1--> By date
1181 sortType=2--> Alphabetically
1182 sortType=3--> Alphabetically - Reversed
1185 res = sorted(self.conferences, cmp=Conference._cmpByDate)
1187 if sortType==2:
1188 res.sort(Conference._cmpTitle)
1189 elif sortType==3:
1190 res.sort(Conference._cmpTitle)
1191 res = reversed(res)
1192 return res
1194 def iterConferences( self):
1195 """returns the iterator for conferences.
1197 return self.conferences
1199 def iterAllConferences( self):
1200 """returns the iterator for conferences in all subcategories.
1202 for conf in self.conferences:
1203 yield conf
1205 for subcateg in self.subcategories.itervalues():
1206 for conf in subcateg.iterAllConferences():
1207 yield conf
1209 def getAllConferenceList( self ):
1210 """returns the list of all conferences included in the current category
1211 and in all its subcategories"""
1212 res = self.getConferenceList()
1213 subcategs = self.getSubCategoryList()
1214 if subcategs != []:
1215 for subcateg in subcategs:
1216 res.extend(subcateg.getAllConferenceList())
1217 return res
1219 def getRelativeEvent(self, which, conf=None):
1220 index = Catalog.getIdx('categ_conf_sd').getCategory(self.getId())
1221 if which == 'first':
1222 return list(index[index.minKey()])[0]
1223 elif which == 'last':
1224 return list(index[index.maxKey()])[-1]
1225 elif which in ('next', 'prev'):
1226 categIter = index.itervalues()
1227 if conf:
1228 prev = None
1229 for c in categIter:
1230 if c == conf:
1231 break
1232 prev = c
1233 nextEvt = next(categIter, None)
1234 if which == 'next':
1235 return nextEvt
1236 else:
1237 return prev
1238 else:
1239 raise AttributeError("'conf' parameter missing")
1240 else:
1241 raise AttributeError("Unknown argument value: '%s'" % which)
1243 def _setNumConferences(self):
1244 self._numConferences = 0
1245 if self.conferences:
1246 self._incNumConfs(len(self.conferences))
1247 else:
1248 for sc in self.getSubCategoryList():
1249 self._incNumConfs(sc.getNumConferences())
1251 def getNumConferences( self ):
1252 """returns the total number of conferences contained in the current
1253 category and all its sub-categories (if any)"""
1254 #this new approach will speed up considerably the counting of category
1255 # conferences. However, it will give non accurate results for
1256 # conferences within many categories (a conference will be counted
1257 # twice in parent categories).
1258 # Besides this approach will generate much more conflict errors. This
1259 # can be reduced by simply isolating the counter in a separate object.
1260 try:
1261 if self._numConferences:
1262 pass
1263 except AttributeError:
1264 self._setNumConferences()
1265 return self._numConferences
1267 def _getRepository( self ):
1268 dbRoot = DBMgr.getInstance().getDBConnection().root()
1269 try:
1270 fr = dbRoot["local_repositories"]["main"]
1271 except KeyError, e:
1272 fr = fileRepository.MaterialLocalRepository()
1273 dbRoot["local_repositories"] = OOBTree()
1274 dbRoot["local_repositories"]["main"] = fr
1275 return fr
1277 def removeResource( self, res ):
1278 pass
1280 def setIcon( self, iconFile ):
1281 iconFile.setOwner( self )
1282 iconFile.setId( "icon" )
1283 iconFile.archive( self._getRepository() )
1284 iconFile.setProtection( -1 )
1285 if self.getIcon() != None:
1286 self._icon.delete()
1287 self._icon = iconFile
1288 self.notifyModification()
1290 def getIcon( self ):
1291 try:
1292 if self._icon:
1293 pass
1294 except AttributeError, e:
1295 self._icon=None
1296 return self._icon
1298 def getIconURL( self ):
1299 if self.getIcon() is None:
1300 return ""
1301 return self._icon.getURL()
1303 def removeIcon(self):
1304 if self.getIcon() is None:
1305 return
1306 self._icon.delete()
1307 self._icon = None
1308 self.notifyModification()
1310 def recoverIcon(self, icon):
1311 icon.setOwner(self)
1312 if self.getIcon() != None:
1313 self._icon.delete()
1314 self._icon = icon
1315 icon.recover()
1316 self.notifyModification()
1318 def getManagerList( self ):
1319 return self.__ac.getModifierList()
1321 def grantModification( self, prin ):
1322 self.__ac.grantModification( prin )
1323 if isinstance(prin, MaKaC.user.Avatar):
1324 prin.linkTo(self, "manager")
1325 self.cleanCache()
1327 def revokeModification( self, prin ):
1328 self.__ac.revokeModification( prin )
1329 if isinstance(prin, MaKaC.user.Avatar):
1330 prin.unlinkTo(self, "manager")
1331 self.cleanCache()
1333 def canModify( self, aw ):
1334 return self.canUserModify( aw.getUser() )
1336 def canUserModify( self, av ):
1337 inherited = 0
1338 if self.getOwner() != None:
1339 inherited = self.getOwner().canUserModify( av )
1340 return inherited or self.__ac.canModify( av )
1343 def getAllowedToAccessList( self ):
1344 return self.__ac.getAccessList()
1346 def canKeyAccess( self, aw ):
1347 # Categories don't allow access keys
1348 return False
1350 def canIPAccess( self, ip ):
1351 if not self.__ac.canIPAccess( ip ):
1352 return False
1354 # if category is inheriting, check protection above
1355 if self.getAccessProtectionLevel() == 0 and self.getOwner():
1356 return self.getOwner().canIPAccess(ip)
1357 return True
1359 def isProtected( self ):
1360 return self.__ac.isProtected()
1362 def getAccessProtectionLevel( self ):
1363 return self.__ac.getAccessProtectionLevel()
1365 def isItselfProtected( self ):
1366 return self.__ac.isItselfProtected()
1368 def hasAnyProtection( self ):
1369 if self.__ac.isProtected() or len(self.getDomainList())>0:
1370 return True
1371 if self.getAccessProtectionLevel() == -1: #PUBLIC
1372 return False
1373 if self.getOwner() is not None:
1374 return self.getOwner().hasAnyProtection()
1375 return False
1377 def setProtection( self, private ):
1379 Allows to change the category's access protection
1382 oldProtection = 1 if self.isProtected() else -1
1384 self.__ac.setProtection( private )
1385 self._notify('protectionChanged', oldProtection, private)
1386 self.cleanCache()
1388 def hasProtectedOwner( self ):
1389 return self.__ac._getFatherProtection()
1391 def isAllowedToAccess( self, av ):
1392 """Says whether an avatar can access a category independently of it is
1393 or not protected or domain filtered
1395 if self.__ac.canUserAccess( av ) or self.canUserModify( av ):
1396 return True
1397 if not self.isItselfProtected() and self.getOwner():
1398 return self.getOwner().isAllowedToAccess( av )
1400 def canView(self,aw):
1401 if self.canAccess( aw ):
1402 return True
1403 for conf in self.getConferenceList():
1404 if conf.canView( aw ):
1405 return True
1406 for subcateg in self.getSubCategoryList():
1407 if subcateg.canView( aw ):
1408 return True
1409 return False
1411 def canAccess( self, aw ):
1412 if not self.hasAnyProtection():
1413 return True
1414 if not self.isProtected():
1415 #domain checking only triggered if the category is PUBLIC
1416 return self.canIPAccess( aw.getIP() ) or \
1417 self.isAllowedToCreateConference(aw.getUser()) or \
1418 self.isAllowedToAccess(aw.getUser())
1419 return self.isAllowedToCreateConference(aw.getUser()) or \
1420 self.isAllowedToAccess(aw.getUser())
1422 def grantAccess( self, prin ):
1423 self.__ac.grantAccess( prin )
1424 if isinstance(prin, MaKaC.user.Avatar):
1425 prin.linkTo(self, "access")
1427 def revokeAccess( self, prin ):
1428 self.__ac.revokeAccess( prin )
1429 if isinstance(prin, MaKaC.user.Avatar):
1430 prin.unlinkTo(self, "access")
1432 def isConferenceCreationRestricted( self ):
1433 return self.__confCreationRestricted
1435 def restrictConferenceCreation( self ):
1436 self.__confCreationRestricted = 1
1438 def allowConferenceCreation( self ):
1439 self.__confCreationRestricted = 0
1441 def grantConferenceCreation( self, prin ):
1442 if prin not in self.__confCreators:
1443 self.__confCreators.append( prin )
1444 if isinstance(prin, MaKaC.user.Avatar):
1445 prin.linkTo(self, "creator")
1446 self._p_changed = 1
1448 def revokeConferenceCreation( self, prin ):
1449 if prin in self.__confCreators:
1450 self.__confCreators.remove( prin )
1451 if isinstance(prin, MaKaC.user.Avatar):
1452 prin.unlinkTo(self, "creator")
1453 self._p_changed = 1
1455 def getConferenceCreatorList( self ):
1456 return self.__confCreators
1458 def isAllowedToCreateConference( self, av ):
1460 if self.canUserModify( av ):
1461 return 1
1463 # Avatar is directly in the list
1464 if av in self.__confCreators:
1465 return 1
1467 # Otherwise, if it is a member of one of the groups in the list...
1468 for group in self.__confCreators:
1469 if isinstance(group, MaKaC.user.Group):
1470 if group.containsUser(av):
1471 return 1
1472 else:
1473 pass
1474 return 0
1476 def canCreateConference( self, av ):
1477 if not self.isConferenceCreationRestricted():
1478 return 1
1479 return self.isAllowedToCreateConference( av )
1481 def requireDomain( self, dom ):
1482 self.__ac.requireDomain( dom )
1483 self._notify('accessDomainAdded', dom)
1485 def freeDomain( self, dom ):
1486 self.__ac.freeDomain( dom )
1487 self._notify('accessDomainRemoved', dom)
1489 def getDomainList( self ):
1490 return self.__ac.getRequiredDomainList()
1492 def getStatistics( self ):
1493 try:
1494 if self._statistics:
1495 pass
1496 except AttributeError, e:
1497 self._statistics = {}
1498 return self._statistics
1500 def notifyModification(self, raiseEvent = True):
1501 """Method called to notify the current category has been modified.
1503 if raiseEvent:
1504 self._notify('infoChanged')
1505 self.cleanCache()
1506 self._p_changed=1
1509 class CustomLocation(Persistent):
1511 def __init__(self, **locationData):
1512 self.name = ""
1513 self.address = ""
1514 self.room = ""
1516 def setValues(self, data):
1517 self.setName(data.get("name",""))
1518 self.setAddress(data.get("address",""))
1519 self.setRoom(data.get("room",""))
1521 def getValues(self):
1522 d={}
1523 d["name"]=self.getName()
1524 d["address"]=self.getAddress()
1525 d["room"]=self.getRoom()
1526 return d
1528 def clone(self):
1529 newCL=CustomLocation()
1530 newCL.setValues(self.getValues())
1531 return newCL
1533 def setName(self, newName):
1534 self.name = newName
1536 def getName(self):
1537 return self.name
1539 def setAddress(self, newAddress):
1540 self.address = newAddress
1542 def getAddress(self):
1543 return self.address
1545 def setRoom(self, newRoom):
1546 self.room = newRoom
1548 def getRoom(self):
1549 return self.room
1552 class CustomRoom(Persistent):
1554 def __init__( self ):
1555 self.name = ""
1557 def setValues(self, data):
1558 self.setName(data.get("name",""))
1559 self.setFullName(data.get("fullName"))
1561 def getValues(self):
1562 d={}
1563 d["name"]=self.getName()
1564 d["fullName"]=self.getFullName()
1565 return d
1567 def getId(self):
1568 return "Custom"
1570 def clone(self):
1571 newCR=CustomRoom()
1572 newCR.setValues(self.getValues())
1573 return newCR
1575 def setName( self, newName ):
1576 self.name = newName.strip()
1578 def getName( self ):
1579 return self.name
1581 def retrieveFullName(self, location):
1582 if not location:
1583 return
1584 room = CrossLocationQueries.getRooms(roomName=self.name, location=location)
1585 self.fullName = room.getFullName() if room else None
1587 def setFullName(self, newFullName):
1588 self.fullName = newFullName
1590 def getFullName(self):
1591 if not hasattr(self, 'fullName'):
1592 self.fullName = None
1593 return self.fullName
1596 class ConferenceParticipation(Persistent, Fossilizable, Observable):
1598 fossilizes(IConferenceParticipationFossil, IConferenceParticipationMinimalFossil)
1600 def __init__(self):
1601 self._firstName=""
1602 self._surName=""
1603 self._email=""
1604 self._affiliation=""
1605 self._address=""
1606 self._phone=""
1607 self._title=""
1608 self._fax=""
1610 def _notifyModification( self ):
1611 pass
1613 def setValues(self, data):
1614 self.setFirstName(data.get("firstName", ""))
1615 self.setFamilyName(data.get("familyName",""))
1616 self.setAffiliation(data.get("affilation",""))
1617 self.setAddress(data.get("address",""))
1618 self.setEmail(data.get("email",""))
1619 self.setFax(data.get("fax",""))
1620 self.setTitle(data.get("title",""))
1621 self.setPhone(data.get("phone",""))
1622 self._notifyModification()
1624 def getValues(self):
1625 data={}
1626 data["firstName"]=self.getFirstName()
1627 data["familyName"]=self.getFamilyName()
1628 data["affilation"]=self.getAffiliation()
1629 data["address"]=self.getAddress()
1630 data["email"]=self.getEmail()
1631 data["fax"]=self.getFax()
1632 data["title"]=self.getTitle()
1633 data["phone"]=self.getPhone()
1634 return data
1636 def setId(self, newId):
1637 self._id = newId
1639 def getId( self ):
1640 return self._id
1642 def setDataFromAvatar(self,av):
1643 # av is an Avatar object.
1644 if av is None:
1645 return
1646 self.setFirstName(av.getName())
1647 self.setFamilyName(av.getSurName())
1648 self.setEmail(av.getEmail())
1649 self.setAffiliation(av.getOrganisation())
1650 self.setAddress(av.getAddress())
1651 self.setPhone(av.getTelephone())
1652 self.setTitle(av.getTitle())
1653 self.setFax(av.getFax())
1654 self._notifyModification()
1656 def setDataFromOtherCP(self,cp):
1657 # cp is a ConferenceParticipation object.
1658 if cp is None:
1659 return
1660 self.setFirstName(cp.getFirstName())
1661 self.setFamilyName(cp.getFamilyName())
1662 self.setEmail(cp.getEmail())
1663 self.setAffiliation(cp.getAffiliation())
1664 self.setAddress(cp.getAddress())
1665 self.setPhone(cp.getPhone())
1666 self.setTitle(cp.getTitle())
1667 self.setFax(cp.getFax())
1668 self._notifyModification()
1670 def delete( self ):
1671 TrashCanManager().add(self)
1673 def recover(self):
1674 TrashCanManager().remove(self)
1676 @Updates (['MaKaC.conference.ConferenceParticipation',
1677 'MaKaC.conference.SessionChair',
1678 'MaKaC.conference.SlotChair'], 'firstName')
1679 def setFirstName(self,newName):
1680 tmp=newName.strip()
1681 if tmp==self._firstName:
1682 return
1683 self._firstName=tmp
1684 self._notifyModification()
1686 def getFirstName( self ):
1687 return self._firstName
1689 @Updates (['MaKaC.conference.ConferenceParticipation',
1690 'MaKaC.conference.SessionChair',
1691 'MaKaC.conference.SlotChair'], 'familyName')
1692 def setFamilyName(self,newName):
1693 tmp=newName.strip()
1694 if tmp==self._surName:
1695 return
1696 self._surName=tmp
1697 self._notifyModification()
1699 def getFamilyName( self ):
1700 return self._surName
1702 @Updates (['MaKaC.conference.ConferenceParticipation',
1703 'MaKaC.conference.SessionChair',
1704 'MaKaC.conference.SlotChair'], 'email')
1705 def setEmail(self,newMail):
1706 tmp=newMail.strip()
1707 if tmp==self._email:
1708 return
1709 self._email=newMail.strip()
1710 self._notifyModification()
1712 def getEmail( self ):
1713 return self._email
1715 @Updates (['MaKaC.conference.ConferenceParticipation',
1716 'MaKaC.conference.SessionChair',
1717 'MaKaC.conference.SlotChair'], 'affiliation')
1718 def setAffiliation(self,newAffil):
1719 self._affiliation=newAffil.strip()
1720 self._notifyModification()
1722 def getAffiliation(self):
1723 return self._affiliation
1725 @Updates (['MaKaC.conference.ConferenceParticipation',
1726 'MaKaC.conference.SessionChair',
1727 'MaKaC.conference.SlotChair'], 'address')
1728 def setAddress(self,newAddr):
1729 self._address=newAddr.strip()
1730 self._notifyModification()
1732 def getAddress(self):
1733 return self._address
1735 @Updates (['MaKaC.conference.ConferenceParticipation',
1736 'MaKaC.conference.SessionChair',
1737 'MaKaC.conference.SlotChair'], 'phone')
1738 def setPhone(self,newPhone):
1739 self._phone=newPhone.strip()
1740 self._notifyModification()
1742 def getPhone(self):
1743 return self._phone
1745 @Updates (['MaKaC.conference.ConferenceParticipation',
1746 'MaKaC.conference.SessionChair',
1747 'MaKaC.conference.SlotChair'], 'title')
1748 def setTitle(self,newTitle):
1749 self._title=newTitle.strip()
1750 self._notifyModification()
1752 def getTitle(self):
1753 return self._title
1755 @Updates (['MaKaC.conference.ConferenceParticipation',
1756 'MaKaC.conference.SessionChair',
1757 'MaKaC.conference.SlotChair'], 'fax')
1758 def setFax(self,newFax):
1759 self._fax=newFax.strip()
1760 self._notifyModification()
1762 def getFax(self):
1763 return self._fax
1765 def getFullName( self ):
1766 res = self.getFamilyName()
1767 if self.getFirstName() != "":
1768 if res.strip() != "":
1769 res = "%s, %s"%( res, self.getFirstName() )
1770 else:
1771 res = self.getFirstName()
1772 if self.getTitle() != "":
1773 res = "%s %s"%( self.getTitle(), res )
1774 return res
1776 def getFullNameNoTitle( self ):
1777 res = self.getFamilyName()
1778 if self.getFirstName() != "":
1779 if res.strip() != "":
1780 res = "%s, %s"%( res, self.getFirstName() )
1781 else:
1782 res = self.getFirstName()
1783 return res
1785 def getDirectFullName( self ):
1786 res = "%s %s"%( self.getFirstName(), self.getFamilyName() )
1787 res=res.strip()
1788 if self.getTitle() != "":
1789 res = "%s %s"%( self.getTitle(), res )
1790 return res
1792 def getAbrName(self):
1793 res = self.getFamilyName()
1794 if self.getFirstName() != "":
1795 if res != "":
1796 res = "%s, "%res
1797 res = "%s%s."%(res, self.getFirstName()[0].upper())
1798 return res
1800 def _cmpFamilyName( cp1, cp2 ):
1801 o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName())
1802 o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName())
1803 o1=o1.lower().strip()
1804 o2=o2.lower().strip()
1805 return cmp( o1, o2 )
1806 _cmpFamilyName=staticmethod(_cmpFamilyName)
1809 class ConferenceChair(ConferenceParticipation, Fossilizable):
1811 fossilizes(IConferenceParticipationFossil)
1813 def __init__(self):
1814 self._conf=None
1815 self._id=""
1816 ConferenceParticipation.__init__(self)
1818 def _notifyModification( self ):
1819 if self._conf != None:
1820 self._conf.notifyModification()
1822 def clone(self):
1823 newCC=ConferenceChair()
1824 newCC.setValues(self.getValues())
1825 return newCC
1827 def getConference(self):
1828 return self._conf
1830 def getId(self):
1831 return self._id
1833 def includeInConference(self,conf,id):
1834 if self.getConference()==conf and self.getId()==id.strip():
1835 return
1836 self._conf=conf
1837 self._id=id
1839 def delete( self ):
1840 self._conf=None
1841 ConferenceParticipation.delete(self)
1843 def getLocator(self):
1844 if self.getConference() is None:
1845 return None
1846 loc=self.getConference().getLocator()
1847 loc["chairId"]=self.getId()
1848 return loc
1850 class SubmitterIndex(Persistent):
1851 """Index for contribution submitters.
1853 This class allows to index users with submission privileges over the
1854 conference contributions so the owner can answer optimally to the query
1855 if a user has any submission privilege over any contribution
1856 of the conference.
1857 It is implemented by simply using a BTree where the Avatar id is used
1858 as key (because it is unique and non variable) and a list of
1859 contributions over which he has submission privileges is kept as values.
1860 It is the responsability of the index owner (conference contributions)
1861 to keep it up-to-date i.e. notify conference sumitters additions and
1862 removals.
1865 def __init__( self ):
1866 self._idx = OOBTree()
1867 self._idxEmail = OOBTree()
1869 def _getIdxEmail(self):
1870 try:
1871 return self._idxEmail
1872 except:
1873 self._idxEmail = OOBTree()
1874 return self._idxEmail
1876 def getContributions(self,av):
1877 """Gives a list with the contributions over which a user has
1878 coordination privileges
1880 if av == None:
1881 return []
1882 ret = self._idx.get(av.getId(),[])
1883 if not ret:
1884 self._moveEmailtoId(av)
1885 ret = self._idx.get(av.getId(),[])
1886 return ret
1888 def index(self,av,contrib):
1889 """Registers in the index a submitter of a contribution.
1891 if av==None or contrib==None:
1892 return
1893 if not self._idx.has_key(av.getId()):
1894 l=[]
1895 self._idx[av.getId()]=l
1896 else:
1897 l=self._idx[av.getId()]
1898 if contrib not in l:
1899 l.append(contrib)
1900 self._idx[av.getId()]=l
1902 def indexEmail(self, email, contrib):
1903 if not email or not contrib:
1904 return
1905 if not self._getIdxEmail().has_key(email):
1906 l = [contrib]
1907 self._getIdxEmail()[email] = l
1908 else:
1909 l = self._getIdxEmail()[email]
1910 if not contrib in l:
1911 l.append(contrib)
1912 self._getIdxEmail()[email] = l
1915 def unindex(self,av,contrib):
1916 if av==None or contrib==None:
1917 return
1918 l=self._idx.get(av.getId(),[])
1919 if contrib in l:
1920 l.remove(contrib)
1921 self._idx[av.getId()]=l
1923 def unindexEmail(self, email, contrib):
1924 if not email or not contrib:
1925 return
1926 if self._getIdxEmail().has_key(email):
1927 l = self._getIdxEmail()[email]
1928 if contrib in l:
1929 l.remove(contrib)
1930 if l == []:
1931 del self._getIdxEmail()[email]
1932 else:
1933 self._getIdxEmail()[email] = l
1935 def _moveEmailtoId(self, av):
1936 id = av.getId()
1937 email = av.getEmail()
1938 if not self._idx.has_key(id):
1939 if self._getIdxEmail().has_key(email):
1940 self._idx[id] = self._getIdxEmail()[email]
1941 del self._getIdxEmail()[email]
1944 class ReportNumberHolder(Persistent):
1946 def __init__(self, owner):
1947 self._owner=owner
1948 self._reports={}
1950 def getOwner(self):
1951 return self._owner
1953 def addReportNumber(self, system, number):
1954 if system in self.getReportNumberKeys() or system in Config.getInstance().getReportNumberSystems().keys():
1955 try:
1956 if not number in self._reports[system]:
1957 self._reports[system].append(number)
1958 except:
1959 self._reports[system]=[ number ]
1960 self.notifyModification()
1962 def removeReportNumber(self, system, number):
1963 if self.hasReportNumbersBySystem(system):
1964 if number in self._reports[system]:
1965 self._reports[system].remove(number)
1966 self.notifyModification()
1968 def removeReportNumberById(self, id):
1969 try:
1970 rn = self.listReportNumbers()[int(id)]
1971 self.removeReportNumber(rn[0], rn[1])
1972 except:
1973 pass
1975 def hasReportNumbersBySystem(self, system):
1976 return self._reports.has_key(system)
1978 def getReportNumbersBySystem(self, system):
1979 if self.hasReportNumbersBySystem(system):
1980 return self._reports[system]
1981 return None
1983 def getReportNumberKeys(self):
1984 return self._reports.keys()
1986 def listReportNumbersOnKey(self, key):
1987 reports=[]
1988 if key in self._reports.keys():
1989 # compatibility with previous versions
1990 if type(self._reports[key]) is str:
1991 self._reports[key] = [ self._reports[key] ]
1992 for number in self._reports[key]:
1993 reports.append([key, number])
1994 return reports
1996 def hasReportNumberOnSystem(self, system, number):
1997 if self.hasReportNumbersBySystem(system):
1998 if number in self._reports[system]:
1999 return True
2000 return False
2002 def listReportNumbers(self):
2003 reports=[]
2004 keys = self._reports.keys()
2005 keys.sort()
2006 for key in keys:
2007 # compatibility with previous versions
2008 if type(self._reports[key]) is str:
2009 self._reports[key] = [ self._reports[key] ]
2010 for number in self._reports[key]:
2011 reports.append([key, number])
2012 return reports
2014 def clone(self, owner):
2015 newR=ReportNumberHolder(owner)
2016 for key in self._reports.keys():
2017 for number in self._reports[key]:
2018 newR.addReportNumber(key, number)
2019 return newR
2021 def notifyModification(self):
2022 self._p_changed=1
2023 if self.getOwner() != None:
2024 self.getOwner().notifyModification()
2027 class Conference(CommonObjectBase, Locatable):
2028 """This class represents the real world conferences themselves. Objects of
2029 this class will contain basic data about the confence and will provide
2030 access to other objects representing certain parts of the conferences
2031 (ex: contributions, sessions, ...).
2034 fossilizes(IConferenceFossil, IConferenceMinimalFossil, IConferenceEventInfoFossil)
2036 def __init__(self, creator, id="", creationDate = None, modificationDate = None):
2037 """Class constructor. Initialise the class attributes to the default
2038 values.
2039 Params:
2040 confData -- (Dict) Contains the data the conference object has to
2041 be initialised to.
2043 #IndexedObject.__init__(self)
2044 if creator == None:
2045 raise MaKaCError( _("A creator must be specified when creating a new Event"), _("Event"))
2046 self.__creator = creator
2047 self.id = id
2048 self.title = ""
2049 self.description = ""
2050 self.places = []
2051 self.rooms = []
2052 ###################################
2053 # Fermi timezone awareness #
2054 ###################################
2055 self.startDate = nowutc()
2056 self.endDate = nowutc()
2057 self.timezone = ""
2058 ###################################
2059 # Fermi timezone awareness(end) #
2060 ###################################
2061 self._screenStartDate = None
2062 self._screenEndDate = None
2063 self.contactInfo =""
2064 self.chairmanText = ""
2065 self.chairmans = []
2066 self._chairGen=Counter()
2067 self._chairs=[]
2068 self.sessions = {}
2069 self.__sessionGenerator = Counter() # Provides session unique
2070 # identifiers for this conference
2071 self.contributions = {}
2072 self.__contribGenerator = Counter() # Provides contribution unique
2073 # identifiers for this conference
2074 self.programDescription = ""
2075 self.program = []
2076 self.__programGenerator = Counter() # Provides track unique
2077 # identifiers for this conference
2078 self.__ac = AccessController(self)
2079 self.materials = {}
2080 self.__materialGenerator = Counter() # Provides material unique
2081 # identifiers for this conference
2082 self.paper = None
2083 self.slides = None
2084 self.video = None
2085 self.poster = None
2086 self.minutes=None
2087 self.__schedule=None
2088 self.__owners = []
2089 if creationDate:
2090 self._creationDS = creationDate
2091 else:
2092 self._creationDS = nowutc() #creation timestamp
2093 if modificationDate:
2094 self._modificationDS = modificationDate
2095 else:
2096 self._modificationDS = nowutc() #modification timestamp
2098 self.alarmList = {}
2099 self.__alarmCounter = Counter()
2101 self.abstractMgr = review.AbstractMgr(self)
2102 self._logo = None
2103 self._trackCoordinators = TCIndex() #index for the track coordinators
2104 self._supportInfo = SupportInfo(self, "Support")
2105 self._contribTypes = {}
2106 self.___contribTypeGenerator = Counter()
2107 self._authorIdx=AuthorIndex()
2108 self._speakerIdx=AuthorIndex()
2109 self._primAuthIdx=_PrimAuthIdx(self)
2110 self._sessionCoordinators=SCIndex()
2111 self._sessionCoordinatorRights = []
2112 self._submitterIdx=SubmitterIndex()
2113 self._boa=BOAConfig(self)
2114 self._registrationForm = registration.RegistrationForm(self)
2115 self._evaluationCounter = Counter()
2116 self._evaluations = [Evaluation(self)]
2117 self._registrants = {} #key=registrantId; value=Registrant
2118 self._bookings = {}
2119 self._registrantGenerator = Counter()
2120 self._accessKey=""
2121 self._modifKey=""
2122 self._closed = False
2123 self._visibility = 999
2124 self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self)
2125 self._sections = []
2126 self._participation = Participation(self)
2127 self._logHandler = LogHandler()
2128 self._reportNumberHolder=ReportNumberHolder(self)
2129 self._enableSessionSlots = False
2130 self._enableSessions = False
2131 self._autoSolveConflict = True
2132 self.__badgeTemplateManager = BadgeTemplateManager(self)
2133 self.__posterTemplateManager = PosterTemplateManager(self)
2134 self._keywords = ""
2135 self._confPaperReview = ConferencePaperReview(self)
2136 self._confAbstractReview = ConferenceAbstractReview(self)
2137 self._orgText = ""
2138 self._comments = ""
2139 self._sortUrlTag = ""
2141 self._observers = []
2143 if PluginsHolder().hasPluginType("Collaboration"):
2144 from MaKaC.plugins.Collaboration.base import CSBookingManager
2145 self._CSBookingManager = CSBookingManager(self)
2147 def __str__(self):
2148 return "<Conference %s@%s>" % (self.getId(), hex(id(self)))
2150 @staticmethod
2151 def _cmpByDate(self, toCmp):
2152 res = cmp(self.getStartDate(), toCmp.getStartDate())
2153 if res != 0:
2154 return res
2155 else:
2156 return cmp(self, toCmp)
2158 def __cmp__(self, toCmp):
2159 if isinstance(toCmp, Conference):
2160 return cmp(self.getId(), toCmp.getId())
2161 else:
2162 return cmp(hash(self), hash(toCmp))
2164 def __eq__(self, toCmp):
2165 return self is toCmp
2167 def __ne__(self, toCmp):
2168 return not(self is toCmp)
2170 def setUrlTag(self, tag):
2171 self._sortUrlTag = tag
2173 def getUrlTag(self):
2174 try:
2175 return self._sortUrlTag
2176 except:
2177 self._sortUrlTag = ""
2178 return self._sortUrlTag
2180 def setComments(self,comm=""):
2181 self._comments = comm.strip()
2183 def getComments(self):
2184 try:
2185 if self._comments:
2186 pass
2187 except AttributeError,e:
2188 self.setComments()
2189 return self._comments
2191 def getConfPaperReview(self):
2192 if not hasattr(self, "_confPaperReview"):
2193 self._confPaperReview = ConferencePaperReview(self)
2194 return self._confPaperReview
2196 def getConfAbstractReview(self):
2197 if not hasattr(self, "_confAbstractReview"):
2198 self._confAbstractReview = ConferenceAbstractReview(self)
2199 return self._confAbstractReview
2201 def getOrgText( self ):
2202 try:
2203 return self._orgText
2204 except:
2205 self.setOrgText()
2206 return ""
2208 def setOrgText( self, org="" ):
2209 self._orgText = org
2211 def cleanCache( self ):
2212 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
2213 if minfo.isCacheActive():
2214 cache = EventCache({"id":self.getId(), "type": "normal"})
2215 cache.cleanCache()
2216 cache = EventCache({"id":self.getId(), "type": "manager"})
2217 cache.cleanCache()
2218 cache = EventCache({"id":self.getId(), "type": "static"})
2219 cache.cleanCache()
2221 if not ContextManager.get('clean%s'%self.getUniqueId(), False):
2222 ScheduleToJson.cleanConferenceCache(self)
2223 ContextManager.set('clean%s'%self.getUniqueId(), True)
2225 def cleanCategoryCache( self ):
2226 if len(self.getOwnerList()) > 0:
2227 self.getOwnerList()[0].cleanCache()
2229 def updateNonInheritingChildren(self, elem, delete=False):
2230 self.getAccessController().updateNonInheritingChildren(elem, delete)
2232 def getKeywords(self):
2233 try:
2234 return self._keywords
2235 except:
2236 self._keywords = ""
2237 return ""
2239 def setKeywords(self, keywords):
2240 self._keywords = keywords
2242 # Room booking related ===================================================
2244 def getRoomBookingList( self ):
2246 Returns list of bookings for this conference.
2248 from MaKaC.plugins.RoomBooking.default.dalManager import DALManager
2250 if not DALManager.isConnected():
2251 return []
2253 resvs = []
2254 for resvGuid in self.getRoomBookingGuids():
2255 r = resvGuid.getReservation()
2256 if r == None:
2257 self.removeRoomBookingGuid( resvGuid )
2258 elif r.isValid:
2259 resvs.append( r )
2260 return resvs
2262 def getBookedRooms( self ):
2264 Returns list of rooms booked for this conference.
2265 Returns [] if room booking module is off.
2267 rooms = []
2269 for r in self.getRoomBookingList():
2270 if not r.room in rooms:
2271 rooms.append( r.room )
2272 return rooms
2274 def getRoomBookingGuids( self ):
2275 try:
2276 self.__roomBookingGuids
2277 except AttributeError:
2278 self.__roomBookingGuids = []
2279 return self.__roomBookingGuids
2281 def setRoomBookingGuids( self, guids ):
2282 self.__roomBookingGuids = guids
2284 def addRoomBookingGuid( self, guid ):
2285 self.getRoomBookingGuids().append( guid )
2286 self._p_changed = True
2288 def removeRoomBookingGuid( self, guid ):
2289 self.getRoomBookingGuids().remove( guid )
2290 self._p_changed = True
2292 def __TMP_PopulateRoomBookings( self ):
2293 # TEMPORARY GENERATION OF RESERVATIONS FOR CONFERENCE
2294 from MaKaC.rb_reservation import ReservationBase
2295 from MaKaC.rb_location import ReservationGUID, Location
2296 resvs = []
2297 resvs.append( ReservationBase.getReservations( resvID = 395887 ) )
2298 resvs.append( ReservationBase.getReservations( resvID = 381406 ) )
2299 resvs.append( ReservationBase.getReservations( resvID = 387688 ) )
2300 resvs.append( ReservationBase.getReservations( resvID = 383459 ) )
2302 resvGuids = []
2303 for resv in resvs:
2304 resvGuids.append( ReservationGUID( Location.getDefaultLocation(), resv.id ) )
2306 self.__roomBookingGuids = resvGuids
2309 # ========================================================================
2311 def getParticipation(self):
2312 try :
2313 if self._participation :
2314 pass
2315 except AttributeError :
2316 self._participation = Participation(self)
2317 return self._participation
2319 def getType( self ):
2320 import MaKaC.webinterface.webFactoryRegistry as webFactoryRegistry
2321 wr = webFactoryRegistry.WebFactoryRegistry()
2322 wf = wr.getFactory(self)
2323 if wf != None:
2324 type = wf.getId()
2325 else:
2326 type = "conference"
2327 return type
2329 def getVerboseType( self ):
2330 # Like getType, but returns "Lecture" instead of "simple_type"
2331 type = self.getType()
2332 if type == "simple_event":
2333 type = "lecture"
2334 return type.capitalize()
2337 def getLogHandler(self):
2338 try :
2339 if self._logHandler:
2340 pass
2341 except AttributeError :
2342 self._logHandler = LogHandler()
2343 return self._logHandler
2346 def getEnableSessionSlots(self):
2347 #try :
2348 # if self._enableSessionSlots :
2349 # pass
2350 #except AttributeError :
2351 # self._enableSessionSlots = True
2352 #if self.getType() == "conference":
2353 # return True
2354 #return self._enableSessionSlots
2355 return True
2357 def getEnableSessions(self):
2358 try :
2359 if self._enableSessions :
2360 pass
2361 except AttributeError :
2362 self._enableSessions = True
2363 if self.getType() == "conference":
2364 return True
2365 return self._enableSessions
2367 def enableSessionSlots(self):
2368 self._enableSessionSlots = True
2370 def disableSessionSlots(self):
2371 self._enableSessionSlots = False
2373 def enableSessions(self):
2374 self._enableSessions = True
2376 def disableSessions(self):
2377 self._enableSessions = False
2379 def setValues(self, confData):
2381 Sets SOME values of the current conference object from a dictionary
2382 containing the following key-value pairs:
2383 visibility-(str)
2384 title-(str)
2385 description-(str)
2386 supportEmail-(str)
2387 contactInfo-(str)
2388 locationName-(str) => name of the location, if not specified
2389 it will be set to the conference location name.
2390 locationAddress-(str)
2391 roomName-(str) => name of the room, if not specified it will
2392 be set to the conference room name.
2393 Please, note that this method sets SOME values which means that if
2394 needed it can be completed to set more values. Also note that if
2395 the given dictionary doesn't contain all the values, the missing
2396 ones will be set to the default values.
2398 self.setVisibility(confData.get("visibility", "999"))
2399 self.setTitle(confData.get("title", _("NO TITLE ASSIGNED")))
2400 self.setDescription(confData.get("description", ""))
2401 self.getSupportInfo().setEmail(confData.get("supportEmail", ""))
2402 self.setContactInfo(confData.get("contactInfo", ""))
2403 if confData.get("locationName", "").strip() == "":
2404 self.setLocation(None)
2405 else:
2406 #if the location name is defined we must set a new location (or
2407 # modify the existing one) for the conference
2408 loc = self.getLocation()
2409 if not loc:
2410 loc = CustomLocation()
2411 self.setLocation(loc)
2412 loc.setName(confData["locationName"])
2413 loc.setAddress(confData.get("locationAddress", ""))
2414 #same as for the location
2415 if confData.get("roomName", "").strip() == "":
2416 self.setRoom(None)
2417 else:
2418 room = self.getRoom()
2419 if not room:
2420 room = CustomRoom()
2421 self.setRoom(room)
2422 room.setName(confData["roomName"])
2423 self.notifyModification()
2425 def getVisibility ( self ):
2426 try:
2427 return int(self._visibility)
2428 except:
2429 self._visibility = 999
2430 return 999
2432 def getFullVisibility( self ):
2433 return max(0,min(self.getVisibility(), self.getOwnerList()[0].getVisibility()))
2435 def setVisibility( self, visibility=999 ):
2436 self._visibility = int(visibility)
2437 catIdx = indexes.IndexesHolder().getIndex('category')
2438 catIdx.reindexConf(self)
2439 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2440 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
2441 catDateIdx.reindexConf(self)
2442 catDateAllIdx.reindexConf(self)
2444 def isClosed( self ):
2445 try:
2446 return self._closed
2447 except:
2448 self._closed = False
2449 return False
2451 def setClosed( self, closed=True ):
2452 self._closed = closed
2454 def indexConf( self ):
2455 # called when event dates change
2456 # see also Category.indexConf()
2458 calIdx = indexes.IndexesHolder().getIndex('calendar')
2459 calIdx.indexConf(self)
2460 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2461 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
2462 catDateIdx.indexConf(self)
2463 catDateAllIdx.indexConf(self)
2464 nameIdx = indexes.IndexesHolder().getIndex('conferenceTitle')
2465 nameIdx.index(self.getId(), self.getTitle().decode('utf-8'))
2467 Catalog.getIdx('categ_conf_sd').index_obj(self)
2470 def unindexConf( self ):
2471 calIdx = indexes.IndexesHolder().getIndex('calendar')
2472 calIdx.unindexConf(self)
2473 catDateIdx = indexes.IndexesHolder().getIndex('categoryDate')
2474 catDateAllIdx = indexes.IndexesHolder().getIndex('categoryDateAll')
2475 catDateIdx.unindexConf(self)
2476 catDateAllIdx.unindexConf(self)
2477 nameIdx = indexes.IndexesHolder().getIndex('conferenceTitle')
2478 nameIdx.unindex(self.getId())
2480 Catalog.getIdx('categ_conf_sd').unindex_obj(self)
2483 def __generateNewContribTypeId( self ):
2484 """Returns a new unique identifier for the current conference sessions
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 linkCreator(self):
2655 self.__creator.linkTo(self, "creator")
2657 def getId( self ):
2658 """returns (string) the unique identifier of the conference"""
2659 return self.id
2661 def getUniqueId( self ):
2662 """returns (string) the unique identiffier of the item"""
2663 """used mainly in the web session access key table"""
2664 return "a%s" % self.id
2666 def setId(self, newId):
2667 """changes the current unique identifier of the conference to the
2668 one which is specified"""
2669 self.id = str(newId)
2671 def getLocator( self ):
2672 """Gives back (Locator) a globaly unique identification encapsulated in
2673 a Locator object for the conference instance """
2674 d = Locator()
2675 d["confId"] = self.getId()
2676 return d
2678 def getOwner( self ):
2679 if self.getOwnerList() == []:
2680 return None
2681 return self.getOwnerList()[0]
2683 def getOwnerList( self ):
2684 return self.__owners
2686 def getOwnerPath( self ):
2687 l=[]
2688 owner = self.getOwnerList()[0]
2689 while owner != None and owner.getId() != "0":
2690 l.append(owner)
2691 owner = owner.getOwner()
2692 return l
2694 def getOwnerById( self, key ):
2695 """Returns one specific category which contains the conference.
2696 Params:
2697 - key: The "id" of the category.
2699 for owner in self.__owners:
2700 if key == owner.getId():
2701 return owner
2702 return None
2704 def addOwner( self, newOwner ):
2705 if newOwner == None:
2706 return
2707 self.__owners.append( newOwner )
2708 self.notifyModification()
2710 def removeOwner( self, owner, notify=True ):
2711 if not (owner in self.__owners):
2712 return
2713 self.__owners.remove( owner )
2714 owner.removeConference( self )
2715 if notify:
2716 self.notifyModification()
2718 def getCategoriesPath(self):
2719 return [self.getOwnerList()[0].getCategoryPath()]
2721 def notifyContributions(self):
2723 for c in self.getContributionList():
2724 # take care of subcontributions
2725 for sc in c.getSubContributionList():
2726 sc._notify('deleted', c)
2728 c._notify('deleted', self)
2730 def delete( self ):
2731 """deletes the conference from the system.
2733 #we notify the observers that the conference has been deleted
2734 try:
2735 self._notify('deleted', self.getOwner())
2736 except Exception, e:
2737 try:
2738 Logger.get('Conference').error("Exception while notifying the observer of a conference deletion for conference %s: %s" %
2739 (self.getId(), str(e)))
2740 except Exception, e2:
2741 Logger.get('Conference').error("Exception while notifying a conference deletion: %s (origin: %s)" % (str(e2), str(e)))
2743 self.notifyContributions()
2745 #will have to remove it from all the owners (categories) and the
2746 # conference registry
2747 ConferenceHolder().remove( self )
2748 for owner in self.__owners:
2749 owner.removeConference( self, notify=False )
2751 for alarm in self.getAlarmList():
2752 if not alarm.getEndedOn():
2753 self.removeAlarm(alarm)
2755 self.removeAllEvaluations()
2757 #Delete the RoomBooking associated reservations
2758 minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
2759 if minfo.getRoomBookingModuleActive() and CrossLocationDB.isConnected():
2760 for resv in self.getRoomBookingList():
2761 resv.remove()
2763 #For each conference we have a list of managers. If we delete the conference but we don't delete
2764 #the link in every manager to the conference then, when the manager goes to his "My profile" he
2765 #will see a link to a conference that doesn't exist. Therefore, we need to delete that link as well
2766 for manager in self.getManagerList():
2767 if isinstance(manager, MaKaC.user.Avatar):
2768 manager.unlinkTo(self, "manager")
2770 # Remove all links in redis
2771 if redis_write_client:
2772 avatar_links.delete_event(self)
2774 # Remote short URL mappings
2775 sum = ShortURLMapper()
2776 sum.remove(self)
2778 TrashCanManager().add(self)
2780 def getConference( self ):
2781 return self
2783 def getObservers(self):
2784 if not hasattr(self, "_observers"):
2785 self._observers = []
2786 return self._observers
2788 def setDates( self, sDate, eDate=None, check=1, moveEntries=0):
2790 Set the start/end date for a conference
2793 oldStartDate = self.getStartDate()
2794 oldEndDate = self.getEndDate()
2796 # do some checks first
2797 if sDate > eDate:
2798 # obvious case
2799 raise MaKaCError( _("Start date cannot be after the end date"), _("Event"))
2801 elif sDate == oldStartDate and eDate == oldEndDate:
2802 # if there's nothing to do (yet another obvious case)
2803 return
2805 # if we reached this point, it means either the start or
2806 # the end date (or both) changed
2807 # If only the end date was changed, moveEntries = 0
2808 if sDate == oldStartDate:
2809 moveEntries = 0
2811 # Pre-check for moveEntries
2812 if moveEntries == 1:
2813 # in case the entries are to be simply shifted
2814 # we should make sure the interval is big enough
2815 # just store the old values for later
2817 oldInterval = oldEndDate - oldStartDate
2818 newInterval = eDate - sDate
2820 entries = self.getSchedule().getEntries()
2821 if oldInterval > newInterval and entries:
2822 eventInterval = entries[-1].getEndDate() - entries[0].getStartDate()
2823 diff = entries[0].getStartDate() - oldStartDate
2824 if sDate + diff + eventInterval > eDate:
2825 raise TimingError(
2826 _("The start/end dates were not changed since the selected "
2827 "timespan is not large enough to accomodate the contained "
2828 "timetable entries and spacings."),
2829 explanation=_("You should try using a larger timespan."))
2831 # so, we really need to try changing something
2833 self.unindexConf()
2835 # set the dates
2836 self.setStartDate(sDate, check=0, moveEntries = moveEntries, index=False, notifyObservers = False)
2837 self.setEndDate(eDate, check=0, index=False, notifyObservers = False)
2839 # sanity check
2840 self._checkInnerSchedule()
2842 # reindex the conference
2843 self.indexConf()
2845 # clear the category cache
2846 self.cleanCategoryCache()
2848 # notify observers
2849 try:
2850 self._notify('dateChanged', {'oldStartDate': oldStartDate, 'newStartDate': self.getStartDate(), 'oldEndDate': oldEndDate, 'newEndDate': self.getEndDate()})
2851 except Exception, e:
2852 try:
2853 Logger.get('Conference').error("Exception while notifying the observer of a start and end date change from %s - %s to %s - %s for conference %s: %s" %
2854 (formatDateTime(oldStartDate), formatDateTime(oldEndDate),
2855 formatDateTime(self.getStartDate()), formatDateTime(self.getEndDate()), self.getId(), str(e)))
2856 except Exception, e2:
2857 Logger.get('Conference').error("Exception while notifying a start and end date change: %s (origin: %s)" % (str(e2), str(e)))
2860 def _checkInnerSchedule( self ):
2861 self.getSchedule().checkSanity()
2863 def setStartDate(self, sDate, check = 1, moveEntries = 0, index = True, notifyObservers = True):
2864 """ Changes the current conference starting date/time to the one specified by the parameters.
2866 if not sDate.tzname():
2867 raise MaKaCError("date should be timezone aware")
2868 if sDate == self.getStartDate():
2869 return
2870 ###################################
2871 # Fermi timezone awareness #
2872 ###################################
2873 if sDate.year < 1900:
2874 sDate = timezone('UTC').localize(1900,sDate.month, \
2875 sDate.day,sDate.hour,sDate.minute)
2876 ###################################
2877 # Fermi timezone awareness #
2878 ###################################
2879 if check != 0:
2880 self.verifyStartDate(sDate)
2881 oldSdate = self.getStartDate()
2882 diff = sDate - oldSdate
2884 if index:
2885 self.unindexConf()
2886 self.startDate = sDate
2887 if moveEntries and diff is not None:
2888 # If the start date changed, we move entries inside the timetable
2889 self.getSchedule()._startDate=None
2890 self.getSchedule()._endDate=None
2891 #if oldSdate.date() != sDate.date():
2892 # entries = self.getSchedule().getEntries()[:]
2893 #else:
2894 # entries = self.getSchedule().getEntriesOnDay(sDate.astimezone(timezone(self.getTimezone())))[:]
2895 entries = self.getSchedule().getEntries()[:]
2896 self.getSchedule().moveEntriesBelow(diff, entries)
2897 #datetime object is non-mutable so we must "force" the modification
2898 # otherwise ZODB won't be able to notice the change
2899 self.notifyModification()
2900 if index:
2901 self.indexConf()
2903 # update the time for the alarms to be sent
2904 self._updateAlarms()
2906 # Update redis link timestamp
2907 if redis_write_client:
2908 avatar_links.update_event_time(self)
2910 #if everything went well, we notify the observers that the start date has changed
2911 if notifyObservers:
2912 try:
2913 self._notify('startDateChanged', {'newDate': sDate, 'oldDate': oldSdate})
2914 except Exception, e:
2915 try:
2916 Logger.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s" %
2917 (formatDateTime(oldSdate), formatDateTime(sDate), self.getId(), str(e)))
2918 except Exception, e2:
2919 Logger.get('Conference').error("Exception while notifying a start date change: %s (origin: %s)" % (str(e2), str(e)))
2922 def _updateAlarms(self):
2923 c = Client()
2924 # are there any alarms? if so, update the relative ones
2925 for alarm in self.getAlarmList():
2926 tbef = alarm.getTimeBefore()
2927 if tbef:
2928 # only relative alarms
2929 c.moveTask(alarm, self.getStartDate() - tbef)
2931 def verifyStartDate(self, sdate, check=1):
2932 if sdate>self.getEndDate():
2933 raise MaKaCError( _("End date cannot be before the Start date"), _("Event"))
2935 def setStartTime(self, hours=0, minutes=0, notifyObservers = True):
2936 """ Changes the current conference starting time (not date) to the one specified by the parameters.
2939 sdate = self.getStartDate()
2940 self.startDate = datetime( sdate.year, sdate.month, sdate.day,
2941 int(hours), int(minutes) )
2942 self.verifyStartDate(self.startDate)
2943 self.notifyModification()
2945 #if everything went well, we notify the observers that the start date has changed
2946 if notifyObservers:
2947 try:
2948 self._notify('startTimeChanged', sdate)
2949 #for observer in self.getObservers():
2950 #observer.notifyEventDateChanges(sdate, self.startDate, None, None)
2951 except Exception, e:
2952 try:
2953 Logger.get('Conference').error("Exception while notifying the observer of a start date change from %s to %s for conference %s: %s"%
2954 (formatDateTime(sdate), formatDateTime(self.startDate), self.getId(), str(e)))
2955 except Exception, e2:
2956 Logger.get('Conference').error("Exception while notifying a start time change: %s (origin: %s)"%(str(e2), str(e)))
2958 def getStartDate(self):
2959 """returns (datetime) the starting date of the conference"""
2960 return self.startDate
2962 def getUnixStartDate(self):
2963 return datetimeToUnixTimeInt(self.startDate)
2965 ###################################
2966 # Fermi timezone awareness #
2967 ###################################
2969 def getAdjustedStartDate(self,tz=None):
2970 if not tz:
2971 tz = self.getTimezone()
2972 if tz not in all_timezones:
2973 tz = 'UTC'
2974 return self.getStartDate().astimezone(timezone(tz))
2976 ###################################
2977 # Fermi timezone awareness(end) #
2978 ###################################
2980 def setScreenStartDate(self, date):
2981 if date == self.getStartDate():
2982 date = None
2983 self._screenStartDate = date
2984 self.notifyModification()
2986 def getScreenStartDate(self):
2987 try:
2988 date = self._screenStartDate
2989 except:
2990 date = self._screenStartDate = None
2991 if date != None:
2992 return date
2993 else:
2994 return self.getStartDate()
2996 def getAdjustedScreenStartDate(self, tz=None):
2997 if not tz:
2998 tz = self.getTimezone()
2999 return self.getScreenStartDate().astimezone(timezone(tz))
3001 def calculateDayStartTime(self, day):
3002 """returns (date) the start date of the conference on a given day
3003 day is a tz aware datetime"""
3004 if self.getStartDate().astimezone(day.tzinfo).date() == day.date():
3005 return self.getStartDate().astimezone(day.tzinfo)
3006 return self.getSchedule().calculateDayStartDate(day)
3008 def verifyEndDate(self, edate):
3009 if edate<self.getStartDate():
3010 raise TimingError( _("End date cannot be before the start date"), _("Event"))
3011 if self.getSchedule().hasEntriesAfter(edate):
3012 raise TimingError(_("Cannot change end date to %s: some entries in the timetable would be outside this date (%s)") % (edate,self.getSchedule().getEntries()[-1].getStartDate()), _("Event"))
3014 def setEndDate(self, eDate, check = 1, index = True, notifyObservers = True):
3015 """ Changes the current conference end date/time to the one specified by the parameters.
3017 if not eDate.tzname():
3018 raise MaKaCError("date should be timezone aware")
3019 if eDate == self.getEndDate():
3020 return
3021 if eDate.year < 1900:
3022 eDate = datetime(1900,eDate.month,eDate.day,eDate.hour,eDate.minute)
3023 if check != 0:
3024 self.verifyEndDate(eDate)
3025 if index:
3026 self.unindexConf()
3028 oldEdate = self.endDate
3029 self.endDate = eDate
3030 #datetime object is non-mutable so we must "force" the modification
3031 # otherwise ZODB won't be able to notice the change
3032 self.notifyModification()
3033 if index:
3034 self.indexConf()
3036 #if everything went well, we notify the observers that the start date has changed
3037 if notifyObservers:
3038 try:
3039 self._notify('endDateChanged', {'newDate': eDate, 'oldDate': oldEdate})
3040 except Exception, e:
3041 try:
3042 Logger.get('Conference').error("Exception while notifying the observer of a end date change from %s to %s for conference %s: " %
3043 (formatDateTime(oldEdate), formatDateTime(eDate), self.getId(), str(e)))
3044 except Exception, e2:
3045 Logger.get('Conference').error("Exception while notifying a end date change: %s (origin: %s)" % (str(e2), str(e)))
3048 def setEndTime(self, hours = 0, minutes = 0, notifyObservers = True):
3049 """ Changes the current conference end time (not date) to the one specified by the parameters.
3051 edate = self.getEndDate()
3052 self.endDate = datetime( edate.year, edate.month, edate.day, int(hours), int(minutes) )
3053 self.verifyEndDate(self.endDate)
3054 self.notifyModification()
3056 #if everything went well, we notify the observers that the start date has changed
3057 if notifyObservers:
3058 try:
3059 self._notify('endTimeChanged', edate)
3060 #for observer in self.getObservers():
3061 except Exception, e:
3062 #observer.notifyEventDateChanges(None, None, edate, self.endDate)
3063 try:
3064 Logger.get('Conference').error("Exception while notifying the observer of a end timet change from %s to %s for conference %s: %s" %
3065 (formatDateTime(edate), formatDateTime(self.endDate), self.getId(), str(e)))
3066 except Exception, e2:
3067 Logger.get('Conference').error("Exception while notifying a end time change: %s (origin: %s)"%(str(e2), str(e)))
3069 def getEndDate(self):
3070 """returns (datetime) the ending date of the conference"""
3071 return self.endDate
3073 ##################################
3074 # Fermi timezone awareness #
3075 ##################################
3077 def getAdjustedEndDate(self,tz=None):
3078 if not tz:
3079 tz = self.getTimezone()
3080 if tz not in all_timezones:
3081 tz = 'UTC'
3082 return self.getEndDate().astimezone(timezone(tz))
3084 ##################################
3085 # Fermi timezone awareness(end) #
3086 ##################################
3088 def setScreenEndDate(self, date):
3089 if date == self.getEndDate():
3090 date = None
3091 self._screenEndDate = date
3092 self.notifyModification()
3094 def getScreenEndDate(self):
3095 try:
3096 date = self._screenEndDate
3097 except:
3098 date = self._screenEndDate = None
3099 if date != None:
3100 return date
3101 else:
3102 return self.getEndDate()
3104 def getAdjustedScreenEndDate(self, tz=None):
3105 if not tz:
3106 tz = self.getTimezone()
3107 return self.getScreenEndDate().astimezone(timezone(tz))
3109 def isEndDateAutoCal( self ):
3110 """Says whether the end date has been explicitely set for the session
3111 or it must be calculated automatically
3113 return self._endDateAutoCal
3115 ####################################
3116 # Fermi timezone awareness #
3117 ####################################
3118 def setTimezone(self, tz):
3119 try:
3120 oldTimezone = self.timezone
3121 except AttributeError:
3122 oldTimezone = tz
3123 self.timezone = tz
3124 #for observer in self.getObservers():
3125 try:
3126 #observer.notifyTimezoneChange(oldTimezone, tz)
3127 self._notify('timezoneChanged', oldTimezone)
3128 except Exception, e:
3129 try:
3130 Logger.get('Conference').error("Exception while notifying the observer of a timezone change from %s to %s for conference %s: %s" %
3131 (str(oldTimezone), str(tz), self.getId(), str(e)))
3132 except Exception, e2:
3133 Logger.get('Conference').error("Exception while notifying a timezone change: %s (origin: %s)"%(str(e2), str(e)))
3135 def getTimezone(self):
3136 try:
3137 return self.timezone
3138 except:
3139 return 'UTC'
3141 def moveToTimezone(self, tz):
3142 if self.getTimezone() == tz:
3143 return
3144 sd=self.getAdjustedStartDate()
3145 ed=self.getAdjustedEndDate()
3146 self.setTimezone(tz)
3147 try:
3148 sDate = timezone(tz).localize(datetime(sd.year, \
3149 sd.month, \
3150 sd.day, \
3151 sd.hour, \
3152 sd.minute))
3153 eDate = timezone(tz).localize(datetime(ed.year, \
3154 ed.month, \
3155 ed.day, \
3156 ed.hour, \
3157 ed.minute))
3158 except ValueError,e:
3159 raise MaKaCError("Error moving the timezone: %s"%e)
3160 self.setDates( sDate.astimezone(timezone('UTC')), \
3161 eDate.astimezone(timezone('UTC')),
3162 moveEntries=1)
3166 ####################################
3167 # Fermi timezone awareness(end) #
3168 ####################################
3170 def getTitle(self):
3171 """returns (String) the title of the conference"""
3172 return self.title
3174 def setTitle(self, title):
3175 """changes the current title of the conference to the one specified"""
3176 oldTitle = self.title
3178 self.title = title
3179 self.cleanCategoryCache()
3180 self.notifyModification()
3182 nameIdx = indexes.IndexesHolder().getIndex('conferenceTitle')
3183 nameIdx.unindex(self.getId())
3184 nameIdx.index(self.getId(), self.getTitle().decode('utf-8'))
3186 #we notify the observers that the conference's title has changed
3187 try:
3188 self._notify('eventTitleChanged', oldTitle, title)
3189 except Exception, e:
3190 Logger.get('Conference').exception("Exception while notifying the observer of a conference title change for conference %s: %s" %
3191 (self.getId(), str(e)))
3194 def getDescription(self):
3195 """returns (String) the description of the conference"""
3196 return self.description
3198 def setDescription(self, desc):
3199 """changes the current description of the conference"""
3200 oldDescription = self.description
3201 self.description = desc
3202 self._notify('eventDescriptionChanged', oldDescription, desc)
3203 self.notifyModification()
3205 def getSupportInfo(self):
3206 if not hasattr(self, "_supportInfo"):
3207 self._supportInfo = SupportInfo(self, "Support")
3208 return self._supportInfo
3210 def setSupportInfo(self, supportInfo):
3211 self._supportInfo = supportInfo
3213 def getChairmanText( self ):
3214 try:
3215 if self.chairmanText:
3216 pass
3217 except AttributeError, e:
3218 self.chairmanText = ""
3219 return self.chairmanText
3221 def setChairmanText( self, newText ):
3222 self.chairmanText = newText.strip()
3224 def appendChairmanText( self, newText ):
3225 self.setChairmanText( "%s, %s"%(self.getChairmanText(), newText.strip()) )
3226 self._chairGen=Counter()
3227 self._chairs=[]
3229 def _resetChairs(self):
3230 try:
3231 if self._chairs:
3232 return
3233 except AttributeError:
3234 self._chairs=[]
3235 for oc in self.chairmans:
3236 newChair=ConferenceChair()
3237 newChair.setDataFromAvatar(oc)
3238 self._addChair(newChair)
3240 def getChairList(self):
3241 """Method returning a list of the conference chairmans (Avatars)
3243 self._resetChairs()
3244 return self._chairs
3246 def _addChair(self,newChair):
3247 for chair in self._chairs:
3248 if newChair.getEmail() != "" and newChair.getEmail() == chair.getEmail():
3249 return
3250 try:
3251 if self._chairGen:
3252 pass
3253 except AttributeError:
3254 self._chairGen=Counter()
3255 id = newChair.getId()
3256 if id == "":
3257 id=int(self._chairGen.newCount())
3258 if isinstance(newChair,ConferenceChair):
3259 newChair.includeInConference(self,id)
3260 self._chairs.append(newChair)
3261 if isinstance(newChair, MaKaC.user.Avatar):
3262 newChair.linkTo(self, "chair")
3263 self.notifyModification()
3265 def addChair(self,newChair):
3266 """includes the specified user in the list of conference
3267 chairs"""
3268 self._resetChairs()
3269 self._addChair(newChair)
3271 def removeChair(self,chair):
3272 """removes the specified user from the list of conference
3273 chairs"""
3274 self._resetChairs()
3275 if chair not in self._chairs:
3276 return
3277 self._chairs.remove(chair)
3278 if isinstance(chair, MaKaC.user.Avatar):
3279 chair.unlinkTo(self, "chair")
3280 chair.delete()
3281 self.notifyModification()
3283 def recoverChair(self, ch):
3284 self.addChair(ch)
3285 ch.recover()
3287 def getChairById(self,id):
3288 id=int(id)
3289 for chair in self._chairs:
3290 if chair.getId()==id:
3291 return chair
3292 return None
3294 def getAllSessionsConvenerList(self) :
3295 dictionary = {}
3296 for session in self.getSessionList() :
3297 for convener in session.getConvenerList() :
3298 key = convener.getEmail()+" "+convener.getFirstName().lower()+" "+convener.getFamilyName().lower()
3299 dictionary.setdefault(key, set()).add(convener)
3300 for slot in session.getSlotList():
3301 for convener in slot.getConvenerList() :
3302 key = convener.getEmail()+" "+convener.getFirstName().lower()+" "+convener.getFamilyName().lower()
3303 dictionary.setdefault(key, set()).add(convener)
3305 return dictionary
3307 def getContactInfo(self):
3308 return self.contactInfo
3310 def setContactInfo(self, contactInfo):
3311 self.contactInfo = contactInfo
3312 self.notifyModification()
3314 def getLocationParent( self ):
3316 Returns the object from which the room/location
3317 information should be inherited.
3318 For Conferences, it's None, since they can't inherit
3319 from anywhere else.
3321 return None
3323 def getLocation( self ):
3324 return self.getOwnLocation()
3326 def getAddress( self ):
3327 if self.getOwnLocation():
3328 return self.getOwnLocation().getAddress()
3329 else:
3330 return None
3332 def getRoom( self ):
3333 return self.getOwnRoom()
3335 def getLocationList(self):
3336 """Method returning a list of "location" objects which contain the
3337 information about the different places the conference is gonna
3338 happen
3340 return self.places
3342 def getFavoriteRooms(self):
3343 roomList = []
3344 roomList.extend(self.getRoomList())
3345 #roomList.extend(map(lambda x: x._getName(), self.getBookedRooms()))
3347 return roomList
3349 def addLocation(self, newPlace):
3350 self.places.append( newPlace )
3351 self.notifyModification()
3353 def setAccessKey(self, accessKey=""):
3354 """sets the access key of the conference"""
3355 self._accessKey = accessKey
3356 self.notifyModification()
3358 def getAccessKey(self):
3359 try:
3360 return self._accessKey
3361 except AttributeError:
3362 self._accessKey = ""
3363 return self._accessKey
3365 def setModifKey(self, modifKey=""):
3366 """sets the modification key of the conference"""
3367 self._modifKey = modifKey
3368 self.notifyModification()
3370 def getModifKey(self):
3371 try:
3372 return self._modifKey
3373 except AttributeError:
3374 self._modifKey = ""
3375 return self._modifKey
3377 def __generateNewSessionId( self ):
3378 """Returns a new unique identifier for the current conference sessions
3380 return str(self.__sessionGenerator.newCount())
3382 def addSession(self,newSession, check = 2, id = None):
3383 """Adds a new session object to the conference taking care of assigning
3384 a new unique id to it
3386 """check parameter:
3387 0: no check at all
3388 1: check and raise error in case of problem
3389 2: check and adapt the owner dates"""
3391 if self.hasSession(newSession):
3392 return
3393 if self.getSchedule().isOutside(newSession):
3394 if check == 1:
3395 MaKaCError( _("Cannot add this session (Start:%s - End:%s) Outside of the event's time table(Start:%s - End:%s)") % (newSession.getStartDate(),newSession.getEndDate(),self.getSchedule().getStartDate(), self.getSchedule().getEndDate()),"Event")
3396 elif check == 2:
3397 if self.getSchedule().getStartDate() > newSession.getStartDate():
3398 self.setStartDate(newSession.getStartDate())
3399 if self.getSchedule().getEndDate() < newSession.getEndDate():
3400 self.setEndDate(newSession.getEndDate())
3401 if id!=None:
3402 sessionId = id
3403 else:
3404 sessionId=self.__generateNewSessionId()
3405 self.sessions[sessionId]=newSession
3406 newSession.includeInConference(self,sessionId)
3407 #keep the session coordinator index updated
3408 for sc in newSession.getCoordinatorList():
3409 self.addSessionCoordinator(newSession,sc)
3410 self.notifyModification()
3412 def hasSession(self,session):
3413 if session != None and session.getConference()==self and \
3414 self.sessions.has_key(session.getId()):
3415 return True
3416 return False
3418 def removeSession(self,session, deleteContributions=False):
3419 if self.hasSession(session):
3420 for sc in session.getCoordinatorList():
3421 self.removeSessionCoordinator(session,sc)
3423 if deleteContributions:
3424 for contrib in session.getContributionList():
3425 contrib.delete()
3427 del self.sessions[session.getId()]
3429 session.delete()
3430 self.notifyModification()
3432 def recoverSession(self, session, check, isCancelled):
3433 self.addSession(session, check, session.getId())
3434 session.recover(isCancelled)
3436 def getSessionById( self, sessionId ):
3437 """Returns the session from the conference list corresponding to the
3438 unique session id specified
3440 return self.sessions.get(sessionId,None)
3442 def getRoomList(self):
3443 roomList =[]
3444 for session in self.sessions.values():
3445 if session.getRoom()!=None:
3446 roomname = session.getRoom().getName()
3447 if roomname not in roomList:
3448 roomList.append(roomname)
3449 return roomList
3451 def getSessionList( self ):
3452 """Retruns a list of the conference session objects
3454 return self.sessions.values()
3456 def getSessionListSorted( self ):
3457 """Retruns a sorted list of the conference sessions
3459 res=[]
3460 for entry in self.getSchedule().getEntries():
3461 if isinstance(entry,LinkedTimeSchEntry) and \
3462 isinstance(entry.getOwner(),SessionSlot):
3463 session=entry.getOwner().getSession()
3464 if session not in res:
3465 res.append(session)
3466 return res
3468 def getNumberOfSessions( self ):
3469 return len(self.sessions)
3471 def _generateNewContributionId( self ):
3472 """Returns a new unique identifier for the current conference
3473 contributions
3475 return str(self.__contribGenerator.newCount())
3477 def genNewAbstractId(self):
3478 return str(self.__contribGenerator.newCount())
3480 def syncContribCounter(self):
3481 self.__contribGenerator.sync(self.getAbstractMgr()._getOldAbstractCounter())
3482 return self.__contribGenerator._getCount()
3484 def addContribution(self,newContrib,id=""):
3485 """Adds a new contribution object to the conference taking care of
3486 assigning a new unique id to it
3488 if self.hasContribution(newContrib):
3489 return
3490 if isinstance(newContrib.getCurrentStatus(),ContribStatusWithdrawn):
3491 raise MaKaCError( _("Cannot add a contribution which has been withdrawn"), _("Event"))
3492 if id is None or id=="":
3493 contribId=self._generateNewContributionId()
3494 while self.contributions.has_key(contribId):
3495 contribId=self._generateNewContributionId()
3496 else:
3497 contribId=str(id)
3498 if self.contributions.has_key(contribId):
3499 raise MaKaCError( _("Cannot add this contribution id:(%s) as it has already been used")%contribId, _("Event"))
3500 newContrib.includeInConference(self,contribId)
3501 self.contributions[contribId]=newContrib
3502 for auth in newContrib.getAuthorList():
3503 self.indexAuthor(auth)
3504 for spk in newContrib.getSpeakerList():
3505 self.indexSpeaker(spk)
3506 for sub in newContrib.getSubmitterList():
3507 self.addContribSubmitter(newContrib,sub)
3509 newContrib._notify('created', self)
3510 self.notifyModification()
3512 def hasContribution(self,contrib):
3513 return contrib.getConference()==self and \
3514 self.contributions.has_key(contrib.getId())
3516 def removeContribution( self, contrib, callDelete=True ):
3517 if not self.contributions.has_key( contrib.getId() ):
3518 return
3519 for sub in contrib.getSubmitterList()[:]:
3520 self.removeContribSubmitter(contrib,sub)
3521 for auth in contrib.getPrimaryAuthorList()[:]:
3522 contrib.removePrimaryAuthor(auth)
3523 for auth in contrib.getCoAuthorList()[:]:
3524 contrib.removeCoAuthor(auth)
3525 for spk in contrib.getSpeakerList()[:]:
3526 contrib.removeSpeaker(spk)
3527 del self.contributions[ contrib.getId() ]
3528 if callDelete:
3529 contrib.delete()
3530 #else:
3531 # contrib.unindex()
3532 self.notifyModification()
3534 def recoverContribution(self, contrib):
3535 self.addContribution(contrib, contrib.getId())
3536 contrib.recover()
3538 # Note: this kind of factories should never be used as they only allow to
3539 # create a single type of contributions
3540 def newContribution( self, id=None ):
3541 """Creates and returns a new contribution object already added to the
3542 conference list (all its data is set to the default)
3544 c = Contribution()
3545 self.addContribution( c, id )
3546 return c
3548 def getOwnContributionById( self, id ):
3549 """Returns the contribution from the conference list corresponding to
3550 the unique contribution id specified
3552 if self.contributions.has_key( id ):
3553 return self.contributions[ id ]
3554 return None
3556 def getContributionById( self, id ):
3557 """Returns the contribution corresponding to the id specified
3559 return self.contributions.get(str(id).strip(),None)
3561 def getContributionList(self):
3562 """Returns a list of the conference contribution objects
3564 return self.contributions.values()
3566 def iterContributions(self):
3567 return self.contributions.itervalues()
3569 def getContributionListWithoutSessions(self):
3570 """Returns a list of the conference contribution objects which do not have a session
3572 return [c for c in self.contributions.values() if not c.getSession()]
3575 def getContributionListSorted(self, includeWithdrawn=True, key="id"):
3576 """Returns a list of the conference contribution objects, sorted by key provided
3578 contributions = self.contributions.values()
3579 if not includeWithdrawn:
3580 contributions = filter(lambda c: not isinstance(c.getCurrentStatus(), ContribStatusWithdrawn), contributions)
3581 contributions.sort(key = lambda c: getattr(c, key))
3582 return contributions
3584 def getNumberOfContributions(self, only_scheduled=False):
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
3712 # if event is inheriting, check IP protection above
3713 if self.getAccessProtectionLevel() == 0:
3714 for owner in self.getOwnerList():
3715 if not owner.canIPAccess(ip):
3716 return False
3718 return True
3720 def requireDomain( self, dom ):
3721 self.__ac.requireDomain( dom )
3722 self._notify('accessDomainAdded', dom)
3724 def freeDomain( self, dom ):
3725 self.__ac.freeDomain( dom )
3726 self._notify('accessDomainRemoved', dom)
3728 def getDomainList( self ):
3729 return self.__ac.getRequiredDomainList()
3731 def isProtected( self ):
3732 """Tells whether a conference is protected for accessing or not
3734 return self.__ac.isProtected()
3736 def getAccessProtectionLevel( self ):
3737 return self.__ac.getAccessProtectionLevel()
3739 def isItselfProtected( self ):
3740 return self.__ac.isItselfProtected()
3742 def hasAnyProtection( self ):
3743 """Tells whether a conference has any kind of protection over it:
3744 access or domain protection.
3746 if self.isProtected():
3747 return True
3748 if self.getDomainList():
3749 return True
3751 if self.getAccessProtectionLevel() == -1:
3752 return False
3754 for owner in self.getOwnerList():
3755 if owner.hasAnyProtection():
3756 return True
3758 return False
3760 def hasProtectedOwner( self ):
3761 return self.__ac._getFatherProtection()
3763 def setProtection( self, private ):
3765 Allows to change the conference access protection
3768 oldValue = 1 if self.isProtected() else -1
3770 self.getAccessController().setProtection( private )
3771 self.cleanCategoryCache()
3773 if oldValue != private:
3774 # notify listeners
3775 self._notify('protectionChanged', oldValue, private)
3777 def grantAccess( self, prin ):
3778 self.__ac.grantAccess( prin )
3779 if isinstance(prin, MaKaC.user.Avatar):
3780 prin.linkTo(self, "access")
3782 def revokeAccess( self, prin ):
3783 self.__ac.revokeAccess( prin )
3784 if isinstance(prin, MaKaC.user.Avatar):
3785 prin.unlinkTo(self, "access")
3787 def canView( self, aw ):
3788 """tells whether the specified access wrappers has access to the current
3789 object or any of its parts"""
3790 if self.canAccess( aw ):
3791 return True
3792 for session in self.getSessionList():
3793 if session.canView( aw ):
3794 return True
3795 for contrib in self.getContributionList():
3796 if contrib.canView( aw ):
3797 return True
3798 return False
3800 def isAllowedToAccess( self, av):
3801 """tells if a user has privileges to access the current conference
3802 (independently that it is protected or not)
3804 if not av:
3805 return False
3806 if (av in self.getChairList()) or (self.__ac.canUserAccess( av )) or (self.canUserModify( av )):
3807 return True
3809 # if the conference is not protected by itself
3810 if not self.isItselfProtected():
3811 # then inherit behavior from parent category
3812 for owner in self.getOwnerList():
3813 if owner.isAllowedToAccess( av ):
3814 return True
3816 # track coordinators are also allowed to access the conference
3817 for track in self.getTrackList():
3818 if track.isCoordinator( av ):
3819 return True
3821 # paper reviewing team should be also allowed to access
3822 if self.getConfPaperReview().isInReviewingTeam(av):
3823 return True
3825 # video services managers are also allowed to access the conference
3826 if PluginsHolder().hasPluginType("Collaboration"):
3827 if self.getCSBookingManager().isPluginManagerOfAnyPlugin(av):
3828 return True
3829 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
3830 if RCCollaborationAdmin.hasRights(user=av) or \
3831 RCCollaborationPluginAdmin.hasRights(user=av, plugins ='any'):
3832 return True
3834 return False
3836 def canAccess( self, aw ):
3837 """Tells whether an access wrapper is allowed to access the current
3838 conference: when the conference is protected, only if the user is a
3839 chair or is granted to access the conference, when the client ip is
3840 not restricted.
3842 # Allow harvesters (Invenio, offline cache) to access
3843 # protected pages
3844 if self.__ac.isHarvesterIP(aw.getIP()):
3845 return True
3847 # Managers have always access
3848 if self.canUserModify(aw.getUser()):
3849 return True
3851 if self.isProtected():
3852 if self.isAllowedToAccess( aw.getUser() ):
3853 return True
3854 else:
3855 return self.canKeyAccess(aw)
3856 else:
3857 # Domain control is triggered just for PUBLIC events
3858 return self.canIPAccess(aw.getIP())
3860 def canKeyAccess( self, aw, key=None ):
3861 sess = aw.getSession()
3862 accessKey = self.getAccessKey()
3863 if accessKey != "" and sess:
3864 if key and key == accessKey:
3865 return True
3866 keys = sess.getVar("accessKeys")
3867 if keys != None:
3868 if keys.has_key(self.getUniqueId()):
3869 if keys[self.getUniqueId()] == accessKey:
3870 return True
3871 return False
3873 def canKeyModify( self, aw ):
3874 sess = aw.getSession()
3875 modifKey = self.getModifKey()
3876 if modifKey != "" and sess:
3877 keys = sess.getVar("modifKeys")
3878 if keys != None:
3879 if keys.has_key(self.id):
3880 if keys[self.id] == modifKey:
3881 return True
3882 return False
3884 def grantModification( self, prin, sendEmail=True ):
3885 email = None
3886 if isinstance(prin, ConferenceChair):
3887 email = prin.getEmail()
3888 elif isinstance(prin, str):
3889 email = prin
3890 if email != None:
3891 if email == "":
3892 return
3893 ah = AvatarHolder()
3894 results=ah.match({"email":email}, exact=1)
3895 #No registered user in Indico with that email
3896 if len(results) == 0:
3897 self.__ac.grantModificationEmail(email)
3898 if sendEmail and isinstance(prin, ConferenceChair):
3899 notif = pendingQueues._PendingConfManagerNotification( [prin] )
3900 mail.GenericMailer.sendAndLog( notif, self.getConference() )
3901 #The user is registered in Indico and is activated as well
3902 elif len(results) == 1 and results[0] is not None and results[0].isActivated():
3903 self.__ac.grantModification(results[0])
3904 results[0].linkTo(self, "manager")
3905 else:
3906 self.__ac.grantModification( prin )
3907 if isinstance(prin, MaKaC.user.Avatar):
3908 prin.linkTo(self, "manager")
3910 def revokeModification( self, prin ):
3911 self.__ac.revokeModification( prin )
3912 if isinstance(prin, MaKaC.user.Avatar):
3913 prin.unlinkTo(self, "manager")
3915 def canUserModify( self, av ):
3916 if av == None:
3917 return False
3918 if ( av == self.getCreator()) or self.getAccessController().canModify( av ):
3919 return True
3920 for owner in self.getOwnerList():
3921 if owner.canUserModify( av ):
3922 return True
3923 return False
3925 def canModify( self, aw ):
3926 """Tells whether an access wrapper is allowed to modify the current
3927 conference: only if the user is granted to modify the conference and
3928 he is accessing from an IP address which is not restricted.
3930 return self.canUserModify( aw.getUser() ) or self.canKeyModify( aw )
3932 def getManagerList( self ):
3933 return self.__ac.getModifierList()
3935 def addToRegistrars(self, av):
3936 self.getRegistrarList().append(av)
3937 self.notifyModification()
3938 if isinstance(av, MaKaC.user.Avatar):
3939 av.linkTo(self, "registrar")
3941 def removeFromRegistrars(self, av):
3942 self.getRegistrarList().remove(av)
3943 self.notifyModification()
3944 if isinstance(av, MaKaC.user.Avatar):
3945 av.unlinkTo(self, "registrar")
3947 def isRegistrar(self, av):
3948 if av == None:
3949 return False
3950 try:
3951 return av in self.getRegistrarList()
3952 except AttributeError:
3953 return False
3955 def getRegistrarList(self):
3956 try:
3957 return self.__registrars
3958 except AttributeError:
3959 self.__registrars = []
3960 return self.__registrars
3962 def canManageRegistration(self, av):
3963 return self.isRegistrar(av) or self.canUserModify(av)
3965 def getAllowedToAccessList( self ):
3966 return self.__ac.getAccessList()
3968 def addMaterial( self, newMat ):
3969 newMat.setId( str(self.__materialGenerator.newCount()) )
3970 newMat.setOwner( self )
3971 self.materials[ newMat.getId() ] = newMat
3972 self.notifyModification()
3974 def removeMaterial( self, mat ):
3975 if mat.getId() in self.materials.keys():
3976 mat.delete()
3977 self.materials[mat.getId()].setOwner(None)
3978 del self.materials[ mat.getId() ]
3979 self.notifyModification()
3980 elif mat.getId().lower() == 'paper':
3981 self.removePaper()
3982 self.notifyModification()
3983 elif mat.getId().lower() == 'slides':
3984 self.removeSlides()
3985 self.notifyModification()
3986 elif mat.getId().lower() == 'minutes':
3987 self.removeMinutes()
3988 self.notifyModification()
3989 elif mat.getId().lower() == 'video':
3990 self.removeVideo()
3991 self.notifyModification()
3992 elif mat.getId().lower() == 'poster':
3993 self.removePoster()
3994 self.notifyModification()
3996 def recoverMaterial(self, recMat):
3997 # Id must already be set in recMat.
3998 recMat.setOwner(self)
3999 self.materials[recMat.getId()] = recMat
4000 recMat.recover()
4001 self.notifyModification()
4003 def getMaterialRegistry(self):
4005 Return the correct material registry for this type
4007 from MaKaC.webinterface.materialFactories import ConfMFRegistry
4008 return ConfMFRegistry
4010 def getMaterialById( self, matId ):
4011 if matId.lower() == 'paper':
4012 return self.getPaper()
4013 elif matId.lower() == 'slides':
4014 return self.getSlides()
4015 elif matId.lower() == 'video':
4016 return self.getVideo()
4017 elif matId.lower() == 'poster':
4018 return self.getPoster()
4019 elif matId.lower() == 'minutes':
4020 return self.getMinutes()
4021 elif self.materials.has_key(matId):
4022 return self.materials[ matId ]
4023 return None
4025 def getMaterialList( self ):
4026 return self.materials.values()
4028 def getAllMaterialList(self, sort=True):
4029 l = self.getMaterialList()
4030 if self.getPaper():
4031 l.append( self.getPaper() )
4032 if self.getSlides():
4033 l.append( self.getSlides() )
4034 if self.getVideo():
4035 l.append( self.getVideo() )
4036 if self.getPoster():
4037 l.append( self.getPoster() )
4038 if self.getMinutes():
4039 l.append( self.getMinutes() )
4040 if sort:
4041 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
4042 return l
4044 def _getMaterialFiles(self, material):
4046 Adaption of _getMaterialFiles in WPTPLConferenceDisplay for desired format, objects
4047 seemed mutually exclusive hence use of similar logic here specific to Conference.
4049 files = []
4050 processed = []
4052 for res in material.getResourceList():
4053 try:
4054 ftype = res.getFileType()
4055 fname = res.getFileName()
4056 furl = urlHandlers.UHFileAccess.getURL(res)
4058 if fname in processed:
4059 fname = "%s - %s" % (fname, processed.count(fname))
4061 processed.append(res.getFileName())
4062 except:
4063 # If we are here then the resource is a Link object.
4064 fname, ftype, furl = str(res.getURL()), "link", str(res.getURL())
4065 fdesc = res.getDescription()
4066 files.append({'title': fname,
4067 'description': fdesc,
4068 'type': ftype,
4069 'url': furl})
4070 return files
4072 def getAllMaterialDict(self, child=None):
4074 This method iterates through the children of the conference, creating
4075 a dictionary which maps type to material link URLs.
4078 child = self if child is None else child
4080 node = {}
4081 node['title'] = child.getTitle()
4083 try:
4084 node['type'] = child.getType()
4085 except:
4086 # If we land here, it's a session which doesn't have 'getType'
4087 node['type'] = 'session'
4089 node['children'] = []
4090 node['material'] = []
4092 if node['type'] in ['conference', 'meeting']:
4093 for session in child.getSessionList():
4094 node['children'].append(self.getAllMaterialDict(session))
4096 for contrib in child.getContributionList():
4097 node['children'].append(self.getAllMaterialDict(contrib))
4099 for material in child.getAllMaterialList():
4100 files = self._getMaterialFiles(material)
4102 for f in files:
4103 materialNode = {}
4104 materialNode['type'] = 'material'
4105 materialNode['title'] = material.getTitle()
4107 if material.getTitle() != 'Minutes':
4108 materialNode['title'] += ' - ' + f['title']
4110 materialNode['materialType'] = f['type']
4111 materialNode['url'] = str(f['url'])
4113 node['material'].append(materialNode)
4115 return node
4117 def setPaper( self, newPaper ):
4118 if self.getPaper() != None:
4119 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
4120 self.paper=newPaper
4121 self.paper.setOwner( self )
4122 self.notifyModification()
4124 def removePaper( self ):
4125 if self.paper is None:
4126 return
4127 self.paper.delete()
4128 self.paper.setOwner(None)
4129 self.paper = None
4130 self.notifyModification()
4132 def recoverPaper(self, p):
4133 self.setPaper(p)
4134 p.recover()
4136 def getPaper( self ):
4137 try:
4138 if self.paper:
4139 pass
4140 except AttributeError:
4141 self.paper = None
4142 return self.paper
4144 def setSlides( self, newSlides ):
4145 if self.getSlides() != None:
4146 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
4147 self.slides=newSlides
4148 self.slides.setOwner( self )
4149 self.notifyModification()
4151 def removeSlides( self ):
4152 if self.slides is None:
4153 return
4154 self.slides.delete()
4155 self.slides.setOwner( None )
4156 self.slides= None
4157 self.notifyModification()
4159 def recoverSlides(self, s):
4160 self.setSlides(s)
4161 s.recover()
4163 def getSlides( self ):
4164 try:
4165 if self.slides:
4166 pass
4167 except AttributeError:
4168 self.slides = None
4169 return self.slides
4171 def setVideo( self, newVideo ):
4172 if self.getVideo() != None:
4173 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
4174 self.video=newVideo
4175 self.video.setOwner( self )
4176 self.notifyModification()
4178 def removeVideo( self ):
4179 if self.getVideo() is None:
4180 return
4181 self.video.delete()
4182 self.video.setOwner(None)
4183 self.video = None
4184 self.notifyModification()
4186 def recoverVideo(self, v):
4187 self.setVideo(v)
4188 v.recover()
4190 def getVideo( self ):
4191 try:
4192 if self.video:
4193 pass
4194 except AttributeError:
4195 self.video = None
4196 return self.video
4198 def setPoster( self, newPoster ):
4199 if self.getPoster() != None:
4200 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
4201 self.poster=newPoster
4202 self.poster.setOwner( self )
4203 self.notifyModification()
4205 def removePoster( self ):
4206 if self.getPoster() is None:
4207 return
4208 self.poster.delete()
4209 self.poster.setOwner(None)
4210 self.poster = None
4211 self.notifyModification()
4213 def recoverPoster(self, p):
4214 self.setPoster(p)
4215 p.recover()
4217 def getPoster( self ):
4218 try:
4219 if self.poster:
4220 pass
4221 except AttributeError:
4222 self.poster = None
4223 return self.poster
4225 def setMinutes( self, newMinutes ):
4226 if self.getMinutes() != None:
4227 raise MaKaCError( _("The Minutes for this conference has already been set"))
4228 self.minutes=newMinutes
4229 self.minutes.setOwner( self )
4230 self.notifyModification()
4232 def createMinutes( self ):
4233 if self.getMinutes() != None:
4234 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
4235 self.minutes = Minutes()
4236 self.minutes.setOwner( self )
4237 self.notifyModification()
4238 return self.minutes
4240 def removeMinutes( self ):
4241 if self.getMinutes() is None:
4242 return
4243 self.minutes.delete()
4244 self.minutes.setOwner( None )
4245 self.minutes = None
4246 self.notifyModification()
4248 def recoverMinutes(self, min):
4249 self.removeMinutes() # To ensure that the current minutes are put in
4250 # the trash can.
4251 self.minutes = min
4252 self.minutes.setOwner( self )
4253 min.recover()
4254 self.notifyModification()
4255 return self.minutes
4257 def getMinutes( self ):
4258 #To be removed
4259 try:
4260 if self.minutes:
4261 pass
4262 except AttributeError, e:
4263 self.minutes = None
4264 return self.minutes
4266 def _setSchedule( self, sch=None ):
4267 self.__schedule=ConferenceSchedule(self)
4268 for session in self.getSessionList():
4269 for slot in session.getSlotList():
4270 self.__schedule.addEntry(slot.getConfSchEntry())
4272 def getSchedule( self ):
4273 try:
4274 if not self.__schedule:
4275 self._setSchedule()
4276 except AttributeError, e:
4277 self._setSchedule()
4278 return self.__schedule
4280 def fit( self ):
4281 sch = self.getSchedule()
4283 sDate = sch.calculateStartDate()
4284 eDate = sch.calculateEndDate()
4285 self.setStartDate(sDate)
4286 self.setEndDate(eDate)
4288 def fitSlotsOnDay( self, day ):
4289 for entry in self.getSchedule().getEntriesOnDay(day) :
4290 if isinstance(entry.getOwner(), SessionSlot) :
4291 entry.getOwner().fit()
4293 def getDisplayMgr(self):
4295 Return the display manager for the conference
4297 from MaKaC.webinterface import displayMgr
4298 return displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self)
4300 def getDefaultStyle( self ):
4301 return self.getDisplayMgr().getDefaultStyle()
4303 def clone( self, startDate, options, eventManager=None, userPerformingClone = None ):
4304 # startDate must be in the timezone of the event (to avoid problems with daylight-saving times)
4305 cat = self.getOwnerList()[0]
4306 managing = options.get("managing",None)
4307 if managing is not None:
4308 creator = managing
4309 else:
4310 creator = self.getCreator()
4311 conf = cat.newConference(creator)
4312 if managing is not None :
4313 conf.grantModification(managing)
4314 conf.setTitle(self.getTitle())
4315 conf.setDescription(self.getDescription())
4316 conf.setTimezone(self.getTimezone())
4317 for loc in self.getLocationList():
4318 if loc is not None:
4319 conf.addLocation(loc.clone())
4320 if self.getRoom() is not None:
4321 conf.setRoom(self.getRoom().clone())
4322 startDate = timezone(self.getTimezone()).localize(startDate).astimezone(timezone('UTC'))
4323 timeDelta = startDate - self.getStartDate()
4324 endDate = self.getEndDate() + timeDelta
4325 conf.setDates( startDate, endDate, moveEntries=1 )
4326 conf.setContactInfo(self.getContactInfo())
4327 conf.setChairmanText(self.getChairmanText())
4328 conf.setVisibility(self.getVisibility())
4329 conf.setSupportInfo(self.getSupportInfo().clone(self))
4330 conf.setReportNumberHolder(self.getReportNumberHolder().clone(self))
4331 for ch in self.getChairList():
4332 conf.addChair(ch.clone())
4333 ContextManager.setdefault("clone.unique_id_map", {})[self.getUniqueId()] = conf.getUniqueId()
4334 # Display Manager
4335 from MaKaC.webinterface import displayMgr
4336 selfDispMgr=displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self)
4337 selfDispMgr.clone(conf)
4338 # Contribution Types' List (main detailes of the conference)
4339 for t in self.getContribTypeList() :
4340 conf.addContribType(t.clone(conf))
4341 for item in self.getSections() :
4342 conf._sections.append(item)
4343 if options.get("sessions", False):
4344 for entry in self.getSchedule().getEntries():
4345 if isinstance(entry,BreakTimeSchEntry):
4346 conf.getSchedule().addEntry(entry.clone(conf))
4347 db_root = DBMgr.getInstance().getDBConnection().root()
4348 if db_root.has_key( "webfactoryregistry" ):
4349 confRegistry = db_root["webfactoryregistry"]
4350 else:
4351 confRegistry = OOBTree.OOBTree()
4352 db_root["webfactoryregistry"] = confRegistry
4353 meeting=False
4354 # if the event is a meeting or a lecture
4355 if confRegistry.get(str(self.getId()), None) is not None :
4356 meeting=True
4357 confRegistry[str(conf.getId())] = confRegistry[str(self.getId())]
4358 # if it's a conference, no web factory is needed
4359 # Tracks in a conference
4360 if options.get("tracks",False) :
4361 for tr in self.getTrackList() :
4362 conf.addTrack(tr.clone(conf))
4363 # Meetings' and conferences' sessions cloning
4364 if options.get("sessions",False) :
4365 for s in self.getSessionList() :
4366 newSes = s.clone(timeDelta, conf, options)
4367 ContextManager.setdefault("clone.unique_id_map", {})[s.getUniqueId()] = newSes.getUniqueId()
4368 conf.addSession(newSes)
4369 # Materials' cloning
4370 if options.get("materials",False) :
4371 for m in self.getMaterialList() :
4372 conf.addMaterial(m.clone(conf))
4373 if self.getPaper() is not None:
4374 conf.setPaper(self.getPaper().clone(conf))
4375 if self.getSlides() is not None:
4376 conf.setSlides(self.getSlides().clone(conf))
4377 if self.getVideo() is not None:
4378 conf.setVideo(self.getVideo().clone(conf))
4379 if self.getPoster() is not None:
4380 conf.setPoster(self.getPoster().clone(conf))
4381 if self.getMinutes() is not None:
4382 conf.setMinutes(self.getMinutes().clone(conf))
4383 # access and modification keys
4384 if options.get("keys", False) :
4385 conf.setAccessKey(self.getAccessKey())
4386 conf.setModifKey(self.getModifKey())
4387 # Access Control cloning
4388 if options.get("access",False) :
4389 conf.setProtection(self.getAccessController()._getAccessProtection())
4390 for mgr in self.getManagerList() :
4391 conf.grantModification(mgr)
4392 for user in self.getAllowedToAccessList() :
4393 conf.grantAccess(user)
4394 for right in self.getSessionCoordinatorRights():
4395 conf.addSessionCoordinatorRight(right)
4396 for domain in self.getDomainList():
4397 conf.requireDomain(domain)
4398 # conference's registration form
4399 if options.get("registration",False) :
4400 conf.setRegistrationForm(self.getRegistrationForm().clone(conf))
4402 # conference's evaluation
4403 if options.get("evaluation",False) :
4404 #Modify this, if you have now many evaluations.
4405 #You will have to clone every evaluations of this conference.
4406 conf.setEvaluations([self.getEvaluation().clone(conf)])
4408 #conference's abstracts
4409 if options.get("abstracts",False) :
4410 conf.abstractMgr = self.abstractMgr.clone(conf)
4411 # conference's alerts
4412 if options.get("alerts",False) :
4413 for alarm in self.getAlarmList() :
4414 # for absoulte alarms, only clone alarms that will happen in the future
4415 if alarm._relative is not None or alarm.getStartOn() > nowutc():
4416 # .clone takes care of enqueuing it
4417 alarm.clone(conf)
4418 # Meetings' and conferences' contributions cloning
4419 if options.get("contributions",False) :
4420 sch = conf.getSchedule()
4421 for cont in self.getContributionList():
4422 if cont.getSession() is None :
4423 if not meeting:
4424 nc = cont.clone(conf, options, timeDelta)
4425 conf.addContribution(nc)
4426 if cont.isScheduled() :
4427 sch.addEntry(nc.getSchEntry())
4428 ContextManager.setdefault("clone.unique_id_map", {})[cont.getUniqueId()] = nc.getUniqueId()
4429 elif cont.isScheduled():
4430 # meetings...only scheduled
4431 nc = cont.clone(conf, options, timeDelta)
4432 conf.addContribution(nc)
4433 sch.addEntry(nc.getSchEntry())
4434 ContextManager.setdefault("clone.unique_id_map", {})[cont.getUniqueId()] = nc.getUniqueId()
4435 # Participants' module settings and list cloning
4436 if options.get("participants",False) :
4437 self.getParticipation().clone(conf, options, eventManager)
4438 conf.notifyModification()
4440 #we inform the plugins in case they want to add anything to the new conference
4441 self._notify('cloneEvent', {'conf': conf, 'user': userPerformingClone, 'options': options})
4442 return conf
4444 def newAlarm(self, when, enqueue=True):
4446 if type(when) == timedelta:
4447 relative = when
4448 dtStart = None
4449 else:
4450 relative = None
4451 dtStart = when
4453 confRelId = self._getNextAlarmId()
4454 al = tasks.AlarmTask(self, confRelId,
4455 startDateTime=dtStart,
4456 relative=relative)
4458 self.addAlarm(al, enqueue)
4459 return al
4461 def removeAlarm(self, alarm):
4462 confRelId = alarm.getConfRelativeId()
4464 if confRelId in self.alarmList:
4465 del self.alarmList[confRelId]
4466 self._p_changed = 1
4468 tl = Client()
4469 tl.dequeue(alarm)
4470 else:
4471 raise Exception("alarm not in list!")
4473 def _getNextAlarmId(self):
4474 return self.__alarmCounter.newCount()
4476 def addAlarm(self, alarm, enqueue = True):
4477 if enqueue:
4478 tl = Client()
4479 tl.enqueue(alarm)
4481 self.alarmList[alarm.getConfRelativeId()] = alarm
4482 self._p_changed = 1
4484 def recoverAlarm(self, alarm):
4485 self.addAlarm(alarm)
4486 alarm.conf = self
4487 alarm.recover()
4489 def getAlarmList(self):
4490 return self.alarmList.values()
4492 def getAlarmById(self, id):
4493 """For given id returns corresponding Alarm or None if not found."""
4494 return self.alarmList.get(id, None)
4496 def getCoordinatedTracks( self, av ):
4497 """Returns a list with the tracks for which a user is coordinator.
4499 try:
4500 if self._trackCoordinators:
4501 pass
4502 except AttributeError:
4503 self._trackCoordinators = TCIndex()
4504 self.notifyModification()
4505 return self._trackCoordinators.getTracks( av )
4507 def addTrackCoordinator( self, track, av ):
4508 """Makes a user become coordinator for a track.
4510 try:
4511 if self._trackCoordinators:
4512 pass
4513 except AttributeError:
4514 self._trackCoordinators = TCIndex()
4515 self.notifyModification()
4516 if track in self.program:
4517 track.addCoordinator( av )
4518 self._trackCoordinators.indexCoordinator( av, track )
4519 self.notifyModification()
4521 def removeTrackCoordinator( self, track, av ):
4522 """Removes a user as coordinator for a track.
4524 try:
4525 if self._trackCoordinators:
4526 pass
4527 except AttributeError:
4528 self._trackCoordinators = TCIndex()
4529 self.notifyModification()
4530 if track in self.program:
4531 track.removeCoordinator( av )
4532 self._trackCoordinators.unindexCoordinator( av, track )
4533 self.notifyModification()
4535 def _rebuildAuthorIndex(self):
4536 self._authorIdx=AuthorIndex()
4537 for contrib in self.getContributionList():
4538 if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn):
4539 for auth in contrib.getAuthorList():
4540 self._authorIdx.index(auth)
4542 def getAuthorIndex(self):
4543 try:
4544 if self._authorIdx:
4545 pass
4546 except AttributeError:
4547 self._rebuildAuthorIndex()
4548 return self._authorIdx
4550 def indexAuthor(self,auth):
4551 c=auth.getContribution()
4552 if c.isAuthor(auth):
4553 if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4554 self.getAuthorIndex().index(auth)
4555 if c.isPrimaryAuthor(auth):
4556 self._getPrimAuthIndex().index(auth)
4558 def unindexAuthor(self,auth):
4559 c=auth.getContribution()
4560 if c.isAuthor(auth):
4561 self.getAuthorIndex().unindex(auth)
4562 if c.isPrimaryAuthor(auth):
4563 self._getPrimAuthIndex().unindex(auth)
4565 def _rebuildSpeakerIndex(self):
4566 self._speakerIdx=AuthorIndex()
4567 for contrib in self.getContributionList():
4568 if not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn):
4569 for auth in contrib.getSpeakerList():
4570 self._speakerIdx.index(auth)
4571 for subcontrib in contrib.getSubContributionList():
4572 for auth in subcontrib.getSpeakerList():
4573 self._speakerIdx.index(auth)
4575 def getSpeakerIndex(self):
4576 try:
4577 if self._speakerIdx:
4578 pass
4579 except AttributeError:
4580 self._rebuildSpeakerIndex()
4581 return self._speakerIdx
4583 def indexSpeaker(self,auth):
4584 c=auth.getContribution()
4585 if not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4586 self.getSpeakerIndex().index(auth)
4588 def unindexSpeaker(self,auth):
4589 c=auth.getContribution()
4590 if c and not isinstance(c.getCurrentStatus(),ContribStatusWithdrawn):
4591 self.getSpeakerIndex().unindex(auth)
4593 def getRegistrationForm(self):
4594 try:
4595 if self._registrationForm is None:
4596 self._registrationForm = registration.RegistrationForm(self)
4597 except AttributeError,e:
4598 self._registrationForm = registration.RegistrationForm(self)
4599 return self._registrationForm
4601 def setRegistrationForm(self,rf):
4602 self._registrationForm = rf
4603 rf.setConference(self)
4605 def removeRegistrationForm(self):
4606 try:
4607 self._registrationForm.delete()
4608 self._registrationForm.setConference(None)
4609 self._registrationForm = None
4610 except AttributeError:
4611 self._registrationForm = None
4613 def recoverRegistrationForm(self, rf):
4614 self.setRegistrationForm(rf)
4615 rf.recover()
4617 def getEvaluation(self, id=0):
4618 ############################################################################
4619 #For the moment only one evaluation per conference is used. #
4620 #In the future if there are more than one evaluation, modify this function.#
4621 ############################################################################
4622 """ Return the evaluation given by its ID or None if nothing found.
4623 Params:
4624 id -- id of the wanted evaluation
4626 for evaluation in self.getEvaluations():
4627 if str(evaluation.getId()) == str(id) :
4628 return evaluation
4629 if HelperMaKaCInfo.getMaKaCInfoInstance().isDebugActive():
4630 raise Exception(_("Error with id: expected '%s', found '%s'.")%(id, self.getEvaluations()[0].getId()))
4631 else:
4632 return self.getEvaluations()[0]
4634 def getEvaluations(self):
4635 if not hasattr(self, "_evaluations"):
4636 self._evaluations = [Evaluation(self)]
4637 return self._evaluations
4639 def setEvaluations(self, evaluationsList):
4640 self._evaluations = evaluationsList
4641 for evaluation in self._evaluations:
4642 evaluation.setConference(self)
4644 def removeEvaluation(self, evaluation):
4645 """remove the given evaluation from its evaluations."""
4646 evaluations = self.getEvaluations()
4647 if evaluations.count(evaluation)>0:
4648 evaluations.remove(evaluation)
4649 evaluation.removeReferences()
4650 self.notifyModification()
4652 def removeAllEvaluations(self):
4653 for evaluation in self.getEvaluations():
4654 evaluation.removeReferences()
4655 self._evaluations = []
4656 self.notifyModification()
4658 def _getEvaluationCounter(self):
4659 if not hasattr(self, "_evaluationCounter"):
4660 self._evaluationCounter = Counter()
4661 return self._evaluationCounter
4663 ## Videoconference bookings related
4664 def getBookings(self):
4665 try:
4666 if self._bookings:
4667 pass
4668 except AttributeError, e:
4669 self._bookings = {}
4670 self.notifyModification()
4671 return self._bookings
4673 def getBookingsList(self, sort = False):
4674 bl = self.getBookings().values()
4675 if sort:
4676 bl.sort()
4677 return bl
4679 def _getBookingGenerator(self):
4680 try:
4681 return self._bookingGenerator
4682 except AttributeError, e:
4683 self._bookingGenerator = Counter()
4684 return self._bookingGenerator
4686 def getNewBookingId(self):
4687 return str(self._getBookingGenerator().newCount())
4689 def addBooking(self, bp):
4690 if (bp.getId() == ""):
4691 bp.setId(self.getNewBookingId())
4692 self.getBookings()[bp.getId()] = bp
4693 self.notifyModification()
4695 def hasBooking(self,booking):
4696 return booking.getConference()==self and \
4697 self.getBookings().has_key(booking.getId())
4699 def removeBooking(self, booking):
4700 if self.hasBooking(booking):
4701 deletion= booking.deleteBooking()
4702 if deletion[0] != 1:
4703 del self.getBookings()[booking.getId()]
4704 self.notifyModification()
4705 return deletion
4707 def getBookingByType(self, type):
4708 if self.getBookings().has_key(type):
4709 return self.getBookings()[type]
4710 return None
4712 def getBookingById(self, id):
4713 if self.getBookings().has_key(id):
4714 return self.getBookings()[id]
4715 return None
4717 ## End of Videoconference bookings related
4719 def getModPay(self):
4720 try:
4721 if self._modPay is None:
4722 self._modPay= epayment.EPayment(self)
4723 except AttributeError,e:
4724 self._modPay= epayment.EPayment(self)
4725 return self._modPay
4727 def getRegistrants(self):
4728 try:
4729 if self._registrants:
4730 pass
4731 except AttributeError, e:
4732 self._registrants = {}
4733 self.notifyModification()
4734 return self._registrants
4736 def getRegistrantsByEmail(self):
4737 try:
4738 if self._registrantsByEmail:
4739 pass
4740 except AttributeError, e:
4741 self._registrantsByEmail = self._createRegistrantsByEmail()
4742 self.notifyModification()
4743 return self._registrantsByEmail
4745 def _createRegistrantsByEmail(self):
4746 dicByEmail = {}
4747 for r in self.getRegistrantsList():
4748 dicByEmail[r.getEmail()] = r
4749 return dicByEmail
4751 def getRegistrantsList(self, sort = False):
4752 rl = self.getRegistrants().values()
4753 if sort:
4754 rl.sort(registration.Registrant._cmpFamilyName)
4755 return rl
4757 def _getRegistrantGenerator(self):
4758 try:
4759 return self._registrantGenerator
4760 except AttributeError, e:
4761 self._registrantGenerator = Counter()
4762 return self._registrantGenerator
4764 def addRegistrant(self, rp, user):
4765 rp.setId( str(self._getRegistrantGenerator().newCount()) )
4766 rp.setOwner( self )
4767 self.getRegistrants()[rp.getId()] = rp
4768 self._notify('registrantAdded', user)
4769 self.notifyModification()
4771 def updateRegistrantIndexByEmail(self, rp, newEmail):
4772 oldEmail = rp.getEmail()
4773 if oldEmail != newEmail:
4774 if self.getRegistrantsByEmail().has_key(oldEmail):
4775 del self.getRegistrantsByEmail()[oldEmail]
4776 self.getRegistrantsByEmail()[newEmail] = rp
4777 self.notifyModification()
4779 def hasRegistrant(self,rp):
4780 return rp.getConference()==self and \
4781 self.getRegistrants().has_key(rp.getId())
4783 def hasRegistrantByEmail(self, email):
4784 # Return true if there is someone with the email of the param "email"
4785 return self.getRegistrantsByEmail().has_key(email)
4787 def removeRegistrant(self, id):
4788 part = self.getRegistrants()[id]
4789 self._registrationForm.notifyRegistrantRemoval(self.getRegistrants()[id])
4790 del self.getRegistrantsByEmail()[self.getRegistrantById(id).getEmail()]
4791 del self.getRegistrants()[id]
4792 if part.getAvatar() is not None:
4793 part.getAvatar().removeRegistrant(part)
4794 self._notify('registrantRemoved', part)
4795 TrashCanManager().add(part)
4796 self.notifyModification()
4798 def getRegistrantById(self, id):
4799 if self.getRegistrants().has_key(id):
4800 return self.getRegistrants()[id]
4801 return None
4803 def _getPrimAuthIndex(self):
4804 try:
4805 if self._primAuthIdx:
4806 pass
4807 except AttributeError:
4808 self._primAuthIdx=_PrimAuthIdx(self)
4809 return self._primAuthIdx
4811 def getContribsMatchingAuth(self,query,onlyPrimary=True):
4812 if str(query).strip()=="":
4813 return self.getContributionList()
4814 res=self._getPrimAuthIndex().match(query)
4815 return [self.getContributionById(id) for id in res]
4817 def getCoordinatedSessions( self, av ):
4818 """Returns a list with the sessions for which a user is coordinator.
4820 try:
4821 if self._sessionCoordinators:
4822 pass
4823 except AttributeError:
4824 self._sessionCoordinators = SCIndex()
4825 sessions = self._sessionCoordinators.getSessions( av )
4826 for session in self.getSessionList():
4827 if session not in sessions and av != None:
4828 for email in av.getEmails():
4829 if email in session.getCoordinatorEmailList():
4830 sessions.append(session)
4831 break
4832 return sessions
4834 def getManagedSession( self, av ):
4835 ls = []
4836 for session in self.getSessionList():
4837 pending = False
4838 if av != None:
4839 for email in av.getEmails():
4840 if email in session.getAccessController().getModificationEmail():
4841 pending = True
4842 break
4843 if av in session.getManagerList() or pending:
4844 ls.append(session)
4845 return ls
4847 def addSessionCoordinator(self,session,av):
4848 """Makes a user become coordinator for a session.
4850 try:
4851 if self._sessionCoordinators:
4852 pass
4853 except AttributeError:
4854 self._sessionCoordinators = SCIndex()
4855 if self.sessions.has_key(session.getId()):
4856 session.addCoordinator(av)
4857 self._sessionCoordinators.index(av,session)
4859 def removeSessionCoordinator( self, session, av ):
4860 """Removes a user as coordinator for a session.
4862 try:
4863 if self._sessionCoordinators:
4864 pass
4865 except AttributeError:
4866 self._sessionCoordinators = SCIndex()
4867 if self.sessions.has_key(session.getId()):
4868 session.removeCoordinator( av )
4869 self._sessionCoordinators.unindex(av,session)
4871 def _getSubmitterIdx(self):
4872 try:
4873 return self._submitterIdx
4874 except AttributeError:
4875 self._submitterIdx=SubmitterIndex()
4876 return self._submitterIdx
4878 def addContribSubmitter(self,contrib,av):
4879 self._getSubmitterIdx().index(av,contrib)
4881 def removeContribSubmitter(self,contrib,av):
4882 self._getSubmitterIdx().unindex(av,contrib)
4884 def getContribsForSubmitter(self,av):
4885 return self._getSubmitterIdx().getContributions(av)
4887 def getBOAConfig(self):
4888 try:
4889 if self._boa:
4890 pass
4891 except AttributeError:
4892 self._boa=BOAConfig(self)
4893 return self._boa
4895 def getSessionCoordinatorRights(self):
4896 try:
4897 if self._sessionCoordinatorRights:
4898 pass
4899 except AttributeError, e:
4900 self._sessionCoordinatorRights = []
4901 self.notifyModification()
4902 return self._sessionCoordinatorRights
4904 def hasSessionCoordinatorRight(self, right):
4905 return right in self.getSessionCoordinatorRights()
4907 def addSessionCoordinatorRight(self, right):
4908 if SessionCoordinatorRights().hasRight(right) and not self.hasSessionCoordinatorRight(right):
4909 self._sessionCoordinatorRights.append(right)
4910 self.notifyModification()
4912 def removeSessionCoordinatorRight(self, right):
4913 if SessionCoordinatorRights().hasRight(right) and self.hasSessionCoordinatorRight(right):
4914 self._sessionCoordinatorRights.remove(right)
4915 self.notifyModification()
4917 def getSections(self):
4918 try:
4919 if self._sections:
4920 pass
4921 except AttributeError, e:
4922 self._sections = ConfSectionsMgr().getSectionKeys()
4923 self.notifyModification()
4924 return self._sections
4926 def hasEnabledSection(self, section):
4927 # This hack is there since there is no more enable/disable boxes
4928 # in the conference managment area corresponding to those features.
4929 # Until the managment area is improved to get a more user-friendly
4930 # way of enabling/disabling those features, we always make them
4931 # available for the time being, but we keep the previous code for
4932 # further improvements
4933 return True
4935 def enableSection(self, section):
4936 if ConfSectionsMgr().hasSection(section) and not self.hasEnabledSection(section):
4937 self._sections.append(section)
4938 self.notifyModification()
4940 def disableSection(self, section):
4941 if ConfSectionsMgr().hasSection(section) and self.hasEnabledSection(section):
4942 self._sections.remove(section)
4943 self.notifyModification()
4945 def getPendingQueuesMgr(self):
4946 try:
4947 if self._pendingQueuesMgr:
4948 pass
4949 except AttributeError, e:
4950 self._pendingQueuesMgr=pendingQueues.ConfPendingQueuesMgr(self)
4951 return self._pendingQueuesMgr
4953 def getAccessController(self):
4954 return self.__ac
4956 def _cmpTitle( c1, c2 ):
4957 o1 = c1.getTitle().lower().strip()
4958 o2 = c2.getTitle().lower().strip()
4959 return cmp( o1, o2 )
4960 _cmpTitle=staticmethod(_cmpTitle)
4962 def getReportNumberHolder(self):
4963 try:
4964 if self._reportNumberHolder:
4965 pass
4966 except AttributeError, e:
4967 self._reportNumberHolder=ReportNumberHolder(self)
4968 return self._reportNumberHolder
4970 def setReportNumberHolder(self, rnh):
4971 self._reportNumberHolder=rnh
4973 def getBadgeTemplateManager(self):
4974 try:
4975 if self.__badgeTemplateManager:
4976 pass
4977 except AttributeError:
4978 self.__badgeTemplateManager = BadgeTemplateManager(self)
4979 return self.__badgeTemplateManager
4981 def setBadgeTemplateManager(self, badgeTemplateManager):
4982 self.__badgeTemplateManager = badgeTemplateManager
4984 def getPosterTemplateManager(self):
4985 try:
4986 if self.__posterTemplateManager:
4987 pass
4988 except AttributeError:
4989 self.__posterTemplateManager = PosterTemplateManager(self)
4991 return self.__posterTemplateManager
4993 def setPosterTemplateManager(self, posterTemplateManager):
4994 self.__posterTemplateManager = posterTemplateManager
4996 def getCSBookingManager(self):
4998 if PluginsHolder().hasPluginType("Collaboration"):
4999 if not hasattr(self, "_CSBookingManager"):
5000 from MaKaC.plugins.Collaboration.base import CSBookingManager
5001 self._CSBookingManager = CSBookingManager(self)
5002 return self._CSBookingManager
5003 else:
5004 return None
5007 class DefaultConference(Conference):
5008 """ 'default' conference, which stores the
5009 default templates for posters and badges
5012 def indexConf(self):
5013 pass
5015 def __init__(self):
5016 """ Default constructor
5018 try:
5019 Conference.__init__(self, AdminList.getInstance().getList()[0], "default")
5020 except IndexError:
5021 raise MaKaCError(_("""There are no admin users. The "default" conference that stores the template cannot be created.
5022 Please add at least 1 user to the admin list."""))
5025 class ConferenceHolder( ObjectHolder ):
5026 """Specialised ObjectHolder dealing with conference objects. It gives a
5027 common entry point and provides simple methods to access and
5028 maintain the collection of stored conferences (DB).
5030 idxName = "conferences"
5031 counterName = "CONFERENCE"
5033 def _newId( self ):
5034 id = ObjectHolder._newId( self )
5035 return "%s"%id
5037 def getById( self, id, quiet=False ):
5038 """returns an object from the index which id corresponds to the one
5039 which is specified.
5042 if (id == "default"):
5043 return CategoryManager().getDefaultConference()
5045 if type(id) is int:
5046 id = str(id)
5047 if self._getIdx().has_key(str(id)):
5048 return self._getIdx()[str(id)]
5049 elif quiet:
5050 return None
5051 else:
5052 raise NoReportError( _("The specified event with id \"%s\" does not exist or has been deleted.") % escape_html(str(id)) )
5054 class ConfSectionsMgr:
5056 def __init__(self):
5057 self._sections = {
5058 "cfa": "Call for abstracts",
5059 "paperReviewing" : "Paper Reviewing",
5060 "evaluation": "Evaluation Form",
5061 "videoconference": "Videoconference", # only for meetings
5062 "collaboration": "Collaboration", # only for meetings
5063 "regForm": "Registration Form"
5066 def hasSection(self, s):
5067 # This hack is there since there is no more enable/disable boxes
5068 # in the conference managment area corresponding to those features.
5069 # Until the managment area is improved to get a more user-friendly
5070 # way of enabling/disabling those features, we always make them
5071 # available in the side menu for the time being, but we keep
5072 # the previous code for further improvements
5073 #return self._sections.has_key(s)
5074 return True
5076 def getSections(self):
5077 return self._sections
5079 def getSectionList(self, sort=False):
5080 l=self._sections.values()
5081 if sort:
5082 l.sort()
5083 return l
5085 def getSectionKeys(self, sort=False):
5086 l=self._sections.keys()
5087 if sort:
5088 l.sort()
5089 return l
5091 def getSection(self, id):
5092 if self._sections.has_key(id):
5093 return self._sections[id]
5094 return None
5097 class Observer(object):
5098 """ Base class for Observer objects.
5099 Inheriting classes should overload the following boolean class attributes:
5100 _shouldBeTitleNotified
5101 _shouldBeDateChangeNotified
5102 _shouldBeLocationChangeNotified
5103 _shouldBeDeletionNotified
5104 And set them to True if they want to be notified of the corresponding event.
5105 In that case, they also have to implement the corresponding methods:
5106 _notifyTitleChange (for title notification)
5107 _notifyEventDateChanges and _notifyTimezoneChange (for date / timezone notification)
5108 _shouldBeLocationChangeNotified (for location notification)
5109 _notifyDeletion (for deletion notification).
5110 The interface for those methods is also specified in this class. If the corresponding
5111 class attribute is set to False but the method is not implemented, an exception will be thrown.
5113 _shouldBeTitleNotified = False
5114 _shouldBeDateChangeNotified = False
5115 _shouldBeLocationChangeNotified = False
5116 _shouldBeDeletionNotified = False
5118 def getObserverName(self):
5119 name = "'Observer of class" + self.__class__.__name__
5120 try:
5121 conf = self.getOwner()
5122 name = name + " of event " + conf.getId() + "'"
5123 except AttributeError:
5124 pass
5125 return name
5127 def notifyTitleChange(self, oldTitle, newTitle):
5128 if self._shouldBeTitleNotified:
5129 self._notifyTitleChange(oldTitle, newTitle)
5131 def notifyEventDateChanges(self, oldStartDate = None, newStartDate = None, oldEndDate = None, newEndDate = None):
5132 if self._shouldBeDateChangeNotified:
5133 self._notifyEventDateChanges(oldStartDate, newStartDate, oldEndDate, newEndDate)
5135 def notifyTimezoneChange(self, oldTimezone, newTimezone):
5136 if self._shouldBeDateChangeNotified:
5137 self._notifyTimezoneChange(oldTimezone, newTimezone)
5139 def notifyLocationChange(self, newLocation):
5140 if self._shouldBeLocationChangeNotified:
5141 self._notifyLocationChange(newLocation)
5143 def notifyDeletion(self):
5144 if self._shouldBeDeletionNotified:
5145 self._notifyDeletion()
5147 def _notifyTitleChange(self, oldTitle, newTitle):
5148 """ To be implemented by inheriting classes
5149 Notifies the observer that the Conference object's title has changed
5151 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method _notifyTitleChange")
5153 def _notifyEventDateChanges(self, oldStartDate, newStartDate, oldEndDate, newEndDate):
5154 """ To be implemented by inheriting classes
5155 Notifies the observer that the start and / or end dates of the object it is attached to has changed.
5156 If the observer finds any problems during whatever he needs to do as a consequence of
5157 the event dates changing, he should write strings describing the problems
5158 in the 'dateChangeNotificationProblems' context variable (which is a list of strings).
5160 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyStartDateChange")
5162 def _notifyTimezoneChange(self, oldTimezone, newTimezone):
5163 """ To be implemented by inheriting classes.
5164 Notifies the observer that the end date of the object it is attached to has changed.
5165 This method has to return a list of strings describing problems encountered during
5166 whatever the DateChangeObserver object does as a consequence of the notification.
5167 If there are no problems, the DateChangeObserver should return an empty list.
5169 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTimezoneChange")
5171 def _notifyLocationChange(self):
5172 """ To be implemented by inheriting classes
5173 Notifies the observer that the location of the object it is attached to has changed.
5175 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyLocationChange")
5177 def _notifyDeletion(self):
5178 """ To be implemented by inheriting classes
5179 Notifies the observer that the Conference object it is attached to has been deleted
5181 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyDeletion")
5183 class TitleChangeObserver(Observer):
5184 """ Base class for objects who want to be notified of a Conference object being deleted.
5185 Inheriting classes have to implement the notifyTitleChange method, and probably the __init__ method too.
5188 def notifyTitleChange(self, oldTitle, newTitle):
5189 """ To be implemented by inheriting classes
5190 Notifies the observer that the Conference object's title has changed
5192 raise MaKaCError("Class " + str(self.__class__.__name__) + " did not implement method notifyTitleChange")
5195 class SessionChair(ConferenceParticipation):
5197 def __init__(self):
5198 self._session=None
5199 self._id=""
5200 ConferenceParticipation.__init__(self)
5202 def _notifyModification( self ):
5203 if self._session != None:
5204 self._session.notifyModification()
5206 def clone(self):
5207 chair = SessionChair()
5208 chair.setValues(self.getValues())
5209 return chair
5211 def getSession(self):
5212 return self._session
5214 def getConference(self):
5215 s=self.getSession()
5216 if s is None:
5217 return None
5218 return s.getConference()
5220 def includeInSession(self,session,id):
5221 if self.getSession()==session and self.getId()==id.strip():
5222 return
5223 self._session=session
5224 self._id=id
5226 def delete( self ):
5227 self._session=None
5228 ConferenceParticipation.delete(self)
5230 def getLocator(self):
5231 if self.getSession() is None:
5232 return None
5233 loc=self.getSession().getLocator()
5234 loc["convId"]=self.getId()
5235 return loc
5237 def isSessionManager(self):
5238 # pendings managers
5239 if self.getEmail() in self._session.getAccessController().getModificationEmail():
5240 return True
5241 # managers list
5242 for manager in self._session.getManagerList():
5243 if self.getEmail() == manager.getEmail():
5244 return True
5245 return False
5247 def isSessionCoordinator(self):
5248 # pendings coordinators
5249 if self.getEmail() in self._session.getConference().getPendingQueuesMgr().getPendingCoordinatorsKeys():
5250 return True
5251 # coordinator list
5252 for coord in self._session.getCoordinatorList():
5253 if self.getEmail() == coord.getEmail():
5254 return True
5255 return False
5258 class SlotChair(ConferenceParticipation):
5260 def __init__(self):
5261 self._slot=None
5262 self._id=""
5263 ConferenceParticipation.__init__(self)
5265 def _notifyModification( self ):
5266 if self._slot != None:
5267 self._slot.notifyModification()
5269 def clone(self):
5270 chair = SlotChair()
5271 chair.setValues(self.getValues())
5272 return chair
5274 def getSlot(self):
5275 return self._slot
5277 def getSession(self):
5278 s=self.getSlot()
5279 if s is None:
5280 return None
5281 return s.getSession()
5283 def getConference(self):
5284 s=self.getSlot()
5285 if s is None:
5286 return None
5287 return s.getConference()
5289 def includeInSlot(self,slot,id):
5290 if self.getSlot()==slot and self.getId()==id.strip():
5291 return
5292 self._slot=slot
5293 self._id=id
5295 def delete( self ):
5296 self._slot=None
5297 ConferenceParticipation.delete(self)
5299 def getLocator(self):
5300 if self.getSlot() is None:
5301 return None
5302 loc=self.getSlot().getLocator()
5303 loc["convId"]=self.getId()
5304 return loc
5306 class SessionCoordinatorRights:
5308 def __init__(self):
5309 self._rights = {"modifContribs": "Modify the contributions",
5310 "unrestrictedSessionTT": "Unrestricted session timetable management"
5313 def hasRight(self, r):
5314 return self._rights.has_key(r)
5316 def getRights(self):
5317 return self._rights
5319 def getRightList(self, sort=False):
5320 l=self._rights.values()
5321 if sort:
5322 l.sort()
5323 return l
5325 def getRightKeys(self):
5326 return self._rights.keys()
5328 def getRight(self, id):
5329 if self._rights.has_key(id):
5330 return self._rights[id]
5331 return None
5333 class SCIndex(Persistent):
5334 """Index for conference session coordinators.
5336 This class allows to index conference session coordinators so the owner
5337 can answer optimally to the query if a user is coordinating
5338 any conference session.
5339 It is implemented by simply using a BTree where the Avatar id is used
5340 as key (because it is unique and non variable) and a list of
5341 coordinated sessions is kept as keys. It is the responsability of the
5342 index owner (conference) to keep it up-to-date i.e. notify session
5343 coordinator additions and removals.
5346 def __init__( self ):
5347 self._idx=OOBTree()
5350 def getSessions(self,av):
5351 """Gives a list with the sessions a user is coordinating.
5353 if av == None:
5354 return []
5355 return self._idx.get(av.getId(),[])
5357 def index(self,av,session):
5358 """Registers in the index a coordinator of a session.
5360 if av == None or session == None:
5361 return
5362 if not self._idx.has_key(av.getId()):
5363 l=[]
5364 self._idx[av.getId()]=l
5365 else:
5366 l=self._idx[av.getId()]
5367 if session not in l:
5368 l.append(session)
5369 self.notifyModification()
5371 def unindex(self,av,session):
5372 if av==None or session==None:
5373 return
5374 l=self._idx.get(av.getId(),[])
5375 if session in l:
5376 l.remove(session)
5377 self.notifyModification()
5379 def notifyModification(self):
5380 self._idx._p_changed=1
5383 class Session(CommonObjectBase, Locatable):
5384 """This class implements a conference session, being the different parts
5385 in which the conference can be divided and the contributions can be
5386 organised in. The class contains necessary attributes to store session
5387 basic data and provides the operations related to sessions. In
5388 principle, a session has no sense to exist without being related to a
5389 conference but it is allowed for flexibility.
5392 fossilizes(ISessionFossil)
5395 def __init__(self, **sessionData):
5396 """Class constructor. Initialise the class attributes to the default
5397 values.
5398 Params:
5399 sessionData -- (Dict) Contains the data the session object has to
5400 be initialised to.
5402 self.conference=None
5403 self.id="not assigned"
5404 self.title=""
5405 self.description=""
5406 #################################
5407 # Fermi timezone awareness #
5408 #################################
5409 self.startDate = nowutc()
5410 #################################
5411 # Fermi timezone awareness(end) #
5412 #################################
5414 self.duration=timedelta(minutes=1)
5415 self.places=[]
5416 self.rooms=[]
5417 self.conveners=[] # This attribute must not be used and should disappear someday
5418 self._conveners=[]
5419 self._convenerGen=Counter()
5420 self.convenerText=""
5421 self.contributions={}
5422 self._contributionDuration=timedelta(minutes=20)
5423 self.__ac=AccessController(self)
5424 self.materials={}
5425 self.__materialGenerator=Counter()
5426 self.minutes=None
5427 self._comments = ""
5428 self.slots={}
5429 self.__slotGenerator=Counter()
5430 self._setSchedule()
5431 self._coordinators=OOBTree()
5432 self._coordinatorsEmail = []
5433 self._code=""
5434 self._color="#e3f2d3"
5435 self._textColor="#202020"
5436 self._textColorToLinks=False
5437 self._ttType=SlotSchTypeFactory.getDefaultId()
5438 self._closed = False
5439 self._registrationSession = None
5440 self._creationDS = nowutc()
5441 self._modificationDS = nowutc()
5442 self._keywords = ""
5444 def __cmp__(self, other):
5445 if type(self) is not type(other):
5446 # This is actually dangerous and the ZODB manual says not to do this
5447 # because it relies on memory order. However, this branch should never
5448 # be taken anyway since we do not store different types in the same set
5449 # or use them as keys.
5450 return cmp(hash(self), hash(other))
5451 if self.getConference() == other.getConference():
5452 return cmp(self.getId(), other.getId())
5453 return cmp(self.getConference(), other.getConference())
5455 def getTimezone( self ):
5456 return self.getConference().getTimezone()
5458 def updateNonInheritingChildren(self, elem, delete=False, propagate=True):
5459 self.getAccessController().updateNonInheritingChildren(elem, delete)
5460 if propagate == True:
5461 self.notify_protection_to_owner(elem, delete)
5463 def notify_protection_to_owner(self, elem, delete=False):
5464 """ This methods notifies the owner that the protection has been changed,
5465 so it can update its list of non inheriting children """
5466 self.getOwner().updateNonInheritingChildren(elem, delete)
5468 def getKeywords(self):
5469 try:
5470 return self._keywords
5471 except:
5472 self._keywords = ""
5473 return ""
5475 def setKeywords(self, keywords):
5476 self._keywords = keywords
5478 def notifyModification( self, raiseEvent = True, date = None, cleanCache = True ):
5479 """Method called to notify the current session has been modified.
5481 self.setModificationDate(date)
5483 parent = self.getConference()
5484 if parent:
5485 parent.setModificationDate(date)
5486 if cleanCache:
5487 for slot in self.getSlotList():
5488 slot.cleanCache()
5489 self._p_changed=1
5491 def getModificationDate( self ):
5492 """Returns the date in which the session was last modified"""
5493 try:
5494 return self._modificationDS
5495 except:
5496 self._modificationDS = nowutc()
5497 return self._modificationDS
5499 def getCreationDate( self ):
5500 """Returns the date in which the session was created"""
5501 try:
5502 return self._creationDS
5503 except:
5504 self._creationDS = nowutc()
5505 return self._creationDS
5507 def getLogInfo(self):
5508 data = {}
5509 data["subject"] = self.title
5510 data["session id"] = self.id
5511 data["session code"] = self._code
5512 data["title"] = self.title
5513 data["description"] = self.description
5514 data["start date"] = self.startDate
5515 data["duration"] = self.duration
5516 for p in self.places :
5517 data["place"] = p.getName()
5518 for r in self.rooms :
5519 data["room"] = r.getName()
5520 for sc in self.getConvenerList() :
5521 data["convener %s"%sc.getId()] = sc.getFullName()
5522 for co in self.getCoordinatorList() :
5523 data["coordinators %s"%co.getId()] = co.getFullName()
5525 return data
5527 def getEnableSessionSlots(self):
5528 try:
5529 return self.getConference().getEnableSessionSlots()
5530 except:
5531 return True
5533 def cmpSessionByTitle(session1, session2):
5534 return cmp(session1.getTitle(), session2.getTitle())
5535 cmpSessionByTitle = staticmethod(cmpSessionByTitle)
5537 def hasRegistrationSession(self):
5538 return self.getRegistrationSession() is not None
5540 def getRegistrationSession(self):
5541 try:
5542 if self._registrationSession:
5543 pass
5544 except AttributeError, e:
5545 self._registrationSession = None
5546 return self._registrationSession
5548 def setRegistrationSession(self, rs):
5549 self._registrationSession = rs
5551 def isClosed( self ):
5552 if self.getConference().isClosed():
5553 return True
5554 try:
5555 return self._closed
5556 except:
5557 self._closed = False
5558 return False
5560 def setClosed( self, closed=True ):
5561 self._closed = closed
5562 self.notifyModification(cleanCache = False)
5564 def includeInConference(self,conf,newId):
5565 self.conference=conf
5566 self.id=newId
5567 for slot in self.getSlotList():
5568 conf.getSchedule().addEntry(slot.getConfSchEntry(),2)
5569 self.getConference().addSession(self)
5570 self.notifyModification()
5572 def delete(self):
5573 while len(self.getConvenerList()) > 0:
5574 self.removeConvener(self.getConvenerList()[0])
5575 while len(self.getMaterialList()) > 0:
5576 self.removeMaterial(self.getMaterialList()[0])
5577 self.removeMinutes()
5578 for c in self.getCoordinatorList()[:]:
5579 self.removeCoordinator(c)
5580 while len(self.contributions.values())>0:
5581 self.removeContribution(self.contributions.values()[0])
5582 while len(self.slots.values())>0:
5583 self._removeSlot(self.slots.values()[0])
5584 if self.getConference() is not None:
5585 self.getConference().removeSession(self)
5586 if self.hasRegistrationSession():
5587 self.getConference().getRegistrationForm().getSessionsForm().removeSession(self.getId())
5588 self.getRegistrationSession().setRegistrationForm(None)
5589 TrashCanManager().add(self.getRegistrationSession())
5590 self.notify_protection_to_owner(self, delete=True)
5591 self.conference=None
5592 TrashCanManager().add(self)
5594 def recover(self, isCancelled):
5595 if self.hasRegistrationSession():
5596 if not isCancelled:
5597 self.getRegistrationSession().setRegistrationForm(self.getConference().getRegistrationForm())
5598 self.getConference().getRegistrationForm().getSessionsForm().addSession(self.getRegistrationSession())
5599 TrashCanManager().remove(self.getRegistrationSession())
5600 TrashCanManager().remove(self)
5602 def getLocator( self ):
5603 """Gives back a globaly unique identification encapsulated in a Locator
5604 object for the session instance
5606 if self.conference == None:
5607 return Locator()
5608 lconf = self.conference.getLocator()
5609 lconf["sessionId"] = self.getId()
5610 return lconf
5612 def getConference( self ):
5613 return self.conference
5615 def getSession( self ):
5616 return self
5618 def getOwner( self ):
5619 return self.getConference()
5621 def getId( self ):
5622 return self.id
5624 def getUniqueId( self ):
5625 """returns (string) the unique identiffier of the item"""
5626 """used mainly in the web session access key table"""
5627 return "%ss%s" % (self.getConference().getUniqueId(),self.id)
5629 def getModifKey( self ):
5630 return self.getConference().getModifKey()
5632 def getAccessKey( self ):
5633 return self.getConference().getAccessKey()
5635 def getContribDuration(self):
5636 try:
5637 return self._contributionDuration
5638 except:
5639 self._contributionDuration = timedelta(minutes=20)
5640 return self._contributionDuration
5642 def setContribDuration(self, hour=0, min=20, dur=None):
5643 if dur is not None:
5644 self._contributionDuration=dur
5645 else:
5646 self._contributionDuration = timedelta(hours=hour,minutes=min)
5648 def fit(self):
5649 #if not self.getConference().getEnableSessionSlots():
5650 # self.getSlotList()[0].fit()
5651 self.setStartDate(self.getMinSlotStartDate(),0,0)
5652 self.setEndDate(self.getMaxSlotEndDate(),0)
5654 def addSlot(self,newSlot):
5655 id = newSlot.getId()
5656 if id == "not assigned":
5657 newSlot.setId(str(self.__slotGenerator.newCount()))
5658 self.slots[newSlot.getId()]=newSlot
5659 self.fit()
5660 self.getSchedule().addEntry(newSlot.getSessionSchEntry(),2)
5661 if self.getConference() is not None:
5662 self.getConference().getSchedule().addEntry(newSlot.getConfSchEntry(),2)
5663 self.notifyModification()
5665 def _removeSlot(self,slot):
5666 del self.slots[slot.getId()]
5667 self.getSchedule().removeEntry(slot.getSessionSchEntry())
5668 if self.getConference() is not None:
5669 self.getConference().getSchedule().removeEntry(slot.getConfSchEntry())
5670 slot.delete()
5672 def removeSlot(self, slot, force=False):
5673 if self.slots.has_key(slot.getId()):
5674 if len(self.slots)==1 and not force:
5675 raise MaKaCError( _("A session must have at least one slot"), _("Session"))
5676 self._removeSlot(slot)
5677 self.fit()
5678 self.notifyModification()
5680 def recoverSlot(self, slot):
5681 self.addSlot(slot)
5682 slot.recover()
5684 def getSlotById(self,slotId):
5685 return self.slots.get(slotId,None)
5687 def getSlotList(self):
5688 return self.slots.values()
5690 def getSortedSlotList(self):
5691 sl = self.getSlotList()
5692 sl.sort(utils.sortSlotByDate)
5693 return sl
5695 def getMinSlotStartTime(self):
5696 min = (25,61)
5697 for slot in self.getSlotList():
5698 if slot.isMoreThanDay():
5699 return (0,0)
5700 shour = slot.getStartDate().hour
5701 smin = slot.getStartDate().minute
5702 if (shour, smin) < min:
5703 min = (shour, smin)
5704 return min
5706 def getMaxSlotEndTime(self):
5707 max = (-1,-1)
5708 for slot in self.getSlotList():
5709 if slot.isMoreThanDay():
5710 return (23, 59)
5711 endDate = slot.getEndDate()
5712 if (endDate.hour, endDate.minute) > max:
5713 newEndDate = endDate - timedelta(0, 0, 0)
5714 max = (newEndDate.hour, newEndDate.minute)
5715 return max
5717 def getMinSlotStartDate(self):
5718 slotList = self.getSlotList()
5719 if len(slotList)==0:
5720 return self.getStartDate()
5721 else:
5722 sDate = self.getEndDate()
5723 for slot in slotList:
5724 if slot.getStartDate() < sDate:
5725 sDate = slot.getStartDate()
5726 return sDate
5728 def getMaxSlotEndDate(self):
5729 slotList = self.getSlotList()
5730 if len(slotList)==0:
5731 return self.getEndDate()
5732 else:
5733 eDate = self.getStartDate()
5734 for slot in slotList:
5735 if slot.getEndDate() > eDate:
5736 eDate = slot.getEndDate()
5737 return eDate
5739 def _getCorrectColor(self, color):
5740 if not color.startswith("#"):
5741 color = "#%s"%color
5742 m = re.match("^#[0-9A-Fa-f]{6}$", color)
5743 if m:
5744 return color
5745 return None
5747 def _getCorrectBgColor(self, color):
5748 color=self._getCorrectColor(color)
5749 if color is None:
5750 return self._color
5751 return color
5753 def _getCorrectTextColor(self, color):
5754 color=self._getCorrectColor(color)
5755 if color is None:
5756 return self._textColor
5757 return color
5759 def setValues( self, sessionData,check=2,moveEntries=0 ):
5760 """Sets all the values of the current session object from a dictionary
5761 containing the following key-value pairs:
5762 title-(str)
5763 description-(str)
5764 locationName-(str) => name of the location, if not specified
5765 it will be set to the conference location name.
5766 locationAddress-(str)
5767 roomName-(str) => name of the room, if not specified it will
5768 be set to the conference room name.
5769 sDate - (datetime) => starting date of the session, if not
5770 specified it will be set to now.
5771 eDate - (datetime) => ending date of the session, if not
5772 specified the end date will be set to the start one
5773 durHour - (int) => hours of duration for each entry in the session
5774 by default.
5775 durMin - (int) => hours of duration for each entry in the session
5776 by default.
5777 _conveners - (str)
5778 check parameter:
5779 0: no check at all
5780 1: check and raise error in case of problem
5781 2: check and adapt the owner dates
5782 Please, note that this method sets ALL values which means that if
5783 the given dictionary doesn't contain any of the keys the value
5784 will set to a default value.
5787 self.setTitle( sessionData.get("title", "NO TITLE ASSIGNED") )
5788 self.setDescription( sessionData.get("description", "") )
5789 code = sessionData.get("code", "")
5790 if code.strip() == "":
5791 if self.getId()=="not assigned":
5792 self.setCode("no code")
5793 else:
5794 self.setCode(self.getId())
5795 else:
5796 self.setCode(code)
5797 bgcolor = sessionData.get("backgroundColor", "")
5798 if bgcolor.strip() != "":
5799 self.setColor(self._getCorrectBgColor(bgcolor))
5800 textcolor = sessionData.get("textColor", "")
5801 if textcolor.strip() != "":
5802 if sessionData.has_key("autotextcolor"):
5803 self.setTextColor(utils.getTextColorFromBackgroundColor(self.getColor()))
5804 else:
5805 self.setTextColor(self._getCorrectTextColor(textcolor))
5806 self.setTextColorToLinks(sessionData.has_key("textcolortolinks"))
5808 if "locationName" in sessionData:
5809 loc = self.getOwnLocation()
5810 if not loc:
5811 loc = CustomLocation()
5812 self.setLocation( loc )
5813 loc.setName( sessionData["locationName"] )
5814 loc.setAddress( sessionData.get("locationAddress", "") )
5815 else:
5816 self.setLocation(None)
5818 #same as for the location
5819 if "roomName" in sessionData:
5820 room = self.getOwnRoom()
5821 if not room:
5822 room = CustomRoom()
5823 self.setRoom( room )
5824 room.setName( sessionData["roomName"] )
5825 else:
5826 self.setRoom(None)
5828 if sessionData.get("sDate",None) is not None:
5829 self.setStartDate(sessionData["sDate"],check,moveEntries=moveEntries)
5830 if sessionData.get("eDate",None) is not None:
5831 self.setEndDate(sessionData["eDate"],check)
5832 self._checkInnerSchedule()
5833 if sessionData.get("contribDuration","")!="":
5834 self._contributionDuration = sessionData.get("contribDuration")
5835 else:
5836 self._contributionDuration = timedelta(hours=int(sessionData.get("durHour",0)), minutes=int(sessionData.get("durMin",20)))
5837 self.notifyModification()
5839 def move(self, sDate):
5841 Move a session from the old start date to a new start date, and
5842 it moves all the entries of the session as well, without date validations.
5844 if sDate is not None:
5845 oldStartDate=self.startDate
5846 self.startDate=copy.copy(sDate)
5847 diff=self.startDate-oldStartDate
5848 # Check date to not be prior conference start date and to not surpass conference end date
5849 # The schedule is returning the datetime object as timezone aware relative to the conference
5850 # timezone. Must adjust the startdate accordingly for comparison. JMF
5851 conftz = self.getConference().getTimezone()
5852 if self.getStartDate() < self.getConference().getSchedule().getStartDate() or \
5853 self.getEndDate() > self.getConference().getSchedule().getEndDate():
5854 raise MaKaCError( _("Impossible to move the session because it would be out of the conference dates"))
5855 for entry in self.getSchedule().getEntries():
5856 if isinstance(entry,LinkedTimeSchEntry) and \
5857 isinstance(entry.getOwner(), SessionSlot):
5858 e = entry.getOwner()
5859 e.move(e.getStartDate() + diff)
5860 self.getSchedule().reSchedule()
5861 self.getConference().getSchedule().reSchedule()
5862 self.notifyModification()
5864 def clone(self, deltaTime, conf, options):
5865 ses = Session()
5866 conf.addSession(ses,check=0)
5867 ses.setTitle(self.getTitle())
5868 ses.setDescription(self.getDescription())
5869 startDate = self.getStartDate() + deltaTime
5870 ses.setStartDate(startDate, check=1)
5871 ses.setDuration(dur=self.getDuration())
5873 if self.getOwnLocation() is not None:
5874 ses.addLocation(self.getOwnLocation().clone())
5875 if self.getOwnRoom() is not None:
5876 ses.setRoom(self.getOwnRoom().clone())
5877 ses.setColor(self.getColor())
5878 ses.setTextColor(self.getTextColor())
5879 ses.setTextColorToLinks(self.isTextColorToLinks())
5880 ses.setCode(self.getCode())
5881 ses.setContribDuration(dur=self.getContribDuration())
5882 ses.setScheduleType(self.getScheduleType())
5883 ses.setComments(self.getComments())
5885 # Access Control cloning
5886 if options.get("access", False) :
5887 ses.setProtection(self.getAccessController()._getAccessProtection())
5888 for mgr in self.getManagerList() :
5889 ses.grantModification(mgr)
5890 for user in self.getAllowedToAccessList() :
5891 ses.grantAccess(user)
5892 for domain in self.getDomainList():
5893 ses.requireDomain(domain)
5894 for coord in self.getCoordinatorList():
5895 ses.addCoordinator(coord)
5897 #slots in timeschedule
5898 for slot in self.getSlotList() :
5899 newslot = slot.clone(ses, options)
5900 ses.addSlot(newslot)
5901 ContextManager.setdefault("clone.unique_id_map", {})[slot.getUniqueId()] = newslot.getUniqueId()
5903 ses.notifyModification()
5905 return ses
5908 def setTitle( self, newTitle ):
5909 self.title = newTitle
5910 self.notifyModification()
5912 def getTitle( self ):
5913 return self.title
5915 def setDescription(self, newDescription ):
5916 self.description = newDescription
5917 self.notifyModification()
5919 def getDescription(self):
5920 return self.description
5922 def getCode(self):
5923 try:
5924 if self._code:
5925 pass
5926 except AttributeError:
5927 self._code=self.id
5928 return self._code
5930 def setCode(self,newCode):
5931 self._code=str(newCode).strip()
5933 def getColor(self):
5934 try:
5935 if self._color:
5936 pass
5937 except AttributeError:
5938 self._color="#e3f2d3"
5939 return self._color
5940 getBgColor=getColor
5942 def setColor(self,newColor):
5943 self._color=str(newColor).strip()
5944 self.notifyModification()
5945 setBgColor=setColor
5947 def getTextColor(self):
5948 try:
5949 if self._textColor:
5950 pass
5951 except AttributeError:
5952 self._textColor="#202020"
5953 return self._textColor
5955 def setTextColor(self,newColor):
5956 self._textColor=str(newColor).strip()
5957 self.notifyModification()
5959 def isTextColorToLinks(self):
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
5969 self.notifyModification()
5971 def getStartDate(self):
5972 return self.startDate
5974 def getAdjustedStartDate(self,tz=None):
5975 if not tz:
5976 tz = self.getConference().getTimezone()
5977 if tz not in all_timezones:
5978 tz = 'UTC'
5979 return self.startDate.astimezone(timezone(tz))
5981 def verifyStartDate(self, sdate, check=2):
5982 """check parameter:
5983 0: no check at all
5984 1: check and raise error in case of problem (default)
5985 2: check and adapt the owner dates
5988 conf=self.getConference()
5990 if conf is not None and sdate < conf.getSchedule().getStartDate():
5991 if check==1:
5992 raise ParentTimingError( _("The session starting date cannot be prior to the event starting date"), _("Session"))
5993 elif check==2:
5994 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
5995 conf, sdate.astimezone(timezone(conf.getTimezone()))))
5996 conf.setStartDate(sdate,check=0,moveEntries=0)
5998 def setStartDate(self,newDate,check=2,moveEntries=0):
6000 moveEntries parameter:
6001 0: do not move inner slots
6002 1: move
6003 2: do not move but check that session is not out of the conference dates
6006 if not newDate.tzname():
6007 raise MaKaCError("date should be timezone aware")
6008 if check != 0:
6009 self.verifyStartDate(newDate,check)
6010 oldSdate = self.getStartDate()
6011 try:
6012 tz = str(self.getStartDate().tzinfo)
6013 except:
6014 tz = 'UTC'
6015 diff = newDate - oldSdate
6016 self.startDate=copy.copy(newDate)
6017 if moveEntries == 1 and diff is not None and diff != timedelta(0):
6018 # If the start date changed, we move entries inside the timetable
6019 newDateTz = newDate.astimezone(timezone(tz))
6020 if oldSdate.astimezone(timezone(tz)).date() != newDateTz.date():
6021 entries = self.getSchedule().getEntries()[:]
6022 else:
6023 entries = self.getSchedule().getEntriesOnDay(newDateTz)[:]
6024 self.getSchedule().moveEntriesBelow(diff, entries)
6026 if moveEntries != 0 and self.getConference() and \
6027 not self.getConference().getEnableSessionSlots() and \
6028 self.getSlotList() != [] and \
6029 self.getSlotList()[0].getStartDate() != newDate:
6030 self.getSlotList()[0].startDate = newDate
6032 if check == 1:
6033 self._checkInnerSchedule()
6034 self.notifyModification()
6036 def _checkInnerSchedule( self ):
6037 self.getSchedule().checkSanity()
6039 def getEndDate(self):
6040 return self.startDate+self.duration
6042 ####################################
6043 # Fermi timezone awareness #
6044 ####################################
6046 def getAdjustedEndDate(self,tz=None):
6047 return self.getAdjustedStartDate(tz) + self.duration
6049 ####################################
6050 # Fermi timezone awareness(end) #
6051 ####################################
6053 def verifyEndDate(self, edate,check=1):
6054 """check parameter:
6055 0: no check at all
6056 1: check and raise error in case of problem
6057 2: check and adapt the owner dates
6059 try:
6060 tz = timezone(self.getConference().getTimezone())
6061 except:
6062 tz = timezone('UTC')
6063 # compare end date with start date
6064 if edate<=self.getStartDate():
6065 if check == 1:
6066 raise MaKaCError( _("End date cannot be prior to the Start date"), _("Session"))
6067 if check == 2:
6068 self.setStartDate(edate)
6069 # check conference dates
6070 if (self.getConference()):
6071 conf=self.getConference()
6072 confStartDate = conf.getSchedule().getStartDate()
6073 confEndDate = conf.getSchedule().getEndDate()
6074 if conf is not None and (edate>confEndDate or edate<=confStartDate):
6075 if check==1:
6076 raise ParentTimingError( _("The end date has to be between the event dates (%s - %s)")%\
6077 (confStartDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
6078 confEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
6079 _("Session"))
6080 if check==2:
6081 if edate>confEndDate:
6082 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
6083 self.getConference(),
6084 edate.astimezone(tz)))
6085 self.getConference().setEndDate(edate)
6086 if edate<=confStartDate:
6087 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
6088 self.getConference(),
6089 edate.astimezone(tz)))
6090 self.getConference().setStartDate(edate)
6091 # check inner schedule
6092 if len(self.getSlotList()) != 0 and self.getSlotList()[-1].getSchedule().hasEntriesAfter(edate):
6093 raise TimingError( _("Cannot change end date: some entries in the session schedule end after the new date"), _("Session"))
6095 def setEndDate(self,newDate,check=2):
6096 if not newDate.tzname():
6097 raise MaKaCError("date should be timezone aware")
6098 if check != 0:
6099 self.verifyEndDate(newDate,check)
6100 self.duration=newDate-self.getStartDate()
6101 # A session is not always linked to a conference (for eg. at creation time)
6102 #if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSlotList()[0].getEndDate() != newDate:
6103 # self.getSlotList()[0].duration = self.duration
6104 self.notifyModification()
6106 def setDates(self,sDate,eDate,check=1,moveEntries=0):
6107 if eDate<=sDate:
6108 tz = timezone(self.getConference().getTimezone())
6109 raise MaKaCError(_("The end date (%s) cannot be prior to the start date (%s)") % (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),_("Session"))
6110 self.setStartDate(sDate,check,moveEntries)
6111 self.setEndDate(eDate,check)
6112 self._checkInnerSchedule()
6114 def getDuration( self ):
6115 return self.duration
6117 def setDuration(self,hours=0,minutes=15,dur=0):
6118 if dur==0:
6119 dur = timedelta(hours=int(hours),minutes=int(minutes))
6120 if dur.seconds <= 0:
6121 raise MaKaCError( _("The duration cannot be less than zero"), _("Session"))
6122 self.duration = dur
6123 self.verifyEndDate(self.getEndDate())
6124 self.notifyModification()
6126 def getStartOnDay(self, day, tz=None):
6127 if not tz:
6128 tz = self.getConference().getTimezone()
6129 if type(day) is datetime:
6130 day = day.astimezone(timezone(tz))
6131 if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() :
6132 return None
6133 minTime = self.getEndDate()
6134 for e in self.getSchedule().getEntriesOnDay(day) :
6135 if e.getStartDate() < minTime :
6136 minTime = e.getStartDate()
6137 if minTime == self.getEndDate() :
6138 minTime = day.replace(hour=8, minute=0)#datetime.combine(day,time(hour=8, minute=0))
6139 if minTime < self.getStartDate() :
6140 return self.getStartDate()
6141 return minTime
6143 def getEndOnDay(self, day, tz=None):
6144 if not tz:
6145 tz = self.getConference().getTimezone()
6146 if type(day) is datetime:
6147 day = day.astimezone(timezone(tz))
6148 if day.date() < self.getStartDate().astimezone(timezone(tz)).date() or day.date() > self.getEndDate().astimezone(timezone(tz)).date() :
6149 return None
6150 maxTime = self.getStartDate();
6151 for e in self.getSchedule().getEntriesOnDay(day) :
6152 if e.getEndDate() > maxTime :
6153 maxTime = e.getEndDate()
6154 if maxTime == self.getStartDate() :
6155 maxTime = day.replace(hour=19, minute=0)#datetime.combine(day,time(19,0))
6156 if maxTime > self.getEndDate() :
6157 return self.getEndDate()
6158 return maxTime
6160 def getLocationParent( self ):
6162 Returns the object from which the room/location
6163 information should be inherited
6165 return self.getConference()
6167 def getLocationList(self):
6168 """Method returning a list of "location" objects which contain the
6169 information about the different places the conference is gonna
6170 happen
6172 return self.places
6174 def addLocation(self, newPlace):
6175 self.places.append( newPlace )
6176 self.notifyModification()
6178 def _resetConveners(self):
6179 try:
6180 if self._conveners:
6181 return
6182 except AttributeError:
6183 self._conveners=[]
6184 for oc in self.conveners:
6185 newConv=SessionChair()
6186 newConv.setDataFromAvatar(oc)
6187 self._addConvener(newConv)
6189 def getConvenerList(self):
6190 self._resetConveners()
6191 return self._conveners
6193 def getAllConvenerList(self):
6194 convenerList = set()
6195 for slot in self.getSlotList():
6196 for convener in slot.getConvenerList():
6197 convenerList.add(convener)
6198 return convenerList
6200 def _addConvener(self,newConv):
6201 if newConv in self._conveners:
6202 return
6203 try:
6204 if self._convenerGen:
6205 pass
6206 except AttributeError:
6207 self._convenerGen=Counter()
6208 id = newConv.getId()
6209 if id == "":
6210 id=int(self._convenerGen.newCount())
6211 newConv.includeInSession(self,id)
6212 self._conveners.append(newConv)
6213 self.notifyModification()
6215 def addConvener(self,newConv):
6216 self._resetConveners()
6217 self._addConvener(newConv)
6218 if isinstance(newConv, MaKaC.user.Avatar):
6219 conv.unlinkTo(self, "convener")
6221 def removeConvener(self,conv):
6222 self._resetConveners()
6223 if conv not in self._conveners:
6224 return
6225 #--Pending queue: remove pending Convener waiting to became manager if anything
6226 self.getConference().getPendingQueuesMgr().removePendingManager(conv)
6228 #--Pending queue: remove pending Convener waiting to became coordinator if anything
6229 self.getConference().getPendingQueuesMgr().removePendingCoordinator(conv)
6231 self._conveners.remove(conv)
6232 if isinstance(conv, MaKaC.user.Avatar):
6233 conv.linkTo(self, "convener")
6234 conv.delete()
6235 self.notifyModification()
6237 def recoverConvener(self, con):
6238 self.addConvener(con)
6239 con.recover()
6241 def getConvenerById(self,id):
6242 id=int(id)
6243 for conv in self._conveners:
6244 if conv.getId()==id:
6245 return conv
6246 return None
6248 def getConvenerText( self ):
6249 #to be removed
6250 try:
6251 if self.convenerText:
6252 pass
6253 except AttributeError, e:
6254 self.convenerText = ""
6255 return self.convenerText
6257 def setConvenerText( self, newText ):
6258 self.convenerText = newText.strip()
6260 def appendConvenerText( self, newText ):
6261 self.setConvenerText( "%s, %s"%(self.getConvenerText(), newText.strip()) )
6263 def addContribution(self, newContrib, id=None):
6264 """Registers the contribution passed as parameter within the session
6265 assigning it a unique id.
6267 if self.hasContribution(newContrib):
6268 return
6269 self.getConference().addContribution(newContrib,id)
6270 self.contributions[newContrib.getId()]=newContrib
6271 newContrib.setSession(self)
6273 self.updateNonInheritingChildren(newContrib)
6274 for child in newContrib.getAccessController().getNonInheritingChildren():
6275 self.updateNonInheritingChildren(child)
6277 self.notifyModification()
6279 def hasContribution(self,contrib):
6280 return contrib.getSession()==self and \
6281 self.contributions.has_key(contrib.getId())
6283 def removeContribution(self,contrib):
6284 """Removes the indicated contribution from the session
6286 if not self.hasContribution(contrib):
6287 return
6288 if contrib.isScheduled():
6289 # unschedule the contribution
6290 contrib._notify("contributionUnscheduled")
6291 sch=contrib.getSchEntry().getSchedule()
6292 sch.removeEntry(contrib.getSchEntry())
6293 del self.contributions[contrib.getId()]
6295 self.updateNonInheritingChildren(contrib, delete=True, propagate=False)
6296 for child in contrib.getAccessController().getNonInheritingChildren():
6297 self.updateNonInheritingChildren(child, delete=True, propagate=False)
6299 contrib.setSession(None)
6301 self.notifyModification()
6303 def newContribution( self, params = None, id=None ):
6304 c = Contribution()
6305 if params:
6306 c.setValues(params)
6307 self.addContribution( c, id )
6308 return c
6310 def getContributionById(self,id):
6311 id=str(id).strip()
6312 if self.contributions.has_key( id ):
6313 return self.contributions[ id ]
6314 return None
6316 def getContributionList( self ):
6317 return self.contributions.values()
6319 def getNumberOfContributions(self, only_scheduled=False):
6320 if only_scheduled:
6321 return len(filter(lambda c: c.isScheduled(), self.contributions.itervalues()))
6322 else:
6323 return len(self.contributions)
6325 def canIPAccess( self, ip ):
6326 if not self.__ac.canIPAccess( ip ):
6327 return False
6328 if self.getOwner() != None:
6329 return self.getOwner().canIPAccess(ip)
6330 return True
6332 def isProtected( self ):
6333 # tells if a session is protected or not
6334 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
6336 def getAccessProtectionLevel( self ):
6337 return self.__ac.getAccessProtectionLevel()
6339 def isItselfProtected( self ):
6340 return self.__ac.isItselfProtected()
6342 def hasAnyProtection( self ):
6343 """Tells whether a session has any kind of protection over it:
6344 access or domain protection.
6346 if self.__ac.isProtected():
6347 return True
6348 if self.getDomainList():
6349 return True
6350 if self.getAccessProtectionLevel() == -1:
6351 return False
6353 return self.getOwner().hasAnyProtection()
6355 def hasProtectedOwner( self ):
6356 if self.getOwner() != None:
6357 return self.getOwner().isProtected()
6358 return False
6360 def setProtection( self, private ):
6361 self.__ac.setProtection( private )
6362 self.notify_protection_to_owner(self)
6364 def grantAccess( self, prin ):
6365 self.__ac.grantAccess( prin )
6366 if isinstance(prin, MaKaC.user.Avatar):
6367 prin.linkTo(self, "access")
6369 def revokeAccess( self, prin ):
6370 self.__ac.revokeAccess( prin )
6371 if isinstance(prin, MaKaC.user.Avatar):
6372 prin.unlinkTo(self, "access")
6374 def canView( self, aw ):
6375 """tells whether the specified user has access to the current object
6376 or any of its sub-objects
6378 if self.canAccess( aw ):
6379 return True
6380 ### TODO: Replace this code when plugins allow extension points+notifications ##################
6381 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
6382 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
6383 RCCollaborationPluginAdmin.hasRights(user = aw.getUser(), plugins = "any"):
6384 return True
6385 ################################################################################################
6386 for contrib in self.getContributionList():
6387 if contrib.canView( aw ):
6388 return True
6389 return False
6391 def isAllowedToAccess( self, user ):
6392 if not user:
6393 return False
6394 if user in self.getCoordinatorList() or self.__ac.canUserAccess( user ) \
6395 or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess(user)):
6396 return True
6397 return False
6399 def canAccess( self, aw ):
6400 # Allow harvesters (Invenio, offline cache) to access
6401 # protected pages
6402 if self.__ac.isHarvesterIP(aw.getIP()):
6403 return True
6404 #####################################################
6406 if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ):
6407 return False
6408 if not self.isProtected():
6409 return True
6410 flag = self.isAllowedToAccess( aw.getUser() )
6411 return flag or self.conference.canKeyAccess( aw )
6413 def grantModification( self, sb, sendEmail=True ):
6414 if isinstance(sb, SessionChair) or isinstance(sb, SlotChair):
6415 ah = AvatarHolder()
6416 results=ah.match({"email":sb.getEmail()}, exact=1)
6417 r=None
6418 for i in results:
6419 if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]:
6421 break
6422 if r is not None and r.isActivated():
6423 self.__ac.grantModification( r )
6424 r.linkTo(self, "manager")
6425 elif sb.getEmail() != "":
6426 modificationEmailGranted = self.__ac.grantModificationEmail(sb.getEmail())
6427 if modificationEmailGranted and sendEmail:
6428 notif = pendingQueues._PendingManagerNotification( [sb] )
6429 mail.GenericMailer.sendAndLog( notif, self.getConference() )
6430 else:
6431 self.__ac.grantModification( sb )
6432 if isinstance(sb, MaKaC.user.Avatar):
6433 sb.linkTo(self, "manager")
6435 def revokeModification( self, prin ):
6436 self.__ac.revokeModification( prin )
6437 if isinstance(prin, MaKaC.user.Avatar):
6438 prin.unlinkTo(self, "manager")
6440 def canModify( self, aw ):
6441 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
6443 def canUserModify( self, av ):
6444 """Tells whether a user is allowed to modify the current session:
6445 only if the user is granted to modify the session or the user
6446 can modify the corresponding conference.
6448 return self.getConference().canUserModify( av ) or self.__ac.canModify( av )
6450 def getManagerList( self ):
6451 return self.__ac.getModifierList()
6453 def getAllowedToAccessList( self ):
6454 return self.__ac.getAccessList()
6456 def addMaterial( self, newMat ):
6457 newMat.setId( str(self.__materialGenerator.newCount()) )
6458 newMat.setOwner( self )
6459 self.materials[ newMat.getId() ] = newMat
6460 self.notifyModification()
6462 def removeMaterial( self, mat ):
6463 if mat.getId() in self.materials.keys():
6464 mat.delete()
6465 self.materials[mat.getId()].setOwner(None)
6466 del self.materials[ mat.getId() ]
6467 self.notifyModification()
6468 return "done: %s"%mat.getId()
6469 elif mat.getId().lower() == 'minutes':
6470 self.removeMinutes()
6471 return "done: %s"%mat.getId()
6472 return "not done: %s"%mat.getId()
6474 def recoverMaterial(self, recMat):
6475 # Id must already be set in recMat.
6476 recMat.setOwner( self )
6477 self.materials[ recMat.getId() ] = recMat
6478 recMat.recover()
6479 self.notifyModification()
6481 def getMaterialRegistry(self):
6483 Return the correct material registry for this type
6485 from MaKaC.webinterface.materialFactories import SessionMFRegistry
6486 return SessionMFRegistry
6488 def getMaterialById( self, matId ):
6489 if matId.lower() == 'minutes':
6490 return self.getMinutes()
6491 elif self.materials.has_key(matId):
6492 return self.materials[ matId ]
6493 return None
6495 def getMaterialList( self ):
6496 return self.materials.values()
6498 def getAllMaterialList(self, sort=True):
6499 l = self.getMaterialList()
6500 if self.getMinutes():
6501 l.append( self.getMinutes() )
6502 if sort:
6503 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
6504 return l
6506 def _setSchedule(self):
6507 self.__schedule=SessionSchedule(self)
6508 sl=self.getSlotList()
6509 for slot in self.getSlotList():
6510 self.__schedule.addEntry(slot.getSchEntry())
6512 def getSchedule( self ):
6513 try:
6514 if self.__schedule is None or not isinstance(self.__schedule,SessionSchedule):
6515 self._setSchedule()
6516 except AttributeError, e:
6517 self._setSchedule()
6518 return self.__schedule
6520 def getMasterSchedule( self ):
6521 return self.getOwner().getSchedule()
6523 def requireDomain( self, dom ):
6524 self.__ac.requireDomain( dom )
6526 def freeDomain( self, dom ):
6527 self.__ac.freeDomain( dom )
6529 def getDomainList( self ):
6530 return self.__ac.getRequiredDomainList()
6532 def setComments(self,comm):
6533 self._comments = comm.strip()
6535 def getComments(self):
6536 try:
6537 if self._comments:
6538 pass
6539 except AttributeError,e:
6540 self._comments=""
6541 return self._comments
6543 def createMinutes( self ):
6544 if self.getMinutes() != None:
6545 raise MaKaCError( _("The minutes for this session have already been created"), _("Session"))
6546 self.minutes = Minutes()
6547 self.minutes.setOwner( self )
6548 self.notifyModification()
6549 return self.minutes
6551 def removeMinutes( self ):
6552 if self.minutes is None:
6553 return
6554 self.minutes.delete()
6555 self.minutes.setOwner( None )
6556 self.minutes = None
6557 self.notifyModification()
6559 def recoverMinutes(self, min):
6560 self.removeMinutes() # To ensure that the current minutes are put in
6561 # the trash can.
6562 self.minutes = min
6563 self.minutes.setOwner( self )
6564 min.recover()
6565 self.notifyModification()
6566 return self.minutes
6568 def getMinutes( self ):
6569 #To be removed
6570 try:
6571 if self.minutes:
6572 pass
6573 except AttributeError, e:
6574 self.minutes = None
6576 return self.minutes
6578 def _addCoordinator(self, av):
6579 if av is None or self._coordinators.has_key(av.getId()):
6580 return
6581 self._coordinators[av.getId()]=av
6582 if self.getConference() is not None:
6583 self.getConference().addSessionCoordinator(self,av)
6585 def getCoordinatorEmailList(self):
6586 try:
6587 return self._coordinatorsEmail
6588 except:
6589 self._coordinatorsEmail = []
6590 return self._coordinatorsEmail
6592 def _addCoordinatorEmail(self, email):
6593 if not email in self.getCoordinatorEmailList():
6594 self.getCoordinatorEmailList().append(email)
6596 def removeCoordinatorEmail(self, email):
6597 if email in self.getCoordinatorEmailList():
6598 if email in self.getCoordinatorEmailList():
6599 self.getCoordinatorEmailList().remove(email)
6600 self._p_changed = 1
6602 def addCoordinator( self, sb, sendEmail=True ):
6603 """Grants coordination privileges to user.
6605 Arguments:
6606 sb -- It can be either:
6607 (MaKaC.user.Avatar) the user to which
6608 coordination privileges must be granted.
6610 (MaKaC.conference.SessionChair) a non-existing which
6611 has to become indico user before to be granted with privileges.
6613 try:
6614 if self._coordinators:
6615 pass
6616 except AttributeError, e:
6617 self._coordinators=OOBTree()
6619 if isinstance(sb, SessionChair):
6620 ah = AvatarHolder()
6621 results=ah.match({"email":sb.getEmail()}, exact=1)
6622 r=None
6624 for i in results:
6625 if sb.getEmail().lower().strip() in [j.lower().strip() for j in i.getEmails()]:
6627 break
6629 if r is not None and r.isActivated():
6631 self._addCoordinator(r)
6632 r.linkTo(self, "coordinator")
6633 else:
6634 self.getConference().getPendingQueuesMgr().addPendingCoordinator(sb)
6635 else:
6636 self._addCoordinator(sb)
6637 if isinstance(sb, MaKaC.user.Avatar):
6638 sb.linkTo(self, "coordinator")
6640 def removeCoordinator( self, av ):
6641 """Revokes coordination privileges to user.
6643 Arguments:
6644 av -- (MaKaC.user.Avatar) user for which coordination privileges
6645 must be revoked
6647 try:
6648 if self._coordinators:
6649 pass
6650 except AttributeError, e:
6651 self._coordinators=OOBTree()
6653 if av is None or not self._coordinators.has_key(av.getId()):
6654 return
6655 del self._coordinators[av.getId()]
6656 if isinstance(av, MaKaC.user.Avatar):
6657 av.unlinkTo(self, "coordinator")
6658 if self.getConference() is not None:
6659 self.getConference().removeSessionCoordinator(self,av)
6661 def isCoordinator( self, av ):
6662 """Tells whether the specified user is a coordinator of the session.
6664 Arguments:
6665 av -- (MaKaC.user.Avatar) user to be checked
6667 Return value: (boolean)
6669 try:
6670 if self._coordinators:
6671 pass
6672 except AttributeError, e:
6673 self._coordinators=OOBTree()
6674 if (av is not None) and self._coordinators.has_key(av.getId()):
6675 return True
6676 ret = False
6677 if isinstance(av, MaKaC.user.Avatar):
6678 for email in av.getEmails():
6679 if email in self.getCoordinatorEmailList():
6680 self.addCoordinator(av)
6681 self.removeCoordinatorEmail(email)
6682 ret = True
6683 return ret
6685 def hasConvenerByEmail(self, email):
6686 for convener in self.getConvenerList():
6687 if email == convener.getEmail():
6688 return True
6689 return False
6692 def getCoordinatorList( self ):
6693 """Return all users which have privileges to coordinate the session.
6695 Return value: (list)
6697 try:
6698 if self._coordinators:
6699 pass
6700 except AttributeError, e:
6701 self._coordinators=OOBTree()
6703 return self._coordinators.values()
6705 def canCoordinate(self,aw, right=""):
6706 """Tells if a user has coordination privileges.
6708 Only session coordinators have coordination privileges over a
6709 session.
6711 Params:
6712 aw -- (MaKaC.accessControl.AccessWrapper) User access
6713 information for which the coordination privileges must be
6714 checked.
6716 Return value: (boolean)
6718 if right != "":
6719 return self.isCoordinator(aw.getUser()) and self.getConference().hasSessionCoordinatorRight(right)
6720 return self.isCoordinator(aw.getUser())
6723 def getScheduleType(self):
6724 try:
6725 if self._ttType:
6726 pass
6727 except AttributeError:
6728 self._ttType=SlotSchTypeFactory.getDefaultId()
6729 return self._ttType
6731 def setScheduleType(self,t):
6732 try:
6733 if self._ttType:
6734 pass
6735 except AttributeError:
6736 self._ttType=SlotSchTypeFactory.getDefaultId()
6737 t=str(t).strip().lower()
6738 if t not in SlotSchTypeFactory.getIdList() or t==self._ttType:
6739 return
6740 self._ttType=t
6741 for slot in self.getSlotList():
6742 slot.setScheduleType(t)
6744 def getAccessController(self):
6745 return self.__ac
6748 def _cmpTitle( s1, s2 ):
6749 s1=s1.getTitle().lower().strip()
6750 s2=s2.getTitle().lower().strip()
6751 return cmp( s1, s2 )
6752 _cmpTitle=staticmethod(_cmpTitle)
6754 class SessionSlot(Persistent, Fossilizable, Locatable):
6756 fossilizes(ISessionSlotFossil)
6758 def __init__(self,session,**sessionSlotData):
6759 self.session = session
6760 self.id = "not assigned"
6761 self.title = ""
6762 self.startDate=None
6763 self.duration = timedelta(minutes=1)
6764 self.places = []
6765 self.rooms = []
6766 self._conveners = []
6767 self._convenerGen=Counter()
6768 self._schedule=SlotSchTypeFactory.getDefaultKlass()(self)
6769 self._sessionSchEntry=LinkedTimeSchEntry(self)
6770 self._confSchEntry=LinkedTimeSchEntry(self)
6771 self._contributionDuration = None
6773 def getTimezone( self ):
6774 return self.getConference().getTimezone()
6776 def getLogInfo(self):
6777 data = {}
6778 data["id"] = self.id
6779 data["title"] = self.title
6780 data["session"] = self.session.getTitle()
6781 data["start date"] = self.startDate
6782 data["duration"] = self.duration
6783 i = 0
6784 for p in self.places :
6785 data["place %s"%i] = p.getName()
6786 i+=1
6787 i = 0
6788 for r in self.rooms :
6789 data["room %s"%i] = r.getName()
6790 i+=1
6791 for c in self._conveners :
6792 data["convener %s"%c.getId()] = c.getFullName()
6793 return data
6795 def clone(self,session, options):
6797 slot = SessionSlot(session)
6798 slot.session = session
6799 slot.setTitle(self.getTitle())
6800 timeDifference = session.getConference().getStartDate() - self.getSession().getConference().getStartDate()
6801 slot.setStartDate(self.getStartDate() + timeDifference)
6802 slot.setDuration(dur=self.getDuration(), check=2)
6804 #places
6805 if self.getOwnLocation() is not None:
6806 slot.setLocation(self.getOwnLocation().clone())
6807 #rooms
6808 if self.getOwnRoom() is not None:
6809 slot.setRoom(self.getOwnRoom().clone())
6811 #chairs = conveners
6812 for ch in self.getOwnConvenerList() :
6813 slot.addConvener(ch.clone())
6815 #populate the timetable
6816 if options.get("contributions", False) :
6817 for entry in self.getEntries() :
6818 if isinstance(entry, BreakTimeSchEntry) :
6819 newentry = entry.clone(slot)
6820 slot.getSchedule().addEntry(newentry,0)
6821 elif isinstance(entry, ContribSchEntry) :
6822 contrib = entry.getOwner()
6823 newcontrib = contrib.clone(session, options, timeDifference)
6824 slot.getSchedule().addEntry(newcontrib.getSchEntry(),0)
6825 ContextManager.setdefault("clone.unique_id_map", {})[contrib.getUniqueId()] = newcontrib.getUniqueId()
6827 slot.setContribDuration(0, 0, self.getContribDuration())
6828 slot.notifyModification(cleanCache = False)
6830 return slot
6832 def fit( self ):
6834 sets the start date of the slot to the start date of the first son
6835 and the end date to the end date of the last son
6837 sch = self.getSchedule()
6838 entries = sch.getEntries()
6839 if len(entries) > 0:
6840 self.setStartDate(entries[0].getStartDate(),0,0)
6841 self.setEndDate(sch.calculateEndDate(), check=0)
6843 def recalculateTimes( self, type, diff ):
6845 recalculate and reschedule the contributions of the session slot with a time "diff" of separation.
6847 if type=="duration":
6848 entries = self.getSchedule().getEntries()[:]
6850 while i<len(entries):
6851 entry=entries[i]
6852 if i+1 == len(entries):
6853 dur=self.getEndDate()-entry.getStartDate()
6854 else:
6855 nextentry=entries[i+1]
6856 dur=nextentry.getStartDate()-entry.getStartDate()-diff
6857 if dur<timedelta(0):
6858 raise EntryTimingError( _("""With the time between entries you've chosen, the entry "%s" will have a duration less than zero minutes. Please, choose another time""")%entry.getTitle())
6859 entry.setDuration(dur=dur)
6860 i+=1
6861 if len(entries) != 0 and self.getEndDate() < entry.getEndDate():
6862 self.setEndDate(entry.getEndDate(),2)
6863 elif type=="startingTime":
6864 st = self.getStartDate()
6865 entries = self.getSchedule().getEntries()[:]
6866 for entry in entries:
6867 entry.setStartDate(st,0,0)
6868 # add diff to last item end date if and only if the item is
6869 # not a break
6870 #if not isinstance(entry, BreakTimeSchEntry):
6871 # st=entry.getEndDate()+diff
6872 #else:
6873 # st=entry.getEndDate()
6874 st=entry.getEndDate()+diff
6875 if len(entries) != 0 and self.getEndDate() < st:
6876 self.setEndDate(st,2)
6878 def setValues(self,data,check=2, moveEntriesBelow=0):
6879 """check parameter:
6880 0: no check at all
6881 1: check and raise error in case of problem
6882 2: check and adapt the owner dates
6885 # In order to move the entries below, it is needed to know the diff (we have to move them)
6886 # and the list of entries to move. It's is needed to take those datas in advance because they
6887 # are going to be modified before the moving.
6888 if moveEntriesBelow == 1:
6889 oldStartDate=copy.copy(self.getStartDate())
6890 oldDuration=copy.copy(self.getDuration())
6891 i=self.getConfSchEntry().getSchedule().getEntries().index(self.getConfSchEntry())+1
6892 entriesList = self.getConfSchEntry().getSchedule().getEntries()[i:]
6893 self.title=data.get("title", "NO TITLE ASSIGNED")
6894 # Do we move all entries in the slot
6895 move = int(data.get("move",0))
6897 if "locationName" in data:
6898 loc = self.getOwnLocation()
6899 if not loc:
6900 loc = CustomLocation()
6901 self.setLocation( loc )
6902 loc.setName( data["locationName"] )
6903 loc.setAddress( data.get("locationAddress", "") )
6904 else:
6905 self.setLocation( None )
6907 if "roomName" in data:
6908 room = self.getOwnRoom()
6909 if not room:
6910 room = CustomRoom()
6911 self.setRoom( room )
6912 room.setName( data["roomName"] )
6913 else:
6914 self.setRoom( None )
6915 sDate = eDate = None
6916 confTZ = self.getOwner().getConference().getTimezone()
6917 if data.get("sDate",None) is not None:
6918 sd = data.get("sDate")
6919 sDate = timezone(confTZ).localize(datetime(sd.year,sd.month,sd.day,sd.hour,sd.minute))
6920 elif data.get("sYear","")!="" and data.get("sMonth","")!="" and \
6921 data.get("sDay","")!="" and data.get("sHour","")!="" and \
6922 data.get("sMinute","")!="":
6923 sDate = timezone(confTZ).localize(datetime(int(data["sYear"]),int(data["sMonth"]),
6924 int(data["sDay"]),int(data["sHour"]),
6925 int(data["sMinute"])))
6926 if data.get("eDate",None) is not None:
6927 ed = data.get("eDate")
6928 eDate = timezone(confTZ).localize(datetime(ed.year,ed.month,ed.day,ed.hour,ed.minute))
6929 elif data.get("eYear","")!="" and data.get("eMonth","")!="" and \
6930 data.get("eDay","")!="" and data.get("eHour","")!="" and \
6931 data.get("eMinute","")!="":
6932 eDate = timezone(confTZ).localize(datetime(int(data["eYear"]),int(data["eMonth"]),
6933 int(data["eDay"]),int(data["eHour"]),
6934 int(data["eMinute"])))
6935 if sDate != None and eDate != None:
6936 sDateUTC = sDate.astimezone(timezone('UTC'))
6937 eDateUTC = eDate.astimezone(timezone('UTC'))
6938 self.setDates(sDateUTC,eDateUTC,check,moveEntries=move)
6939 elif sDate != None:
6940 sDateUTC = sDate.astimezone(timezone('UTC'))
6941 self.setStartDate(sDateUTC,check,moveEntries=move)
6942 if data.get("durHours","")!="" and data.get("durMins","")!="":
6943 self.setDuration(hours=data["durHours"],minutes=data["durMins"],check=check)
6944 if data.get("contribDurHours","")!="" and data.get("contribDurMins","")!="":
6945 self.setContribDuration(int(data["contribDurHours"]),int(data["contribDurMins"]))
6946 elif data.get("contribDuration","")!="":
6947 self.setContribDuration(dur=data.get("contribDuration"))
6948 else:
6949 self.setContribDuration(None,None)
6950 conveners = data.get("conveners",None)
6951 if conveners is not None:
6952 self.clearConvenerList()
6953 for conv in conveners:
6954 sc = SlotChair()
6955 sc.setTitle(conv.getTitle())
6956 sc.setFirstName(conv.getFirstName())
6957 sc.setFamilyName(conv.getFamilyName())
6958 sc.setAffiliation(conv.getAffiliation())
6959 sc.setEmail(conv.getEmail())
6960 self.addConvener(sc)
6961 if moveEntriesBelow == 1:
6962 diff = (self.getStartDate() - oldStartDate) + (self.getDuration() - oldDuration)
6963 self.getSchedule().moveEntriesBelow(diff, entriesList)
6964 self._checkInnerSchedule()
6965 self.notifyModification()
6967 def _checkInnerSchedule( self ):
6968 self.getSchedule().checkSanity()
6970 def setContribDuration(self, hour=0, min=0, dur=None):
6971 self._contributionDuration = None
6972 if dur is not None:
6973 self._contributionDuration=dur
6974 elif hour != None and min != None:
6975 self._contributionDuration = timedelta(hours=hour,minutes=min)
6977 def getContribDuration(self):
6979 Duration by default for contributions within the slots.
6981 try:
6982 if self._contributionDuration:
6983 pass
6984 except AttributeError, e:
6985 self._contributionDuration = None
6986 return self._contributionDuration
6988 def notifyModification( self, cleanCache = True, cleanCacheEntries = False):
6989 self.getSession().notifyModification(cleanCache = False)
6990 if cleanCache:
6991 self.cleanCache(cleanCacheEntries)
6992 self._p_changed = 1
6994 def cleanCache(self, cleanCacheEntries = False):
6995 if not ContextManager.get('clean%s'%self.getUniqueId(), False):
6996 ScheduleToJson.cleanCache(self)
6997 ContextManager.set('clean%s'%self.getUniqueId(), True)
6998 if cleanCacheEntries:
6999 for entry in self.getSchedule().getEntries():
7000 entry.getOwner().cleanCache(cleanConference = False)
7002 def getLocator( self ):
7003 l=self.getSession().getLocator()
7004 l["slotId"]=self.getId()
7005 return l
7007 def getConference( self ):
7008 return self.getSession().getConference()
7010 def getSession(self):
7011 return self.session
7013 def getOwner( self ):
7014 return self.session
7016 def _setSchedule(self,klass):
7017 old_sch=self.getSchedule()
7018 self._schedule=klass(self)
7019 #after removing old entries, one could try to fit them into the new
7020 # schedule, but there are several things to consider which are left
7021 # for later implementation (breaks, entries not fitting in the
7022 # slots,...)
7023 while len(old_sch.getEntries())>0:
7024 entry=old_sch.getEntries()[0]
7025 old_sch.removeEntry(entry)
7026 self.notifyModification()
7028 def getSchedule(self):
7029 return self._schedule
7031 def getMasterSchedule( self ):
7032 return self.getOwner().getSchedule()
7034 def getConfSchEntry( self ):
7035 try:
7036 if self._confSchEntry:
7037 pass
7038 except AttributeError:
7039 self._confSchEntry=LinkedTimeSchEntry(self)
7040 return self._confSchEntry
7042 def getSessionSchEntry( self ):
7043 try:
7044 if self._sessionSchEntry:
7045 pass
7046 except AttributeError:
7047 self._sessionSchEntry=self._schEntry
7048 return self._sessionSchEntry
7050 def setId( self, newId ):
7051 self.id=str(newId)
7052 self.notifyModification()
7054 def getId( self ):
7055 return self.id
7057 def getUniqueId( self ):
7058 """Returns (string) the unique identiffier of the item.
7059 Used mainly in the web session access key table"""
7060 return "%sl%s" % (self.getSession().getUniqueId(),self.id)
7062 def setTitle( self, newTitle ):
7063 self.title=newTitle
7064 self.notifyModification()
7066 def getTitle( self ):
7067 try:
7068 if self.title:
7069 pass
7070 except AttributeError,e:
7071 self.title=""
7072 return self.title
7074 def getFullTitle( self ):
7075 return self.getSession().getTitle() + (": " + self.getTitle() if self.getTitle() else "")
7077 def getName(self):
7078 return "slot %s"%self.getId()
7080 def getDescription(self):
7081 return self.getSession().getDescription()
7083 def setDates(self,sDate,eDate,check=2,moveEntries=0):
7084 """check parameter:
7085 0: no check at all
7086 1: check and raise error in case of problem
7087 2: check and adapt the owner dates"""
7089 if sDate>eDate:
7090 raise MaKaCError(_("End date cannot be prior to Start date"),_("Slot"))
7092 self.setStartDate(sDate, check, moveEntries, checkDuration=False)
7093 self.setDuration(0, 0, 0, eDate-sDate, check)
7094 self.notifyModification()
7096 def getEntries(self):
7097 entriesList = self.getSchedule().getEntries()
7098 return entriesList
7100 def move(self, sDate):
7101 diff=sDate-self.startDate
7102 self.startDate = sDate
7103 for slotEntry in self.getSchedule().getEntries():
7104 if isinstance(slotEntry, BreakTimeSchEntry):
7105 slotEntry.startDate = slotEntry.getStartDate() + diff
7106 else:
7107 se = slotEntry.getOwner()
7108 se.startDate = se.getStartDate() + diff
7109 self.getSchedule().reSchedule()
7111 def verifyStartDate(self, sDate,check=2):
7112 """check parameter:
7113 0: no check at all
7114 1: check and raise error in case of problem
7115 2: check and adapt the owner dates"""
7117 tz = timezone(self.getConference().getTimezone())
7119 if sDate < self.getSession().getStartDate():
7120 if check == 1:
7121 raise ParentTimingError(_("The slot \"%s\" cannot start (%s) before its parent session starts (%s)")%\
7122 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7123 self.getSession().getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7124 _("Slot"))
7125 elif check == 2:
7126 self.getSession().setStartDate(sDate, check, 0)
7128 def setStartDate(self,sDate,check=2,moveEntries=0,checkDuration=True):
7129 """check parameter:
7130 0: no check at all
7131 1: check and raise error in case of problem
7132 2: check and adapt the owner dates"""
7133 if sDate is None:
7134 return
7135 if not sDate.tzname():
7136 raise MaKaCError("date should be timezone aware")
7137 if check != 0:
7138 #If not using .fit() at the end of this method, comment it out
7139 #if self.getSession().getStartDate() > sDate:
7140 # self.getSession().duration += self.getSession().getStartDate() - sDate
7141 self.verifyStartDate(sDate,check)
7143 # calculate the difference betwwen old and new date
7144 difference = None
7145 if self.startDate is not None:
7146 difference = sDate - self.getStartDate()
7148 self.startDate=copy.copy(sDate)
7150 if difference != None and difference != timedelta(0) and moveEntries:
7151 ContextManager.get('autoOps').append((self, "ENTRIES_MOVED",
7152 self, sDate.astimezone(timezone(self.getTimezone()))))
7153 self.getSchedule().moveEntriesBelow(difference,self.getSchedule().getEntries()[:])
7155 if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getStartDate() != sDate:
7156 self.getSession().setStartDate(sDate, check, 0)
7157 if check != 0 and self.getSession() and checkDuration:
7158 self.verifyDuration(self.getDuration(), check=check)
7160 # synchronize with other timetables
7161 self.getSessionSchEntry().synchro()
7162 self.getConfSchEntry().synchro()
7163 self.getSession().fit()
7164 self.notifyModification()
7166 def setEndDate(self,eDate,check=2):
7167 if not eDate.tzname():
7168 raise MaKaCError("date should be timezone aware")
7169 if check != 0:
7170 self.verifyDuration(eDate-self.startDate, check)
7171 self.setDuration(dur=eDate-self.startDate,check=check)
7172 if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSession().getEndDate() != eDate:
7173 self.getSession().setEndDate(eDate, check)
7174 self.getSession().fit()
7175 self.notifyModification()
7177 def getStartDate( self ):
7178 return self.startDate
7180 def getAdjustedStartDate(self,tz=None):
7181 if not tz:
7182 tz = self.getConference().getTimezone()
7183 if tz not in all_timezones:
7184 tz = 'UTC'
7185 return self.startDate.astimezone(timezone(tz))
7187 def getEndDate( self ):
7188 if self.startDate is None:
7189 return None
7190 return self.startDate+self.duration
7192 def getAdjustedEndDate( self, tz=None ):
7193 if not tz:
7194 tz = self.getConference().getTimezone()
7195 if tz not in all_timezones:
7196 tz = 'UTC'
7197 if self.getEndDate():
7198 return self.getEndDate().astimezone(timezone(tz))
7199 return None
7201 def getDuration( self ):
7202 return self.duration
7204 def isMoreThanDay(self):
7205 if self.getDuration() >= timedelta(days=1):
7206 return True
7207 return False
7209 def verifyDuration(self, dur, check=1):
7210 """check parameter:
7211 0: no check at all
7212 1: check and raise error in case of problem
7213 2: check and adapt the owner dates"""
7215 tz = timezone(self.getConference().getTimezone())
7216 if dur <= timedelta(0):
7217 raise MaKaCError( _("The duration cannot be less than zero"), _("Slot"))
7218 if dur.days > 1:
7219 raise MaKaCError( _("The duration cannot be more than one day"), _("Slot"))
7220 if self.startDate is not None:
7221 sessionStartDate = self.getSession().getStartDate()
7222 sessionEndDate = self.getSession().getEndDate()
7223 # end date has to be between the session dates
7224 eDate = self.startDate + dur
7225 if eDate > sessionEndDate:
7226 if check==1:
7227 raise EntryTimingError(_("The session slot cannot end (%s) after its parent session (%s)") \
7228 % (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7229 sessionEndDate.astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7230 _("Slot"))
7231 elif check==2:
7232 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
7233 self.getSession(), eDate.astimezone(tz)))
7234 self.getSession().setEndDate(eDate,check)
7235 if eDate.astimezone(tz).date() > self.startDate.astimezone(tz).date():
7236 raise TimingError( _("The time slot must end on the same day it has started"), _("Slot"))
7237 # do not modify if slot entries will be affected
7238 sch = self.getSchedule()
7239 entries = sch.getEntries()
7240 if entries != []:
7241 if eDate < sch.calculateEndDate():
7242 raise TimingError(_("The session slot cannot end at (%s) because there is a contribution (%s) ending after that time. ")%\
7243 (eDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
7244 sch.calculateEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
7245 _("Slot"))
7247 def setDuration(self, days=0,hours=0,minutes=0,dur=0,check=1):
7248 """check parameter:
7249 0: no check at all
7250 1: check and raise error in case of problem
7251 2: check and adapt the owner dates"""
7253 if dur==0:
7254 dur = timedelta(days=int(days),hours=int(hours),minutes=int(minutes))
7255 if dur==0 and check==2:
7256 ContextManager.get('autoOps').append((self, "DURATION_SET",
7257 self, 1))
7258 dur = timedelta(minutes=1)
7259 if dur > timedelta(days=1) and check==2:
7260 pass#dur = timedelta(days=1)
7261 if check != 0:
7262 self.verifyDuration(dur, check)
7263 self.duration = dur
7264 self.getSessionSchEntry().synchro()
7265 self.getConfSchEntry().synchro()
7266 self.getSession().fit()
7267 self.notifyModification()
7269 def getLocationParent( self ):
7271 Returns the object from which the room/location
7272 information should be inherited
7274 return self.session.conference
7276 def delete(self):
7277 self.getSchedule().clear()
7278 if self.getSession() is not None:
7279 self.getSession().removeSlot(self)
7280 self.session=None
7281 TrashCanManager().add(self)
7283 def recover(self):
7284 TrashCanManager().remove(self)
7286 def getAccessController( self ):
7287 return self.getSession().getAccessController()
7289 def canAccess(self,aw):
7290 return self.getSession().canAccess(aw)
7292 def canView(self,aw):
7293 return self.getSession().canView(aw)
7295 def isProtected(self):
7296 return self.getSession().isProtected()
7298 def getAccessKey( self ):
7299 return self.getSession().getAccessKey()
7301 def setScheduleType(self,id):
7302 id=str(id).strip().lower()
7303 currentId=SlotSchTypeFactory.getId(self.getSchedule())
7304 if id not in SlotSchTypeFactory.getIdList() or id==currentId:
7305 return
7306 self._setSchedule(SlotSchTypeFactory.getScheduleKlass(id))
7308 def getConvenerList(self):
7309 try:
7310 if self._conveners:
7311 pass
7312 except AttributeError:
7313 self._conveners = []
7314 if self._conveners == []:
7315 return self.getSession().getConvenerList()
7316 return self._conveners
7318 def addConvener(self,newConv):
7319 if newConv in self._conveners:
7320 return
7321 try:
7322 if self._convenerGen:
7323 pass
7324 except AttributeError:
7325 self._convenerGen=Counter()
7326 id = newConv.getId()
7327 if id == "":
7328 id=int(self._convenerGen.newCount())
7329 newConv.includeInSlot(self,id)
7330 self._conveners.append(newConv)
7331 self.notifyModification()
7333 def removeConvener(self,conv):
7334 if conv not in self._conveners:
7335 return
7336 self._conveners.remove(conv)
7337 conv.delete()
7338 self.notifyModification()
7340 def recoverConvener(self, con):
7341 self.addConvener(con)
7342 con.recover()
7344 def getConvenerById(self,id):
7345 id=int(id)
7346 for conv in self._conveners:
7347 if conv.getId()==id:
7348 return conv
7349 return None
7351 def getOwnConvenerList(self):
7352 try:
7353 if self._conveners:
7354 pass
7355 except AttributeError:
7356 self._conveners = []
7357 return self._conveners
7359 def clearConvenerList(self):
7360 while len(self.getOwnConvenerList()) > 0:
7361 self._conveners.pop()
7362 self.notifyModification()
7364 def getColor(self):
7365 res=""
7366 if self.getSession() is not None:
7367 res=self.getSession().getColor()
7368 return res
7370 def getTextColor(self):
7371 res=""
7372 if self.getSession() is not None:
7373 res=self.getSession().getTextColor()
7374 return res
7376 def getAllMaterialList(self, sort=True):
7377 return self.getSession().getAllMaterialList(sort=sort)
7380 class ContributionParticipation(Persistent, Fossilizable):
7382 fossilizes(IContributionParticipationFossil, IContributionParticipationMinimalFossil,\
7383 IContributionParticipationTTDisplayFossil,\
7384 IContributionParticipationTTMgmtFossil)
7386 def __init__( self ):
7387 self._contrib = None
7388 self._id = ""
7389 self._firstName = ""
7390 self._surName = ""
7391 self._email = ""
7392 self._affiliation = ""
7393 self._address = ""
7394 self._phone = ""
7395 self._title = ""
7396 self._fax = ""
7398 def _notifyModification( self ):
7399 if self._contrib != None:
7400 self._contrib.notifyModification()
7402 def setValues(self, data):
7403 self.setFirstName(data.get("firstName", ""))
7404 self.setFamilyName(data.get("familyName",""))
7405 self.setAffiliation(data.get("affilation",""))
7406 self.setAddress(data.get("address",""))
7407 self.setEmail(data.get("email",""))
7408 self.setFax(data.get("fax",""))
7409 self.setTitle(data.get("title",""))
7410 self.setPhone(data.get("phone",""))
7411 self._notifyModification()
7413 def getValues(self):
7414 data={}
7415 data["firstName"]=self.getFirstName()
7416 data["familyName"]=self.getFamilyName()
7417 data["affilation"]=self.getAffiliation()
7418 data["address"]=self.getAddress()
7419 data["email"]=self.getEmail()
7420 data["fax"]=self.getFax()
7421 data["title"]=self.getTitle()
7422 data["phone"]=self.getPhone()
7423 return data
7425 def clone(self):
7426 part = ContributionParticipation()
7427 part.setValues(self.getValues())
7428 return part
7430 def setDataFromAvatar(self,av):
7431 # av is an Avatar object.
7432 if av is None:
7433 return
7434 self.setFirstName(av.getName())
7435 self.setFamilyName(av.getSurName())
7436 self.setEmail(av.getEmail())
7437 self.setAffiliation(av.getOrganisation())
7438 self.setAddress(av.getAddress())
7439 self.setPhone(av.getTelephone())
7440 self.setTitle(av.getTitle())
7441 self.setFax(av.getFax())
7442 self._notifyModification()
7444 def setDataFromOtherCP(self,cp):
7445 # cp is a ContributionParticipation object.
7446 if cp is None:
7447 return
7448 self.setFirstName(cp.getFirstName())
7449 self.setFamilyName(cp.getFamilyName())
7450 self.setEmail(cp.getEmail())
7451 self.setAffiliation(cp.getAffiliation())
7452 self.setAddress(cp.getAddress())
7453 self.setPhone(cp.getPhone())
7454 self.setTitle(cp.getTitle())
7455 self.setFax(cp.getFax())
7456 self._notifyModification()
7458 def includeInContribution( self, contrib, id ):
7459 if self.getContribution() == contrib and self.getId()==id.strip():
7460 return
7461 self._contrib = contrib
7462 self._id = id
7464 def delete( self ):
7465 self._contrib = None
7466 TrashCanManager().add(self)
7468 def recover(self):
7469 TrashCanManager().remove(self)
7471 def setId(self, newId):
7472 self._id = newId
7474 def getId( self ):
7475 return self._id
7477 def getContribution( self ):
7478 return self._contrib
7480 def getConference(self):
7481 return self._contrib.getConference()
7483 def getLocator(self):
7484 if self.getContribution() is None:
7485 return None
7486 loc=self.getContribution().getLocator()
7487 loc["authId"]=self.getId()
7488 return loc
7490 def _unindex(self):
7491 contrib=self.getContribution()
7492 if contrib is not None:
7493 conf=contrib.getConference()
7494 if conf is not None:
7495 conf.unindexAuthor(self)
7496 conf.unindexSpeaker(self)
7498 def _index(self):
7499 contrib=self.getContribution()
7500 if contrib is not None:
7501 conf=contrib.getConference()
7502 if conf is not None:
7503 conf.indexAuthor(self)
7504 conf.indexSpeaker(self)
7506 @Updates ('MaKaC.conference.ContributionParticipation', 'firstName')
7507 def setFirstName( self, newName ):
7508 tmp=newName.strip()
7509 if tmp==self._firstName:
7510 return
7511 self._unindex()
7512 self._firstName=tmp
7513 self._index()
7514 self._notifyModification()
7516 def getFirstName( self ):
7517 return self._firstName
7519 def getName( self ):
7520 return self._firstName
7523 @Updates ('MaKaC.conference.ContributionParticipation', 'familyName')
7524 def setFamilyName( self, newName ):
7525 tmp=newName.strip()
7526 if tmp==self._surName:
7527 return
7528 self._unindex()
7529 self._surName=tmp
7530 self._index()
7531 self._notifyModification()
7533 def getFamilyName( self ):
7534 return self._surName
7536 def getSurName( self ):
7537 return self._surName
7540 @Updates ('MaKaC.conference.ContributionParticipation', 'email')
7541 def setEmail( self, newMail ):
7542 tmp=newMail.strip()
7543 if tmp==self._email:
7544 return
7545 self._unindex()
7546 self._email=newMail.strip()
7547 self._index()
7548 self._notifyModification()
7550 def getEmail( self ):
7551 return self._email
7553 @Updates ('MaKaC.conference.ContributionParticipation', 'affiliation')
7554 def setAffiliation( self, newAffil ):
7555 self._affiliation = newAffil.strip()
7556 self._notifyModification()
7558 def getAffiliation( self ):
7559 if self._affiliation.lower() == "unknown":
7560 return ""
7561 return self._affiliation
7563 @Updates ('MaKaC.conference.ContributionParticipation', 'address')
7564 def setAddress( self, newAddr ):
7565 self._address = newAddr.strip()
7566 self._notifyModification()
7568 def getAddress( self ):
7569 return self._address
7571 @Updates ('MaKaC.conference.ContributionParticipation', 'telephone')
7572 def setPhone( self, newPhone ):
7573 self._phone = newPhone.strip()
7574 self._notifyModification()
7576 def getPhone( self ):
7577 return self._phone
7579 @Updates ('MaKaC.conference.ContributionParticipation', 'title')
7580 def setTitle( self, newTitle ):
7581 self._title = newTitle.strip()
7582 self._notifyModification()
7584 def getTitle( self ):
7585 return self._title
7587 @Updates ('MaKaC.conference.ContributionParticipation', 'fax')
7588 def setFax( self, newFax ):
7589 self._fax = newFax.strip()
7590 self._notifyModification()
7592 def getFax( self ):
7593 try:
7594 if self._fax:
7595 pass
7596 except AttributeError:
7597 self._fax=""
7598 return self._fax
7600 def getDirectFullName( self ):
7601 res = self.getDirectFullNameNoTitle()
7602 if self.getTitle() != "":
7603 res = "%s %s"%( self.getTitle(), res )
7604 return res
7606 def getDirectFullNameNoTitle( self, upper = True ):
7607 return ("%s %s"%(self.getFirstName(), self.getFamilyName().upper() if upper else self.getFamilyName())).strip()
7609 def getFullName( self ):
7610 res = self.getFullNameNoTitle()
7611 if self.getTitle() != "":
7612 res = "%s %s"%( self.getTitle(), res )
7613 return res
7615 def getFullNameNoTitle( self ):
7616 res = self.getFamilyName().decode('utf-8').upper().encode('utf-8')
7617 if self.getFirstName() != "":
7618 if res.strip() != "":
7619 res = "%s, %s"%( res, self.getFirstName() )
7620 else:
7621 res = self.getFirstName()
7622 return res
7624 def getAbrName(self):
7625 res = self.getFamilyName()
7626 if self.getFirstName() != "":
7627 if res != "":
7628 res = "%s, "%res
7629 res = "%s%s."%(res, self.getFirstName()[0].upper())
7630 return res
7632 def isSubmitter(self):
7633 if self.getContribution() is None:
7634 return False
7635 return self.getContribution().canUserSubmit(self)
7637 def isPendingSubmitter(self):
7638 if self.getContribution() is None:
7639 return False
7640 if self.getContribution().getConference() is None:
7641 return False
7642 return self.getContribution().getConference().getPendingQueuesMgr().isPendingSubmitter(self)
7644 def _cmpFamilyName( cp1, cp2 ):
7645 o1 = "%s %s"%(cp1.getFamilyName(), cp1.getFirstName())
7646 o2 = "%s %s"%(cp2.getFamilyName(), cp2.getFirstName())
7647 o1=o1.lower().strip()
7648 o2=o2.lower().strip()
7649 return cmp( o1, o2 )
7650 _cmpFamilyName=staticmethod(_cmpFamilyName)
7653 class AuthorIndex(Persistent):
7655 def __init__(self):
7656 self._idx=OOBTree()
7658 def _getKey(self,author):
7659 k = "%s %s %s"%(author.getFamilyName().lower(),author.getFirstName().lower(),author.getEmail().lower())
7660 return k.strip()
7662 def index(self,author):
7663 key=self._getKey(author)
7664 if not self._idx.has_key(key):
7665 self._idx[key]=[]
7666 l = self._idx[key]
7667 l.append(author)
7668 self._idx[key] = l
7669 self.notifyModification()
7671 def unindex(self,author):
7672 key=self._getKey(author)
7673 if self._idx.has_key(key):
7674 if author in self._idx[key]:
7675 l = self._idx[key]
7676 l.remove(author)
7677 self._idx[key] = l
7678 if len(self._idx[key])<=0:
7679 del self._idx[key]
7680 self.notifyModification()
7682 def getParticipations(self):
7683 return self._idx.values()
7685 def getById(self, id):
7686 return self._idx.get(id,None)
7688 def getByAuthorObj(self, auth):
7689 return self.getById(self._getKey(auth))
7691 def getParticipationKeys(self):
7692 return self._idx.keys()
7694 def notifyModification(self):
7695 self._idx._p_changed = 1
7696 self._p_changed = 1
7698 def iteritems(self):
7699 return self._idx.iteritems()
7701 def match(self, criteria, exact=0):
7702 self._options = ['organisation', 'surName', 'name', 'email']
7703 l = []
7704 for item in self.getParticipations():
7705 if len(item)>0:
7706 ok = []
7707 for f,v in criteria.items():
7708 if f == 'organisation' and v != '':
7709 if (exact == 0 and item[0].getAffiliation().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getAffiliation().lower() != v.lower()):
7710 ok.append(False)
7711 else:
7712 ok.append(True)
7713 if f == 'surName' and v!= '':
7714 if (exact == 0 and item[0].getSurName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getSurName().lower() != v.lower()):
7715 ok.append(False)
7716 else:
7717 ok.append(True)
7718 if f == 'name' and v!= '':
7719 if (exact == 0 and item[0].getName().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getName().lower() != v.lower()):
7720 ok.append(False)
7721 else:
7722 ok.append(True)
7723 if f == 'email' and v!= '':
7724 if (exact == 0 and item[0].getEmail().lower().find(v.lower()) == -1) or (exact == 1 and item[0].getEmail().lower() != v.lower()):
7725 ok.append(False)
7726 else:
7727 ok.append(True)
7728 if len(ok) > 0 and not False in ok:
7729 l.append(item[0])
7730 return l
7732 class _AuthIdx(Persistent):
7734 def __init__(self,conf):
7735 self._conf=conf
7736 self._idx=OOBTree()
7738 def _getKey(self,auth):
7739 return "%s %s"%(auth.getFamilyName().lower(),auth.getFirstName().lower())
7741 def index(self,auth):
7742 if auth.getContribution() is None:
7743 raise MaKaCError( _("Cannot index an author of a contribution which has not been included in a Conference"), _("Author Index"))
7744 if auth.getContribution().getConference()!=self._conf:
7745 raise MaKaCError( _("cannot index an author of a contribution which does not belong to this Conference"), _("Author Index"))
7746 key=self._getKey(auth)
7747 contribId=str(auth.getContribution().getId())
7748 if not self._idx.has_key(key):
7749 self._idx[key]=OIBTree()
7750 if not self._idx[key].has_key(contribId):
7751 self._idx[key][contribId]=0
7752 self._idx[key][contribId]+=1
7754 def unindex(self,auth):
7755 if auth.getContribution() is None:
7756 raise MaKaCError( _("Cannot unindex an author of a contribution which is not included in a conference"), _("Author Index"))
7757 if auth.getContribution().getConference()!=self._conf:
7758 raise MaKaCError( _("Cannot unindex an author of a contribution which does not belong to this conference"), _("Author Index"))
7759 key=self._getKey(auth)
7760 if not self._idx.has_key(key):
7761 return
7762 contribId=str(auth.getContribution().getId())
7763 self._idx[key][contribId]-=1
7764 if self._idx[key][contribId]<=0:
7765 del self._idx[key][contribId]
7766 if len(self._idx[key])<=0:
7767 del self._idx[key]
7769 def match(self,query):
7770 query=query.lower().strip()
7771 res=OISet()
7772 for k in self._idx.keys():
7773 if k.find(query)!=-1:
7774 res=union(res,self._idx[k])
7775 return res
7778 class _PrimAuthIdx(_AuthIdx):
7780 def __init__(self,conf):
7781 _AuthIdx.__init__(self,conf)
7782 for contrib in self._conf.getContributionList():
7783 for auth in contrib.getPrimaryAuthorList():
7784 self.index(auth)
7786 class Contribution(CommonObjectBase, Locatable):
7787 """This class implements a conference contribution, being the concrete
7788 contributes of the conference participants. The class contains
7789 necessary attributes to store contribution basic meta data and provides
7790 the useful operations to access and manage them. A contribution can be
7791 attached either to a session or to a conference.
7794 fossilizes(IContributionFossil, IContributionWithSpeakersFossil,\
7795 IContributionWithSubContribsFossil)
7797 def __init__(self,**contribData):
7798 self.parent = None
7799 self._session=None
7800 self.id = ""
7801 self.title = ""
7802 self._fields = {}
7803 self.description = ""
7804 self.startDate=None
7805 self.duration = timedelta(0)
7806 self.speakers = []
7807 self.speakerText = ""
7808 self.place = None
7809 self.room = None
7810 self._boardNumber=""
7811 self._resetSchEntry()
7812 self.__ac = AccessController(self)
7813 self.materials = {}
7814 self.__materialGenerator = Counter()
7815 self._subConts = []
7816 self.__subContGenerator = Counter()
7817 self.paper = None
7818 self.slides = None
7819 self.video = None
7820 self.poster = None
7821 self.minutes = None
7822 self.reviewing = None
7823 self._authorGen = Counter()
7824 self._authors = OOBTree()
7825 self._primaryAuthors = []
7826 self._coAuthors = []
7827 self._speakers = []
7828 self._track = None
7829 self._type = None
7830 self._status=ContribStatusNotSch(self)
7831 #List of allowed users to submit material
7832 self._submitters=[]
7833 self._submittersEmail=[]
7834 self._modificationDS = nowutc()
7835 self._keywords = ""
7836 self._reviewManager = ReviewManager(self)
7838 def __cmp__(self, other):
7839 if type(self) is not type(other):
7840 # This is actually dangerous and the ZODB manual says not to do this
7841 # because it relies on memory order. However, this branch should never
7842 # be taken anyway since we do not store different types in the same set
7843 # or use them as keys.
7844 return cmp(hash(self), hash(other))
7845 if self.getConference() == other.getConference():
7846 return cmp(self.getId(), other.getId())
7847 return cmp(self.getConference(), other.getConference())
7849 def __str__(self):
7850 if self.parent:
7851 parentId = self.parent.getId()
7852 else:
7853 parentId = None
7854 return "<Contribution %s:%s@%s>" % (parentId, self.getId(), hex(id(self)))
7856 def getTimezone( self ):
7857 return self.getConference().getTimezone()
7859 def getReviewManager(self):
7860 if not hasattr(self, "_reviewManager"):
7861 self._reviewManager = ReviewManager(self)
7862 return self._reviewManager
7864 def updateNonInheritingChildren(self, elem, delete=False):
7865 self.getAccessController().updateNonInheritingChildren(elem, delete)
7866 self.notify_protection_to_owner(elem, delete)
7868 def notify_protection_to_owner(self, elem, delete=False):
7869 self.getOwner().updateNonInheritingChildren(elem, delete)
7871 def getKeywords(self):
7872 try:
7873 return self._keywords
7874 except:
7875 self._keywords = ""
7876 return ""
7878 def setKeywords(self, keywords):
7879 if type(keywords) is list:
7880 self._keywords = keywords[0]
7881 else:
7882 self._keywords = keywords
7883 self.notifyModification(cleanCache = False)
7885 def getFields( self ):
7886 try:
7887 return self._fields
7888 except:
7889 self._fields = {}
7890 try:
7891 if self.summary != "":
7892 self._fields["summary"] = self.summary
7893 del self.summary
7894 except:
7895 pass
7896 return self._fields
7898 def removeField( self, field ):
7899 if self.getFields().has_key(field):
7900 del self.getFields()[field]
7901 self.notifyModification()
7903 def setField( self, field, value ):
7904 try:
7905 self.getFields()[field] = value
7906 self.notifyModification()
7907 except:
7908 pass
7910 def getField( self, field ):
7911 if self.getFields().has_key(field):
7912 value = self.getFields()[field]
7913 if type(value) is list:
7914 return "".join(value)
7915 elif value is None:
7916 return ""
7917 else:
7918 return value
7919 else:
7920 return ""
7922 def getLogInfo(self):
7923 data = {}
7924 data["subject"] = self.getTitle()
7925 data["id"] = self.id
7926 data["title"] = self.title
7927 data["parent title"] = self.parent.getTitle()
7928 if self._session is not None :
7929 data["session title"] = self._session.getTitle()
7930 data["description"] = self.description
7931 if self.getConference():
7932 afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr()
7933 for f in afm.getFields():
7934 id = f.getId()
7935 data[id] = self.getField(id)
7936 data["start date"] = "%s"%self.startDate
7937 data["duration"] = "%s"%self.duration
7938 if self._track is not None :
7939 data["track"] = self._track.getTitle()
7940 if self._type is not None :
7941 data["type"] = self._type
7942 data["speaker text"] = self.speakerText
7943 if self.place is not None :
7944 data["place"] = self.place.getName()
7945 if self.room is not None :
7946 data["room"] = self.room.getName()
7947 data["board number"] = self._boardNumber
7948 for sc in self.getSubContributionList() :
7949 data["subcontribution %s"%sc.getId()] = sc.getTitle()
7950 for pa in self._primaryAuthors :
7951 data["primary author %s"%pa.getId()] = pa.getFullName()
7952 for ca in self._coAuthors :
7953 data["co-author %s"%ca.getId()] = ca.getFullName()
7954 for sp in self._speakers :
7955 data["speaker %s"%sp.getId()] = sp.getFullName()
7956 for s in self.getSubmitterList():
7957 if isinstance(s, MaKaC.user.Avatar):
7958 data["submitter"] = s.getFullName()
7959 else:
7960 data["submitter"] = s.getName()
7961 return data
7964 def setValues( self, data, check=2, moveEntriesBelow=0):
7965 """Sets all the values of the current contribution object from a
7966 dictionary containing the following key-value pairs:
7967 title-(str)
7968 description-(str)
7969 locationName-(str) => name of the location, if not specified
7970 it will be set to the parent location name.
7971 locationAddress-(str)
7972 roomName-(str) => name of the room, if not specified it will
7973 be set to the parent room name.
7974 year, month, day, sHour, sMinute - (str) => components of the
7975 starting date of the session, if not specified it will
7976 be set to now.
7977 durationHours, durationMinutes - (str)
7978 speakers - (str)
7979 check parameter:
7980 0: no check at all
7981 1: check and raise error in case of problem
7982 2: check and adapt the owner dates
7983 moveEntries:
7984 0: no move
7985 1: moveEntries below the contribution
7986 Please, note that this method sets ALL values which means that if
7987 the given dictionary doesn't contain any of the keys the value
7988 will set to a default value.
7991 # In order to move the entries below, it is needed to know the diff (we have to move them)
7992 # and the list of entries to move. It's is needed to take those datas in advance because they
7993 # are going to be modified before the moving.
7994 if moveEntriesBelow == 1:
7995 oldStartDate=copy.copy(self.getStartDate())
7996 oldDuration=copy.copy(self.getDuration())
7997 i=self.getSchEntry().getSchedule().getEntries().index(self.getSchEntry())+1
7998 entriesList = self.getSchEntry().getSchedule().getEntries()[i:]
7999 if data.has_key("title"):
8000 self.setTitle(data["title"])
8001 if data.has_key("keywords"):
8002 self.setKeywords(data["keywords"])
8003 if data.has_key("description"):
8004 self.setDescription(data["description"])
8005 if data.has_key("type") and self.getConference():
8006 self.setType(self.getConference().getContribTypeById(data["type"]))
8007 if self.getConference():
8008 afm = self.getConference().getAbstractMgr().getAbstractFieldsMgr()
8009 for f in afm.getFields():
8010 id = f.getId()
8011 if data.has_key("f_%s"%id):
8012 self.setField(id, data["f_%s"%id])
8014 if "locationName" in data:
8015 loc=self.getOwnLocation()
8016 if not loc:
8017 loc=CustomLocation()
8018 self.setLocation(loc)
8019 loc.setName(data["locationName"])
8020 loc.setAddress(data.get("locationAddress", ""))
8021 else:
8022 self.setLocation(None)
8024 #same as for the location
8025 if "roomName" in data:
8026 room=self.getOwnRoom()
8027 if not room:
8028 room=CustomRoom()
8029 self.setRoom(room)
8030 room.setName(data["roomName"])
8031 room.retrieveFullName(data.get("locationName", ""))
8032 else:
8033 self.setRoom(None)
8035 tz = 'UTC'
8036 if self.getConference():
8037 tz = self.getConference().getTimezone()
8038 if data.get("targetDay","")!="" and data.get("sHour","")!="" and data.get("sMinute","")!="" and check==2:
8039 ############################################
8040 # Fermi timezone awareness #
8041 ############################################
8042 me = timezone(tz).localize(datetime(int(data["targetDay"][0:4]), \
8043 int(data["targetDay"][5:7]),int(data["targetDay"][8:])))
8044 sdate = timezone(tz).localize(datetime(me.year,me.month, \
8045 me.day,int(data["sHour"]),int(data["sMinute"])))
8046 self.setStartDate(sdate.astimezone(timezone('UTC')),check=2)
8047 if data.get("sYear","")!="" and data.get("sMonth","")!="" and \
8048 data.get("sDay","")!="" and data.get("sHour","")!="" and \
8049 data.get("sMinute","")!="":
8050 self.setStartDate(timezone(tz).localize(datetime(int(data["sYear"]),
8051 int(data["sMonth"]), int(data["sDay"]),
8052 int(data["sHour"]), int(data["sMinute"]))).astimezone(timezone('UTC')),
8053 check=2)
8054 ############################################
8055 # Fermi timezone awareness(end) #
8056 ############################################
8057 if data.get("durTimedelta", "") != "":
8058 self.setDuration(check=check, dur=data["durTimedelta"])
8059 elif data.get("durHours","")!="" and data.get("durMins","")!="":
8060 self.setDuration(data["durHours"],data["durMins"],check)
8061 else:
8062 h=data.get("durHours","").strip()
8063 m=data.get("durMins","").strip()
8064 if h!="" or m!="":
8065 h=h or "0"
8066 m=m or "0"
8067 if h!="0" or m!="0":
8068 self.setDuration(int(h), int(m),check)
8069 if data.has_key("boardNumber"):
8070 self.setBoardNumber(data.get("boardNumber",""))
8071 if moveEntriesBelow == 1:
8072 diff = (self.getStartDate() - oldStartDate) + (self.getDuration() - oldDuration)
8073 self.getConference().getSchedule().moveEntriesBelow(diff, entriesList)
8074 self.notifyModification()
8076 def clone(self, parent, options, deltaTime = 0):
8077 cont = Contribution()
8078 parent.addContribution(cont)
8079 cont.setTitle( self.getTitle() )
8080 cont.setDescription( self.getDescription() )
8081 for k in self.getFields().keys():
8082 cont.setField(k, self.getField(k))
8083 cont.setKeywords( self.getKeywords() )
8084 if deltaTime == 0 :
8085 deltaTime = parent.getStartDate() - self.getOwner().getStartDate()
8087 startDate = None
8088 if self.startDate is not None :
8089 startDate = self.getStartDate() + deltaTime
8090 cont.setStartDate( startDate )
8092 cont.setDuration( dur=self.getDuration() )
8094 if self.getOwnLocation() is not None:
8095 cont.setLocation(self.getOwnLocation().clone())
8096 if self.getOwnRoom() is not None:
8097 cont.setRoom(self.getOwnRoom().clone())
8098 cont.setBoardNumber(self.getBoardNumber())
8099 cont.setReportNumberHolder(self.getReportNumberHolder().clone(self))
8101 cont.setStatus(self.getCurrentStatus())
8103 if self.getType() is not None :
8104 for ct in cont.getConference().getContribTypeList() :
8105 if ct.getName() == self.getType().getName() :
8106 cont.setType(ct)
8107 break
8109 if options.get("tracks", False) :
8110 if self.getTrack() is not None :
8111 for tr in cont.getConference().getTrackList() :
8112 if tr.getTitle() == self.getTrack().getTitle() :
8113 cont.setTrack(tr)
8114 break
8115 else :
8116 cont.setTrack(None)
8118 if options.get("access", False) :
8119 cont.setProtection(self.getAccessController()._getAccessProtection())
8120 for u in self.getAllowedToAccessList() :
8121 cont.grantAccess(u)
8122 for mgr in self.getManagerList() :
8123 cont.grantModification(mgr)
8124 for sub in self.getSubmitterList() :
8125 cont.grantSubmission(sub)
8126 for domain in self.getDomainList():
8127 cont.requireDomain(domain)
8129 if options.get("authors", False) :
8130 for a in self.getPrimaryAuthorList() :
8131 cont.addPrimaryAuthor(a.clone())
8132 for ca in self.getCoAuthorList() :
8133 cont.addCoAuthor(ca.clone())
8134 for sp in self.getSpeakerList():
8135 cont.newSpeaker(sp.clone())
8136 cont.setSpeakerText(self.getSpeakerText())
8138 if options.get("materials", False) :
8139 for m in self.getMaterialList() :
8140 cont.addMaterial(m.clone(cont))
8141 if self.getPaper() is not None:
8142 cont.setPaper(self.getPaper().clone(cont))
8143 if self.getSlides() is not None:
8144 cont.setSlides(self.getSlides().clone(cont))
8145 if self.getVideo() is not None:
8146 cont.setVideo(self.getVideo().clone(cont))
8147 if self.getPoster() is not None:
8148 cont.setPoster(self.getPoster().clone(cont))
8149 if self.getMinutes() is not None:
8150 cont.setMinutes(self.getMinutes().clone(cont))
8151 if self.getReviewing() is not None:
8152 cont.setReviewing(self.getReviewing().clone(cont))
8154 if options.get("subcontribs", False) :
8155 for sc in self.getSubContributionList() :
8156 cont.addSubContribution(sc.clone(cont, self, options))
8157 return cont
8159 def notifyModification( self, date = None, raiseEvent = True, cleanCache = True):
8160 self.setModificationDate(date)
8162 if raiseEvent:
8163 self._notify('infoChanged')
8166 if cleanCache:
8167 self.cleanCache()
8169 parent = self.getParent()
8170 if parent:
8171 parent.setModificationDate()
8172 self._p_changed = 1
8174 def cleanCache(self, cleanConference = True):
8175 # Do not clean cache if already cleaned
8176 if not ContextManager.get('clean%s'%self.getUniqueId(), False):
8177 ScheduleToJson.cleanCache(self)
8178 ContextManager.set('clean%s'%self.getUniqueId(), cleanConference)
8180 def getCategoriesPath(self):
8181 return self.getConference().getCategoriesPath()
8183 def getModifKey( self ):
8184 return self.getConference().getModifKey()
8186 def getAccessKey( self ):
8187 return self.getConference().getAccessKey()
8189 def getLocator( self ):
8190 """Gives back a globaly unique identification encapsulated in a Locator
8191 object for the contribution instance
8193 if self.getConference() == None:
8194 return Locator()
8195 lconf = self.getConference().getLocator()
8196 if self.getSession() is not None:
8197 lconf["sessionId"] = self.getSession().getId()
8198 lconf["contribId"] = self.getId()
8199 return lconf
8201 def _setConference( self, conf ):
8202 self.parent = conf
8204 def _setId( self, id ):
8205 self.id = id
8207 def includeInConference( self, conf, id ):
8208 """sets the conference of a contribution
8210 if self.getConference() is not None:
8211 #raise MaKaCError("the contribution is already included in a conference")
8212 pass
8213 else:
8214 self._setConference( conf )
8215 self._setId( id )
8217 def delete( self ):
8218 """deletes a contribution and all of its subitems
8221 oldParent = self.getConference()
8223 if oldParent != None:
8224 self._notify('deleted', oldParent)
8226 self.setTrack(None)
8227 for mat in self.getMaterialList():
8228 self.removeMaterial(mat)
8229 self.removePaper()
8230 self.removeSlides()
8231 self.removeVideo()
8232 self.removePoster()
8233 self.removeMinutes()
8234 self.removeReviewing()
8236 self.notify_protection_to_owner(self, delete=True)
8238 self.setSession(None)
8240 while len(self.getSubContributionList()) > 0:
8242 sc = self.getSubContributionList()[0]
8244 self.removeSubContribution(sc)
8247 # delete it from parent session (if it exists)
8248 if self.getOwner() != self.getConference():
8250 self.getOwner().removeContribution( self )
8252 # (always) delete it from the parent conference
8253 self.getConference().removeContribution( self, callDelete=False )
8255 self._setConference( None )
8257 self.setStatus(ContribStatusNone(self))
8259 TrashCanManager().add(self)
8261 def recover(self):
8262 TrashCanManager().remove(self)
8264 def setId( self, newId ):
8265 self._setId(newId)
8267 def getId( self ):
8268 return self.id
8270 def getUniqueId( self ):
8271 """returns (string) the unique identifier of the item"""
8272 """used mainly in the web session access key table"""
8273 return "%st%s" % (self.getConference().getUniqueId(),self.id)
8275 def setTitle( self, newTitle, notify = True ):
8276 oldTitle = self.title
8277 self.title = newTitle.strip()
8279 if notify:
8280 self._notify('contributionTitleChanged', oldTitle, newTitle)
8281 self.notifyModification()
8283 def getTitle( self ):
8284 if self.title.strip() == "":
8285 return "(no title)"
8286 return self.title
8288 #def setDescription( self, newDesc ):
8289 # self.description = newDesc.strip()
8290 # self.notifyModification()
8292 #def getDescription( self ):
8293 # return self.description
8295 def getDescription(self):
8296 return self.getField("content")
8298 def setDescription(self, desc):
8299 self.setField("content", desc)
8301 def setParent(self,parent):
8302 self.parent=parent
8303 self.notifyModification(cleanCache = False)
8304 if self.parent==None:
8305 return
8307 def getParent( self ):
8308 if self.getSession() is not None:
8309 return self.getSession()
8310 return self.getConference()
8312 def getOwner( self ):
8313 return self.getParent()
8315 def setOwner(self, owner):
8316 self.setParent(owner)
8318 def getConference( self ):
8319 return self.parent
8321 def getSession( self ):
8322 try:
8323 if self._session:
8324 pass
8325 except AttributeError:
8326 self._session=None
8327 return self._session
8329 def setSession(self,session):
8330 if self.getSession()==session:
8331 return
8332 if self.isScheduled():
8333 schEntry=self.getSchEntry()
8334 schEntry.getSchedule().removeEntry(schEntry)
8335 oldSession=self.getSession()
8336 if oldSession is not None:
8337 oldSession.removeContribution(self)
8338 self._session=session
8339 if session is not None:
8340 session.addContribution(self)
8342 def getContribution(self):
8343 return self
8345 def _resetSchEntry(self):
8346 self.__schEntry=ContribSchEntry(self)
8348 def getSchEntry(self):
8349 if self.__schEntry is None or \
8350 not isinstance(self.__schEntry,ContribSchEntry):
8351 self._resetSchEntry()
8352 return self.__schEntry
8354 def isScheduled(self):
8355 #For the moment we do it like this
8356 return self.getSchEntry().getSchedule() is not None
8358 def isWithdrawn(self):
8359 return isinstance(self.getCurrentStatus(), ContribStatusWithdrawn)
8361 def getLocationParent( self ):
8363 Returns the object from which the room/location
8364 information should be inherited
8366 if not self.getConference().getEnableSessionSlots() and self.getSession():
8367 return self.getSession()
8368 if self.isScheduled():
8369 return self.getSchEntry().getSchedule().getOwner()
8370 return self.getOwner()
8372 def getOwnLocation( self ):
8373 return self.place
8375 def setLocation( self, newLocation ):
8376 oldLocation = self.place
8377 self.place = newLocation
8378 self._notify('locationChanged', oldLocation, newLocation)
8379 self.notifyModification()
8381 def getOwnRoom( self ):
8382 return self.room
8384 def setRoom( self, newRoom ):
8385 oldRoom = self.room
8386 self.room = newRoom
8387 self._notify('roomChanged', oldRoom, newRoom)
8388 self.notifyModification()
8390 def setBoardNumber(self,newBoardNum):
8391 self._boardNumber=str(newBoardNum).strip()
8393 def getBoardNumber(self):
8394 try:
8395 if self._boardNumber:
8396 pass
8397 except AttributeError:
8398 self._boardNumber=""
8399 return self._boardNumber
8401 def verifyStartDate(self, sDate, check=2):
8402 """check parameter:
8403 0: no check at all
8404 1: check and raise error in case of problem
8405 2: check and adapt the owner dates"""
8407 tz = timezone(self.getConference().getTimezone())
8408 if self.getSchEntry().getSchedule():
8409 owner = self.getSchEntry().getSchedule().getOwner()
8410 else:
8411 owner = self.getOwner()
8412 if sDate < owner.getStartDate():
8413 if check == 1:
8414 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start before (%s) its parent (%s)") %\
8415 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8416 owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8417 _("Contribution"))
8418 if check == 2:
8419 ContextManager.get('autoOps').append((self, "OWNER_START_DATE_EXTENDED",
8420 owner, sDate.astimezone(tz)))
8421 owner.setDates(sDate,owner.getEndDate(), check)
8422 if sDate > owner.getEndDate():
8423 if check == 1:
8424 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start after (%s) its parent end date(%s)") %\
8425 (self.getTitle(), sDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8426 owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8427 _("Contribution"))
8428 if check == 2:
8429 owner.setEndDate(sDate+self.getDuration(),check)
8430 # Check that after modifying the start date, the end date is still within the limits of the slot
8431 if self.getDuration() and sDate + self.getDuration() > owner.getEndDate():
8432 if check==1:
8433 raise ParentTimingError("The contribution cannot end after (%s) its parent ends (%s)"%\
8434 ((sDate + self.getDuration()).astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8435 owner.getAdjustedEndDate().strftime('%Y-%m-%d %H:%M')),\
8436 _("Contribution"))
8437 elif check==2:
8438 # update the schedule
8439 owner.setEndDate(sDate + self.getDuration(),check)
8440 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
8441 owner, owner.getAdjustedEndDate()))
8443 def setStartDate(self, newDate, check=2, moveEntries=0):
8444 """check parameter:
8445 0: no check at all
8446 1: check and raise error in case of problem
8447 2: check and adapt the owner dates"""
8448 if newDate == None:
8449 self.startDate=None
8450 return
8451 if not newDate.tzname():
8452 raise MaKaCError("date should be timezone aware")
8454 if newDate != None and check != 0:
8455 self.verifyStartDate(newDate, check)
8456 self._notify("contributionUnscheduled")
8457 self.startDate=copy.copy(newDate)
8458 self._notify("contributionScheduled")
8459 self.getSchEntry().synchro()
8460 self.notifyModification()
8462 def getStartDate( self ):
8463 return self.startDate
8465 def getAdjustedStartDate(self,tz=None):
8466 if self.getStartDate() is None:
8467 return None
8468 if not tz:
8469 tz = self.getConference().getTimezone()
8470 if tz not in all_timezones:
8471 tz = 'UTC'
8472 return self.getStartDate().astimezone(timezone(tz))
8474 def getEndDate( self ):
8475 if self.getStartDate() is None:
8476 return None
8477 return self.getStartDate()+self.getDuration()
8479 def getAdjustedEndDate(self,tz=None):
8480 if not tz:
8481 tz = self.getConference().getTimezone()
8482 if tz not in all_timezones:
8483 tz = 'UTC'
8484 if self.getEndDate():
8485 return self.getEndDate().astimezone(timezone(tz))
8486 return None
8488 def getDuration( self ):
8489 return self.duration
8491 def verifyDuration(self, check=2):
8492 """check parameter:
8493 0: no check at all
8494 1: check and raise error in case of problem
8495 2: check and adapt the owner dates"""
8497 tz = timezone(self.getConference().getTimezone())
8499 endDate = self.getEndDate()
8501 if self.getSchEntry().getSchedule() is not None:
8502 owner = self.getSchEntry().getSchedule().getOwner()
8503 if endDate > owner.getEndDate():
8504 if check==1:
8505 raise ParentTimingError(_("The contribution \"%s\" ending date (%s) has to fit between its parent's dates (%s - %s)") %\
8506 (self.getTitle(), endDate.astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8507 owner.getStartDate().astimezone(tz).strftime('%Y-%m-%d %H:%M'),\
8508 owner.getEndDate().astimezone(tz).strftime('%Y-%m-%d %H:%M')),\
8509 _("Contribution"))
8510 elif check==2:
8511 ContextManager.get('autoOps').append((self, "OWNER_END_DATE_EXTENDED",
8512 owner, self.getAdjustedEndDate()))
8513 owner.setEndDate(endDate, check)
8515 def setDuration(self,hours=0,minutes=15,check=2,dur=0):
8516 """check parameter:
8517 0: no check at all
8518 1: check and raise error in case of problem
8519 2: check and adapt the owner dates"""
8521 if dur!=0:
8522 self.duration=dur
8523 else:
8524 self.duration=timedelta(hours=int(hours),minutes=int(minutes))
8525 if check != 0:
8526 self.verifyDuration(check)
8527 self.getSchEntry().synchro()
8528 self.notifyModification()
8530 def _addAuthor( self, part ):
8533 try:
8534 if self._authors:
8535 pass
8536 except AttributeError:
8537 self._authors = OOBTree()
8538 try:
8539 if self._authorGen:
8540 pass
8541 except AttributeError:
8542 self._authorGen=Counter()
8543 newId = part.getId()
8544 if newId == "":
8545 newId = str( self._authorGen.newCount() )
8546 self._authors[newId] = part
8547 part.includeInContribution( self, newId )
8549 def _removeAuthor( self, part ):
8552 try:
8553 if self._authors:
8554 pass
8555 except AttributeError:
8556 self._authors = OOBTree()
8557 if not self._authors.has_key( part.getId() ):
8558 return
8559 del self._authors[ part.getId() ]
8560 part.delete()
8562 def addPrimaryAuthor( self, part, index = None ):
8565 try:
8566 if self._primaryAuthors:
8567 pass
8568 except AttributeError:
8569 self._primaryAuthors = []
8570 self._addAuthor( part )
8571 if index is not None:
8572 self._primaryAuthors.insert(index, part)
8573 else:
8574 self._primaryAuthors.append( part )
8575 if self.getConference() is not None:
8576 self.getConference().indexAuthor(part)
8577 self.notifyModification(cleanCache = False)
8579 def removePrimaryAuthor( self, part, removeSpeaker=1, removePendingSubm=True):
8582 try:
8583 if self._primaryAuthors:
8584 pass
8585 except AttributeError:
8586 self._primaryAuthors = []
8587 if part not in self._primaryAuthors:
8588 return
8589 if self.getConference() is not None:
8590 self.getConference().unindexAuthor(part)
8591 self._primaryAuthors.remove( part )
8592 if removeSpeaker:
8593 self.removeSpeaker( part )
8594 self._removeAuthor( part )
8595 if removePendingSubm:
8596 #--Pending queue: remove pending participant waiting to became submitter if anything
8597 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8599 self.notifyModification(cleanCache = False)
8601 def recoverPrimaryAuthor(self, pa, isPendingSubmitter):
8602 self.addPrimaryAuthor(pa)
8603 pa.recover()
8604 if isPendingSubmitter:
8605 self.getConference().getPendingQueuesMgr().addPendingSubmitter(pa, False)
8607 def isPrimaryAuthor( self, part ):
8610 try:
8611 if self._primaryAuthors:
8612 pass
8613 except AttributeError:
8614 self._primaryAuthors = []
8615 return part in self._primaryAuthors
8617 def isCoAuthor(self, part):
8618 try:
8619 if self._coAuthors:
8620 pass
8621 except AttributeError:
8622 self._coAuthors = []
8623 return part in self._coAuthors
8625 def isPrimaryAuthorByEmail(self, email):
8626 for prAuthor in self.getPrimaryAuthorList():
8627 if prAuthor.getEmail() == email:
8628 return True
8629 return False
8631 def isCoAuthorByEmail(self, email):
8632 for coAuthor in self.getCoAuthorList():
8633 if coAuthor.getEmail() == email:
8634 return True
8635 return False
8637 def isSpeakerByEmail(self, email):
8638 for speaker in self.getSpeakerList():
8639 if speaker.getEmail() == email:
8640 return True
8641 return False
8643 def changePosPrimaryAuthor(self,part,index):
8646 try:
8647 if self._primaryAuthors:
8648 pass
8649 except AttributeError:
8650 self._primaryAuthors=[]
8651 if not part in self._primaryAuthors:
8652 return
8653 self._primaryAuthors.remove(part)
8654 self._primaryAuthors.insert(index,part)
8655 self.notifyModification(cleanCache = False)
8657 def upPrimaryAuthor(self,part):
8660 try:
8661 if self._primaryAuthors:
8662 pass
8663 except AttributeError:
8664 self._primaryAuthors=[]
8665 try:
8666 idx=self._primaryAuthors.index(part)
8667 except ValueError:
8668 return
8669 if idx==0:
8670 return
8671 self._primaryAuthors.remove(part)
8672 self._primaryAuthors.insert(idx-1,part)
8673 self.notifyModification(cleanCache = False)
8675 def downPrimaryAuthor(self,part):
8678 try:
8679 if self._primaryAuthors:
8680 pass
8681 except AttributeError:
8682 self._primaryAuthors=[]
8683 try:
8684 idx=self._primaryAuthors.index(part)
8685 except ValueError:
8686 return
8687 if idx>len(self._primaryAuthors):
8688 return
8689 self._primaryAuthors.remove(part)
8690 self._primaryAuthors.insert(idx+1,part)
8691 self.notifyModification(cleanCache = False)
8693 def newAuthorsList(self, prAuthors, coAuthors):
8694 ''' calculate new lists of both kind of authors, because something has
8695 been changed the position by drag and drop '''
8696 newPrList = self.calculateNewAuthorList(prAuthors, "prAuthor")
8697 newCoList = self.calculateNewAuthorList(coAuthors, "coAuthor")
8698 self.setPrimaryAuthorList(newPrList)
8699 self.setCoAuthorList(newCoList)
8701 def calculateNewAuthorList(self, list, kind):
8702 result = []
8703 if kind == "prAuthor":
8704 for auth in list:
8705 author = self.getPrimaryAuthorById(auth['id'])
8706 if author:
8707 result.append(author)
8708 else:
8709 author = self.getCoAuthorById(auth['id'])
8710 if author:
8711 result.append(author)
8713 elif kind == "coAuthor":
8714 for auth in list:
8715 author = self.getCoAuthorById(auth['id'])
8716 if author:
8717 result.append(author)
8718 else:
8719 author = self.getPrimaryAuthorById(auth['id'])
8720 if author:
8721 result.append(author)
8722 return result
8725 def getPrimaryAuthorById(self, authorId):
8726 for author in self.getPrimaryAuthorList():
8727 if authorId == author.getId():
8728 return author
8729 return None
8731 def getCoAuthorById(self, authorId):
8732 for author in self.getCoAuthorList():
8733 if authorId == author.getId():
8734 return author
8735 return None
8737 def setPrimaryAuthorList(self, l):
8738 self._primaryAuthors = l
8739 self.notifyModification(cleanCache = False)
8741 def setCoAuthorList(self, l):
8742 self._coAuthors = l
8743 self.notifyModification(cleanCache = False)
8745 def changePosCoAuthor(self, part, index):
8748 try:
8749 if self._coAuthors:
8750 pass
8751 except AttributeError:
8752 self._coAuthors=[]
8753 if not part in self._coAuthors:
8754 return
8755 self._coAuthors.remove(part)
8756 self._coAuthors.insert(index,part)
8757 self.notifyModification(cleanCache = False)
8760 def upCoAuthor(self,part):
8763 try:
8764 if self._coAuthors:
8765 pass
8766 except AttributeError:
8767 self._coAuthors=[]
8768 try:
8769 idx=self._coAuthors.index(part)
8770 except ValueError:
8771 return
8772 if idx==0:
8773 return
8774 self._coAuthors.remove(part)
8775 self._coAuthors.insert(idx-1,part)
8776 self.notifyModification(cleanCache = False)
8778 def downCoAuthor(self,part):
8781 try:
8782 if self._coAuthors:
8783 pass
8784 except AttributeError:
8785 self._coAuthors=[]
8786 try:
8787 idx=self._coAuthors.index(part)
8788 except ValueError:
8789 return
8790 if idx>len(self._coAuthors):
8791 return
8792 self._coAuthors.remove(part)
8793 self._coAuthors.insert(idx+1,part)
8794 self.notifyModification(cleanCache = False)
8796 def getPrimaryAuthorList( self ):
8799 try:
8800 if self._primaryAuthors:
8801 pass
8802 except AttributeError:
8803 self._primaryAuthors = []
8804 return self._primaryAuthors
8806 getPrimaryAuthorsList = getPrimaryAuthorList
8808 def getAuthorList( self ):
8811 try:
8812 if self._authors:
8813 pass
8814 except AttributeError:
8815 self._authors = OOBTree()
8816 return self._authors.values()
8818 def getAllAuthors(self):
8819 """ This method returns a list composed by the primary authors
8820 and co-authors. The different with getAuthorList() is the type
8821 of the output.
8823 return self.getPrimaryAuthorList() + self.getCoAuthorList()
8825 def addCoAuthor( self, part, index=None ):
8828 try:
8829 if self._coAuthors:
8830 pass
8831 except AttributeError:
8832 self._coAuthors = []
8833 self._addAuthor( part )
8834 if index is not None:
8835 self._coAuthors.insert(index, part)
8836 else:
8837 self._coAuthors.append( part )
8838 if self.getConference() is not None:
8839 self.getConference().indexAuthor(part)
8840 self.notifyModification(cleanCache = False)
8842 def removeCoAuthor( self, part, removeSpeaker=1, removePendingSubm=True):
8845 try:
8846 if self._coAuthors:
8847 pass
8848 except AttributeError:
8849 self._coAuthors = []
8850 if part not in self._coAuthors:
8851 return
8852 if self.getConference() is not None:
8853 self.getConference().unindexAuthor(part)
8854 self._coAuthors.remove( part )
8855 if removeSpeaker:
8856 self.removeSpeaker( part )
8857 self._removeAuthor( part )
8858 if removePendingSubm:
8859 #--Pending queue: remove pending participant waiting to became submitter if anything
8860 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8862 self.notifyModification(cleanCache = False)
8864 def recoverCoAuthor(self, ca, isPendingSubmitter):
8865 self.addCoAuthor(ca)
8866 ca.recover()
8867 if isPendingSubmitter:
8868 self.getConference().getPendingQueuesMgr().addPendingSubmitter(ca, False)
8870 def getCoAuthorList( self ):
8873 try:
8874 if self._coAuthors:
8875 pass
8876 except AttributeError:
8877 self._coAuthors = []
8878 return self._coAuthors
8880 def getAuthorById( self, authorId ):
8883 try:
8884 if self._authors:
8885 pass
8886 except AttributeError:
8887 self._authors = OOBTree()
8888 return self._authors.get( authorId.strip(), None )
8890 def isAuthor( self, part ):
8893 try:
8894 if self._authors:
8895 pass
8896 except AttributeError:
8897 self._authors = OOBTree()
8898 return self._authors.has_key( part.getId() )
8900 def getSpeakerById( self, authorId ):
8903 try:
8904 if self._speakers:
8905 pass
8906 except AttributeError:
8907 self._speakers = []
8908 for spk in self._speakers:
8909 if spk.getId() == authorId:
8910 return spk
8911 return None
8913 def changePosSpeaker(self,part,index):
8916 try:
8917 if self._speakers:
8918 pass
8919 except AttributeError:
8920 self._speakers = []
8921 if not part in self._speakers:
8922 return
8923 self._speakers.remove(part)
8924 self._speakers.insert(index,part)
8925 self.notifyModification()
8927 def addSpeaker( self, part, index=None ):
8929 Adds a speaker (ContributionParticipation object) to the contribution
8930 forcing it to be one of the authors of the contribution
8932 try:
8933 if self._speakers:
8934 pass
8935 except AttributeError:
8936 self._speakers = []
8937 if not self.isAuthor( part ):
8938 raise MaKaCError( _("The Specified speaker is not the Author"), _("Contribution"))
8939 if index is not None:
8940 self._speakers.insert(index, part)
8941 else:
8942 self._speakers.append( part )
8943 if self.getConference() is not None:
8944 self.getConference().indexSpeaker(part)
8945 self.notifyModification()
8947 def newSpeaker( self, part ):
8949 Adds a new speaker (ContributionParticipation object) to the contribution
8950 setting the speakers ID and the fact it belongs to that contribution
8952 try:
8953 if self._speakers:
8954 pass
8955 except AttributeError:
8956 self._speakers = []
8957 try:
8958 if self._authorGen:
8959 pass
8960 except AttributeError:
8961 self._authorGen=Counter()
8962 self._speakers.append( part )
8963 newId = part.getId()
8964 if newId == "":
8965 newId = str( self._authorGen.newCount() )
8966 part.includeInContribution(self, newId)
8967 if self.getConference() is not None:
8968 self.getConference().indexSpeaker(part)
8969 self.notifyModification()
8971 def removeSpeaker( self, part ):
8974 try:
8975 if self._speakers:
8976 pass
8977 except AttributeError:
8978 self._speakers = []
8979 if part not in self._speakers:
8980 return
8981 self._speakers.remove( part )
8982 if self.getConference() is not None:
8983 self.getConference().unindexSpeaker(part)
8984 if part not in self.getAuthorList():
8985 part.delete()
8986 #--Pending queue: remove pending participant waiting to became submitter if anything
8987 self.getConference().getPendingQueuesMgr().removePendingSubmitter(part)
8989 self.notifyModification()
8991 def recoverSpeaker(self, spk, isPendingSubmitter):
8992 self.newSpeaker(spk)
8993 spk.recover()
8994 if isPendingSubmitter:
8995 self.getConference().getPendingQueuesMgr().addPendingSubmitter(spk, False)
8997 def isSpeaker( self, part ):
9000 try:
9001 if self._speakers:
9002 pass
9003 except AttributeError:
9004 self._speakers = []
9005 return part in self._speakers
9007 def getSpeakerList ( self ):
9010 try:
9011 if self._speakers:
9012 pass
9013 except AttributeError:
9014 self._speakers = []
9015 return self._speakers
9017 def getSpeakerText( self ):
9018 #to be removed
9019 try:
9020 if self.speakerText:
9021 pass
9022 except AttributeError, e:
9023 self.speakerText = ""
9024 return self.speakerText
9026 def setSpeakerText( self, newText ):
9027 self.speakerText = newText.strip()
9029 def appendSpeakerText( self, newText ):
9030 self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) )
9032 def canIPAccess( self, ip ):
9033 if not self.__ac.canIPAccess( ip ):
9034 return False
9035 if self.getOwner() != None:
9036 return self.getOwner().canIPAccess(ip)
9037 return True
9039 def isProtected( self ):
9040 # tells if a contribution is protected or not
9041 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
9043 def getAccessProtectionLevel( self ):
9044 return self.__ac.getAccessProtectionLevel()
9046 def isItselfProtected( self ):
9047 return self.__ac.isItselfProtected()
9049 def hasAnyProtection( self ):
9050 """Tells whether a contribution has any kind of protection over it:
9051 access or domain protection.
9053 if self.__ac.isProtected():
9054 return True
9055 if self.getDomainList():
9056 return True
9057 if self.getAccessProtectionLevel() == -1:
9058 return False
9059 if self.getOwner():
9060 return self.getOwner().hasAnyProtection()
9061 else:
9062 return False
9064 def hasProtectedOwner( self ):
9065 if self.getOwner() != None:
9066 return self.getOwner().isProtected()
9067 return False
9069 def setProtection( self, private ):
9071 oldValue = 1 if self.isProtected() else -1
9073 self.__ac.setProtection( private )
9074 self.notify_protection_to_owner(self)
9076 if oldValue != private:
9077 # notify listeners
9078 self._notify('protectionChanged', oldValue, private)
9080 def grantAccess( self, prin ):
9081 self.__ac.grantAccess( prin )
9082 if isinstance(prin, MaKaC.user.Avatar):
9083 prin.linkTo(self, "access")
9084 self.notifyModification(raiseEvent = False)
9086 def revokeAccess( self, prin ):
9087 self.__ac.revokeAccess( prin )
9088 if isinstance(prin, MaKaC.user.Avatar):
9089 prin.unlinkTo(self, "access")
9090 self.notifyModification(raiseEvent = False)
9092 def canView( self, aw ):
9093 """tells whether the specified user has access to the current object
9094 or any of its sub-objects
9096 if self.canAccess( aw ):
9097 return True
9098 ### TODO: Replace this code when plugins allow extension points+notifications ##################
9099 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
9100 if RCCollaborationAdmin.hasRights(user=aw.getUser()) or \
9101 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
9102 return True
9103 ################################################################################################
9104 for sc in self.getSubContributionList():
9105 if sc.canView( aw ):
9106 return True
9107 return False
9109 def isAllowedToAccess( self, user ):
9110 if not user:
9111 return False
9112 return (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or\
9113 self.__ac.canUserAccess( user ) or\
9114 self.canUserModify( user ) or \
9115 self.canUserSubmit(user)
9117 def canAccess( self, aw ):
9118 # Allow harvesters (Invenio, offline cache) to access
9119 # protected pages
9120 if self.__ac.isHarvesterIP(aw.getIP()):
9121 return True
9122 #####################################################
9124 if self.canModify(aw):
9125 return True
9127 if not self.canIPAccess(aw.getIP()) and not self.isAllowedToAccess( aw.getUser() ):
9128 return False
9129 if not self.isProtected():
9130 return True
9131 flag = self.isAllowedToAccess( aw.getUser() )
9132 return flag or self.getConference().canKeyAccess(aw)
9134 def grantModification( self, prin ):
9135 self.__ac.grantModification( prin )
9136 if isinstance(prin, MaKaC.user.Avatar):
9137 prin.linkTo(self, "manager")
9138 self.notifyModification(raiseEvent = False)
9140 def revokeModification( self, prin ):
9141 self.__ac.revokeModification( prin )
9142 if isinstance(prin, MaKaC.user.Avatar):
9143 prin.unlinkTo(self, "manager")
9144 self.notifyModification(raiseEvent = False)
9146 def canModify( self, aw ):
9147 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
9149 def canUserModify( self, av ):
9150 """Tells whether a user is allowed to modify the current contribution:
9151 only if the user is granted to modify the contribution or the user
9152 can modify any of its upper objects (i.e. conference or session).
9154 return self.getParent().canUserModify( av ) or self.__ac.canModify( av )
9156 def getManagerList( self ):
9157 return self.__ac.getModifierList()
9159 def getAllowedToAccessList( self ):
9160 return self.__ac.getAccessList()
9162 def addMaterial( self, newMat ):
9163 newMat.setId( str(self.__materialGenerator.newCount()) )
9164 newMat.setOwner( self )
9165 self.materials[ newMat.getId() ] = newMat
9166 self.notifyModification()
9168 def removeMaterial( self, mat ):
9169 if mat.getId() in self.materials.keys():
9170 mat.delete()
9171 self.materials[mat.getId()].setOwner(None)
9172 del self.materials[ mat.getId() ]
9173 self.notifyModification()
9174 elif mat.getId().lower() == 'paper':
9175 self.removePaper()
9176 elif mat.getId().lower() == 'slides':
9177 self.removeSlides()
9178 elif mat.getId().lower() == 'minutes':
9179 self.removeMinutes()
9180 elif mat.getId().lower() == 'video':
9181 self.removeVideo()
9182 elif mat.getId().lower() == 'poster':
9183 self.removePoster()
9185 def recoverMaterial(self, recMat):
9186 # Id must already be set in recMat.
9187 recMat.setOwner( self )
9188 self.materials[ recMat.getId() ] = recMat
9189 recMat.recover()
9190 self.notifyModification()
9192 def getMaterialRegistry(self):
9194 Return the correct material registry for this type
9196 from MaKaC.webinterface.materialFactories import ContribMFRegistry
9197 return ContribMFRegistry
9199 def getMaterialById( self, matId ):
9200 if matId.lower() == 'paper':
9201 return self.getPaper()
9202 elif matId.lower() == 'slides':
9203 return self.getSlides()
9204 elif matId.lower() == 'video':
9205 return self.getVideo()
9206 elif matId.lower() == 'poster':
9207 return self.getPoster()
9208 elif matId.lower() == 'minutes':
9209 return self.getMinutes()
9210 elif self.materials.has_key(matId):
9211 return self.materials[ matId ]
9212 return None
9214 def getMaterialList( self ):
9215 return self.materials.values()
9217 def getAllMaterialList(self, sort=True):
9218 l = self.getMaterialList()
9219 if self.getPaper():
9220 l.append( self.getPaper() )
9221 if self.getSlides():
9222 l.append( self.getSlides() )
9223 if self.getVideo():
9224 l.append( self.getVideo() )
9225 if self.getPoster():
9226 l.append( self.getPoster() )
9227 if self.getMinutes():
9228 l.append( self.getMinutes() )
9229 if sort:
9230 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
9231 return l
9233 def getAllViewableMaterialList( self, aw=None ):
9234 if not aw:
9235 aw = ContextManager.get("currentRH").getAW()
9236 return [mat for mat in self.getAllMaterialList() if mat.canView(aw)]
9239 def newSubContribution(self):
9240 newSub = SubContribution()
9241 self.addSubContribution(newSub)
9242 newSub._notify('created', self)
9243 return newSub
9245 def addSubContribution( self, newSubCont ):
9246 newSubCont.setId(str( self.__subContGenerator.newCount()) )
9247 newSubCont.setOwner( self )
9248 self._subConts.append( newSubCont )
9249 self.notifyModification(cleanCache = False)
9251 def removeSubContribution( self, subCont ):
9252 if subCont in self._subConts:
9253 subCont.delete()
9254 subCont.setOwner(None)
9255 self._subConts.remove(subCont)
9256 self.notifyModification(cleanCache = False)
9258 def recoverSubContribution( self, recSubCont ):
9259 # Id must already be set in recSubCont.
9260 recSubCont.setOwner( self )
9261 self._subConts.append( recSubCont )
9262 recSubCont.recover()
9263 self.notifyModification(cleanCache = False)
9265 def getSubContributionById(self, SCId):
9266 for sb in self._subConts:
9267 if sb.getId() == SCId:
9268 return sb
9270 def getSubContributionList(self):
9271 return self._subConts
9273 def iterSubContributions(self):
9274 return iter(self._subConts)
9276 def getNumberOfSubcontributions(self):
9277 return len(self._subConts)
9279 def upSubContribution(self, subcont):
9280 if subcont in self._subConts:
9281 if self._subConts.index(subcont) != 0:
9282 index = self._subConts.index(subcont)
9283 sb = self._subConts.pop(index)
9284 self._subConts.insert(index-1, sb)
9285 self.notifyModification(cleanCache = False)
9287 def downSubContribution(self, subCont):
9288 if subCont in self._subConts:
9289 if self._subConts.index(subCont) < len(self._subConts)-1:
9290 index = self._subConts.index(subCont)
9291 sb = self._subConts.pop(index)
9292 self._subConts.insert(index+1, sb)
9293 self.notifyModification(cleanCache = False)
9295 def setPaper( self, newPaper ):
9296 if self.getPaper() != None:
9297 raise MaKaCError( _("The paper for this contribution has already been set"), _("Contribution"))
9298 self.paper=newPaper
9299 self.paper.setOwner( self )
9300 self.notifyModification()
9302 def removePaper( self ):
9303 if self.paper is None:
9304 return
9305 self.paper.delete()
9306 self.paper.setOwner(None)
9307 self.paper = None
9308 self.notifyModification()
9310 def recoverPaper(self, p):
9311 self.setPaper(p)
9312 p.recover()
9314 def getPaper( self ):
9315 return self.paper
9317 def setSlides( self, newSlides ):
9318 if self.getSlides() != None:
9319 raise MaKaCError( _("The slides for this contribution have already been set"), _("contribution"))
9320 self.slides=newSlides
9321 self.slides.setOwner( self )
9322 self.notifyModification()
9324 def removeSlides( self ):
9325 if self.slides is None:
9326 return
9327 self.slides.delete()
9328 self.slides.setOwner( None )
9329 self.slides= None
9330 self.notifyModification()
9332 def recoverSlides(self, s):
9333 self.setSlides(s)
9334 s.recover()
9336 def getSlides( self ):
9337 return self.slides
9339 def setVideo( self, newVideo ):
9340 if self.getVideo() != None:
9341 raise MaKaCError( _("the video for this contribution has already been set"))
9342 self.video=newVideo
9343 self.video.setOwner( self )
9344 self.notifyModification()
9346 def removeVideo( self ):
9347 if self.getVideo() is None:
9348 return
9349 self.video.delete()
9350 self.video.setOwner(None)
9351 self.video = None
9352 self.notifyModification()
9354 def recoverVideo(self, v):
9355 self.setVideo(v)
9356 v.recover()
9358 def getVideo( self ):
9359 try:
9360 if self.video:
9361 pass
9362 except AttributeError:
9363 self.video = None
9364 return self.video
9366 def setPoster( self, newPoster ):
9367 if self.getPoster() != None:
9368 raise MaKaCError( _("the poster for this contribution has already been set"))
9369 self.poster=newPoster
9370 self.poster.setOwner( self )
9371 self.notifyModification()
9373 def removePoster( self ):
9374 if self.getPoster() is None:
9375 return
9376 self.poster.delete()
9377 self.poster.setOwner(None)
9378 self.poster = None
9379 self.notifyModification()
9381 def recoverPoster(self, p):
9382 self.setPoster(p)
9383 p.recover()
9385 def getPoster( self ):
9386 try:
9387 if self.poster:
9388 pass
9389 except AttributeError:
9390 self.poster = None
9391 return self.poster
9393 def setMinutes( self, newMinutes ):
9394 if self.getMinutes() != None:
9395 raise MaKaCError( _("the Minutes for this contribution has already been set"))
9396 self.minutes=newMinutes
9397 self.minutes.setOwner( self )
9398 self.notifyModification()
9400 def createMinutes( self ):
9401 if self.getMinutes() != None:
9402 raise MaKaCError( _("The minutes for this contribution have already been created"), _("Contribution"))
9403 self.minutes = Minutes()
9404 self.minutes.setOwner( self )
9405 self.notifyModification()
9406 return self.minutes
9408 def removeMinutes( self ):
9409 if self.getMinutes() is None:
9410 return
9411 self.minutes.delete()
9412 self.minutes.setOwner( None )
9413 self.minutes = None
9414 self.notifyModification()
9416 def recoverMinutes(self, min):
9417 self.removeMinutes() # To ensure that the current minutes are put in
9418 # the trash can.
9419 self.minutes = min
9420 self.minutes.setOwner( self )
9421 min.recover()
9422 self.notifyModification()
9423 return self.minutes
9425 def getMinutes( self ):
9426 #To be removed
9427 try:
9428 if self.minutes:
9429 pass
9430 except AttributeError, e:
9431 self.minutes = None
9432 return self.minutes
9434 def setReviewing( self, newReviewing ):
9435 if self.getReviewing() != None:
9436 raise MaKaCError( _("The reviewing maretial for this contribution has already been set"), _("Contribution"))
9437 self.reviewing=newReviewing
9438 self.reviewing.setOwner( self )
9439 self.notifyModification()
9441 def removeReviewing( self ):
9442 if self.getReviewing() is None:
9443 return
9444 self.reviewing.delete()
9445 self.reviewing.setOwner(None)
9446 self.reviewing = None
9447 self.notifyModification()
9449 def recoverReviewing(self, p):
9450 self.setReviewing(p)
9451 p.recover()
9453 def getReviewing( self ):
9454 try:
9455 if self.reviewing:
9456 pass
9457 except AttributeError, e:
9458 self.reviewing = None
9459 return self.reviewing
9461 def getMasterSchedule( self ):
9462 return self.getOwner().getSchedule()
9464 def requireDomain( self, dom ):
9465 self.__ac.requireDomain( dom )
9466 self._notify('domainAdded', dom)
9468 def freeDomain( self, dom ):
9469 self.__ac.freeDomain( dom )
9470 self._notify('domainRemoved', dom)
9472 def getDomainList( self ):
9473 return self.__ac.getRequiredDomainList()
9475 def getTrack( self ):
9476 try:
9477 if self._track:
9478 pass
9479 except AttributeError:
9480 self._track = None
9481 return self._track
9483 def setTrack( self, newTrack ):
9484 currentTrack = self.getTrack()
9485 if newTrack == currentTrack:
9486 return
9487 if currentTrack:
9488 currentTrack.removeContribution( self )
9489 self._track = newTrack
9490 if self._track:
9491 self._track.addContribution( self )
9493 def removeTrack(self, track):
9494 if track == self._track:
9495 self._track = None
9497 def setType( self, newType ):
9498 self._type = newType
9500 def getType( self ):
9501 try:
9502 if self._type:
9503 pass
9504 except AttributeError:
9505 self._type = None
9506 return self._type
9508 def getModificationDate( self ):
9509 """Returns the date in which the contribution was last modified"""
9510 try:
9511 return self._modificationDS
9512 except:
9513 if self.getConference():
9514 self._modificationDS = self.getConference().getModificationDate()
9515 else:
9516 self._modificationDS = nowutc()
9517 return self._modificationDS
9519 def getCurrentStatus(self):
9520 try:
9521 if self._status:
9522 pass
9523 except AttributeError:
9524 self._status=ContribStatusNotSch(self)
9525 return self._status
9526 getStatus = getCurrentStatus
9528 def setStatus(self,newStatus):
9531 self._status=newStatus
9533 def withdraw(self,resp,comment):
9534 """ Remove or put a contribution in a conference
9537 if self.isWithdrawn():
9538 #put back the authors in the author index
9539 for auth in self.getAuthorList():
9540 self.getConference().getAuthorIndex().index(auth)
9541 for spk in self.getSpeakerList():
9542 self.getConference().getSpeakerIndex().index(spk)
9543 #change the status of the contribution
9544 self._status=ContribStatusNotSch(self)
9546 else:
9547 #remove the authors from the author index
9548 if self.getConference() is not None:
9549 for auth in self.getAuthorList():
9550 self.getConference().getAuthorIndex().unindex(auth)
9551 for spk in self.getSpeakerList():
9552 self.getConference().unindexSpeaker(spk)
9553 #remove the contribution from any schedule it is included
9554 if self.isScheduled():
9555 self.getSchEntry().getSchedule().removeEntry(self.getSchEntry())
9556 self.getCurrentStatus().withdraw(resp,comment)
9559 def getSubmitterList(self, no_groups=False):
9560 try:
9561 if self._submitters:
9562 pass
9563 except AttributeError:
9564 self._submitters=[] #create the attribute
9565 self.notifyModification(raiseEvent = False)
9566 if no_groups:
9567 return filter(lambda s: not isinstance(s, MaKaC.user.Group), self._submitters)
9568 else:
9569 return self._submitters
9571 def _grantSubmission(self,av):
9572 if av not in self.getSubmitterList():
9573 self.getSubmitterList().append(av)
9574 if self.getConference() is not None:
9575 self.getConference().addContribSubmitter(self,av)
9576 if isinstance(av, MaKaC.user.Avatar):
9577 av.linkTo(self, "submission")
9578 self.notifyModification(raiseEvent = False)
9580 def _grantSubmissionEmail(self, email):
9581 """Returns True if submission email was granted. False if email was already in the list.
9583 if not email.lower() in map(lambda x: x.lower(), self.getSubmitterEmailList()):
9584 self.getSubmitterEmailList().append(email.lower().strip())
9585 return True
9586 return False
9588 def revokeSubmissionEmail(self, email):
9589 if email in self.getSubmitterEmailList():
9590 self.getSubmitterEmailList().remove(email)
9591 self._p_changed=1
9593 def grantSubmission(self, sb, sendEmail=True):
9594 """Grants a user with submission privileges for the contribution
9595 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9597 if isinstance(sb, ContributionParticipation) or isinstance(sb, SubContribParticipation):
9598 ah = AvatarHolder()
9599 results=ah.match({"email":sb.getEmail()}, exact=1, forceWithoutExtAuth=True)
9600 if not results:
9601 results=ah.match({"email":sb.getEmail()}, exact=1)
9602 r=None
9603 for i in results:
9604 if i.hasEmail(sb.getEmail()):
9606 break
9607 if r and r.isActivated():
9608 self._grantSubmission(r)
9609 elif sb.getEmail():
9610 self.getConference().getPendingQueuesMgr().addPendingSubmitter(sb, False)
9611 submissionEmailGranted = self._grantSubmissionEmail(sb.getEmail())
9612 if submissionEmailGranted and sendEmail:
9613 notif = pendingQueues._PendingSubmitterNotification( [sb] )
9614 mail.GenericMailer.sendAndLog( notif, self.getConference() )
9615 if self.getConference():
9616 self.getConference().addContribSubmitter(self,sb)
9617 else:
9618 self._grantSubmission(sb)
9620 def _revokeSubmission(self, av):
9621 if av in self.getSubmitterList():
9622 self.getSubmitterList().remove(av)
9623 if self.getConference():
9624 self.getConference().removeContribSubmitter(self, av)
9625 if isinstance(av, MaKaC.user.Avatar):
9626 av.unlinkTo(self, "submission")
9627 self.notifyModification(raiseEvent = False)
9629 def revokeSubmission(self, sb):
9630 """Removes submission privileges for the specified user
9631 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9633 if isinstance(sb, ContributionParticipation) or isinstance(sb, SubContribParticipation):
9634 ah = AvatarHolder()
9635 results = ah.match({"email":sb.getEmail()}, exact=1, forceWithoutExtAuth=True)
9636 r = None
9637 for i in results:
9638 if i.hasEmail(sb.getEmail()):
9640 break
9641 if r:
9642 self._revokeSubmission(r)
9643 else:
9644 self.revokeSubmissionEmail(sb.getEmail())
9645 else:
9646 self._revokeSubmission(sb)
9648 def revokeAllSubmitters(self):
9649 self._submitters = []
9650 self.notifyModification(raiseEvent = False)
9652 def getSubmitterEmailList(self):
9653 try:
9654 return self._submittersEmail
9655 except:
9656 self._submittersEmail = []
9657 return self._submittersEmail
9659 def canUserSubmit(self, sb):
9660 """Tells whether a user can submit material for the current contribution
9661 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9663 if sb is None:
9664 return False
9666 if isinstance(sb, ContributionParticipation) or isinstance(sb, SubContribParticipation):
9667 sbEmail = sb.getEmail()
9669 # Normally, we shouldn't get here unless we're adding someone as a Speaker or similar.
9670 # `no_groups` is used so that we do not consider group membership, as to not confuse the
9671 # user (since there will be speakers with "implicit" privileges) and avoid that hasEmail breaks
9672 return any(submitter.hasEmail(sbEmail) for submitter in self.getSubmitterList(no_groups=True)) or \
9673 any(submitterEmail == sbEmail for submitterEmail in self.getSubmitterEmailList())
9675 for principal in self.getSubmitterList():
9676 if principal != None and principal.containsUser(sb):
9677 return True
9679 return False
9681 def getAccessController(self):
9682 return self.__ac
9684 def getReportNumberHolder(self):
9685 try:
9686 if self._reportNumberHolder:
9687 pass
9688 except AttributeError, e:
9689 self._reportNumberHolder=ReportNumberHolder(self)
9690 return self._reportNumberHolder
9692 def setReportNumberHolder(self, rnh):
9693 self._reportNumberHolder=rnh
9695 @classmethod
9696 def contributionStartDateForSort(cls, contribution):
9697 """ Function that can be used as "key" argument to sort a list of contributions by start date
9698 The contributions with no start date will be at the end with this sort
9700 if contribution.getStartDate():
9701 return contribution.getStartDate()
9702 else:
9703 return maxDatetime()
9705 def getColor(self):
9706 res=""
9707 if self.getSession() is not None:
9708 res=self.getSession().getColor()
9709 return res
9711 def getTextColor(self):
9712 res=""
9713 if self.getSession() is not None:
9714 res=self.getSession().getTextColor()
9715 return res
9717 def getCSBookingManager(self):
9718 return self.getConference().getCSBookingManager()
9720 class AcceptedContribution( Contribution ):
9721 """This class represents a contribution which has been created from an
9722 abstract
9725 def __init__(self,abstract):
9726 Contribution.__init__(self)
9727 abstract.getConference().addContribution(self,abstract.getId())
9728 self._abstract = abstract
9729 self.setTitle( abstract.getTitle() )
9730 #self.setDescription(abstract.getField("content"))
9731 for key in abstract.getFields().keys():
9732 #if key != "content":
9733 self.setField(key, abstract.getField(key))
9734 if isinstance( abstract.getCurrentStatus(),review.AbstractStatusAccepted ):
9735 self.setTrack( abstract.getCurrentStatus().getTrack() )
9736 self.setType( abstract.getCurrentStatus().getType() )
9737 for auth in abstract.getAuthorList():
9738 c_auth = ContributionParticipation()
9739 self._setAuthorValuesFromAbstract( c_auth, auth )
9740 if abstract.isPrimaryAuthor( auth ):
9741 self.addPrimaryAuthor( c_auth )
9742 else:
9743 self.addCoAuthor( c_auth )
9744 if abstract.isSpeaker( auth ):
9745 self.addSpeaker( c_auth )
9746 self._grantSubmission(self.getAbstract().getSubmitter().getUser())
9748 def _setAuthorValuesFromAbstract( self, cAuth, aAuth ):
9749 cAuth.setTitle( aAuth.getTitle() )
9750 cAuth.setFirstName( aAuth.getFirstName() )
9751 cAuth.setFamilyName( aAuth.getSurName() )
9752 cAuth.setEmail( aAuth.getEmail() )
9753 cAuth.setAffiliation( aAuth.getAffiliation() )
9754 cAuth.setAddress( aAuth.getAddress() )
9755 cAuth.setPhone( aAuth.getTelephone() )
9757 def getAbstract( self ):
9758 return self._abstract
9760 def setAbstract(self, abs):
9761 self._abstract = abs
9763 def getSubmitterList(self, no_groups=False):
9764 try:
9765 if self._submitters:
9766 pass
9767 except AttributeError:
9768 self._submitters=[]#create the attribute
9769 self._grantSubmission(self.getAbstract().getSubmitter().getUser())
9770 if no_groups:
9771 return filter(lambda s: not isinstance(s, MaKaC.user.Group), self._submitters)
9772 else:
9773 return self._submitters
9775 def delete( self ):
9776 """deletes a contribution and all of their subitems
9778 abs = self.getAbstract()
9779 if abs:
9780 cs=abs.getCurrentStatus()
9781 if isinstance(cs, review.AbstractStatusAccepted):
9782 if cs.getTrack() is not None:
9783 abs.addTrack(cs.getTrack())
9784 abs.setCurrentStatus(review.AbstractStatusSubmitted(abs))
9785 abs._setContribution(None)
9786 self.setAbstract(None)
9787 Contribution.delete(self)
9791 class ContribStatus(Persistent):
9795 def __init__(self,contribution,responsible):
9796 self._setContrib(contribution)
9797 self._setResponsible(responsible)
9798 self._setDate()
9800 def clone(self, contribution, responsible):
9801 cs = ContribStatus(contribution, responsible)
9802 cs.setDate(self.getDate())
9803 return cs
9805 def _setContrib(self,newContrib):
9806 self._contrib=newContrib
9808 def getContrib(self):
9809 return self._contrib
9811 def _setResponsible(self,newResp):
9812 self._responsible=newResp
9814 def getResponsible(self):
9815 return self._responsible
9817 def _setDate(self):
9818 self._date=nowutc()
9820 def setDate(self, date):
9821 self._date = date
9823 def getDate(self):
9824 return self._date
9826 def withdraw(self,resp,comments=""):
9827 self._contrib.setStatus(ContribStatusWithdrawn(self.getContrib(),resp,comments))
9829 class ContribStatusNotSch(ContribStatus):
9832 def __init__(self,contrib):
9833 ContribStatus.__init__(self,contrib,None)
9835 def clone(self, contribution):
9836 csns = ContribStatusNotSch(contribution)
9837 csns.setDate(self.getDate())
9838 return csns
9840 ContribStatusSubmitted=ContribStatusNotSch
9842 class ContribStatusSch(ContribStatus):
9845 def __init__(self,contrib):
9846 ContribStatus.__init__(self,contrib,None)
9848 def clone(self, contribution):
9849 css = ContribStatusSch(contribution)
9850 css.setDate(self.getDate())
9851 return css
9853 class ContribStatusWithdrawn(ContribStatus):
9856 def __init__(self,contrib,resp,comments):
9857 ContribStatus.__init__(self,contrib,resp)
9858 self._setComment(comments)
9860 def clone(self, contribution):
9861 csw = ContribStatusWithdrawn(contribution)
9862 csw.setDate(self.getDate())
9863 csw.setComment(self.getComment())
9864 return csw
9866 def _setComment(self,text):
9867 self._comment=text.strip()
9869 def getComment(self):
9870 return self._comment
9872 class ContribStatusNone(ContribStatus):
9873 # This is a special status we assign to contributions that are put in the trash can.
9875 def __init__(self,contrib):
9876 ContribStatus.__init__(self,contrib,None)
9878 def clone(self, contribution):
9879 csn = ContribStatusNone(contribution)
9880 csn.setDate(self.getDate())
9881 return csn
9883 class SubContribParticipation(Persistent, Fossilizable):
9885 fossilizes(ISubContribParticipationFossil, ISubContribParticipationFullFossil)
9887 def __init__( self ):
9888 self._subContrib = None
9889 self._id = ""
9890 self._firstName = ""
9891 self._surName = ""
9892 self._email = ""
9893 self._affiliation = ""
9894 self._address = ""
9895 self._phone = ""
9896 self._title = ""
9897 self._fax = ""
9899 def getConference(self):
9900 if self._subContrib is not None:
9901 return self._subContrib.getConference()
9902 return None
9904 def _notifyModification( self ):
9905 if self._subContrib != None:
9906 self._subContrib.notifyModification()
9908 def setValues(self, data):
9909 self.setFirstName(data.get("firstName", ""))
9910 self.setFamilyName(data.get("familyName",""))
9911 self.setAffiliation(data.get("affilation",""))
9912 self.setAddress(data.get("address",""))
9913 self.setEmail(data.get("email",""))
9914 self.setFax(data.get("fax",""))
9915 self.setTitle(data.get("title",""))
9916 self.setPhone(data.get("phone",""))
9917 self._notifyModification()
9919 def getValues(self):
9920 data={}
9921 data["firstName"]=self.getFirstName()
9922 data["familyName"]=self.getFamilyName()
9923 data["affilation"]=self.getAffiliation()
9924 data["address"]=self.getAddress()
9925 data["email"]=self.getEmail()
9926 data["fax"]=self.getFax()
9927 data["title"]=self.getTitle()
9928 data["phone"]=self.getPhone()
9929 return data
9931 def clone(self):
9932 part = SubContribParticipation()
9933 part.setValues(self.getValues())
9934 return part
9936 def setDataFromAvatar(self,av):
9937 # av is an Avatar object.
9938 if av is None:
9939 return
9940 self.setFirstName(av.getName())
9941 self.setFamilyName(av.getSurName())
9942 self.setEmail(av.getEmail())
9943 self.setAffiliation(av.getOrganisation())
9944 self.setAddress(av.getAddress())
9945 self.setPhone(av.getTelephone())
9946 self.setTitle(av.getTitle())
9947 self.setFax(av.getFax())
9948 self._notifyModification()
9950 def setDataFromAuthor(self,au):
9951 # au is a ContributionParticipation object.
9952 if au is None:
9953 return
9954 self.setFirstName(au.getFirstName())
9955 self.setFamilyName(au.getFamilyName())
9956 self.setEmail(au.getEmail())
9957 self.setAffiliation(au.getAffiliation())
9958 self.setAddress(au.getAddress())
9959 self.setPhone(au.getPhone())
9960 self.setTitle(au.getTitle())
9961 self.setFax(au.getFax())
9962 self._notifyModification()
9964 def setDataFromSpeaker(self,spk):
9965 # spk is a SubContribParticipation object.
9966 if spk is None:
9967 return
9968 self.setFirstName(spk.getFirstName())
9969 self.setFamilyName(spk.getFamilyName())
9970 self.setEmail(spk.getEmail())
9971 self.setAffiliation(spk.getAffiliation())
9972 self.setAddress(spk.getAddress())
9973 self.setPhone(spk.getPhone())
9974 self.setTitle(spk.getTitle())
9975 self.setFax(spk.getFax())
9976 self._notifyModification()
9978 def includeInSubContrib( self, subcontrib, id ):
9979 if self.getSubContrib() == subcontrib and self.getId()==id.strip():
9980 return
9981 self._subContrib = subcontrib
9982 self._id = id
9984 def delete( self ):
9985 self._subContrib = None
9986 TrashCanManager().add(self)
9988 def recover(self):
9989 TrashCanManager().remove(self)
9991 @Updates ('MaKaC.conference.SubContribParticipation', 'id')
9992 def setId(self, newId):
9993 self._id = newId
9995 def getId( self ):
9996 return self._id
9998 def getSubContrib( self ):
9999 return self._subContrib
10001 def getContribution( self ):
10002 if self._subContrib is not None:
10003 return self._subContrib.getContribution()
10004 return None
10006 # def getLocator(self):
10007 # if self.getSubContrib() is None:
10008 # return None
10009 # loc=self.getSubContrib().getLocator()
10010 # loc["authId"]=self.getId()
10011 # return loc
10013 def _unindex(self):
10014 contrib=self.getContribution()
10015 if contrib is not None:
10016 conf=contrib.getConference()
10017 if conf is not None:
10018 conf.unindexAuthor(self)
10019 conf.unindexSpeaker(self)
10021 def _index(self):
10022 contrib=self.getContribution()
10023 if contrib is not None:
10024 conf=contrib.getConference()
10025 if conf is not None:
10026 conf.indexAuthor(self)
10027 conf.indexSpeaker(self)
10029 @Updates ('MaKaC.conference.SubContribParticipation', 'firstName')
10030 def setFirstName( self, newName ):
10031 tmp=newName.strip()
10032 if tmp==self._firstName:
10033 return
10034 self._unindex()
10035 self._firstName=tmp
10036 self._index()
10037 self._notifyModification()
10039 def getFirstName( self ):
10040 return self._firstName
10042 def getName( self ):
10043 return self._firstName
10045 @Updates ('MaKaC.conference.SubContribParticipation', 'familyName')
10046 def setFamilyName( self, newName ):
10047 tmp=newName.strip()
10048 if tmp==self._surName:
10049 return
10050 self._unindex()
10051 self._surName=tmp
10052 self._index()
10053 self._notifyModification()
10055 def getFamilyName( self ):
10056 return self._surName
10058 def getSurName( self ):
10059 return self._surName
10061 @Updates ('MaKaC.conference.SubContribParticipation', 'email')
10062 def setEmail( self, newMail ):
10063 tmp=newMail.strip()
10064 if tmp==self._email:
10065 return
10066 self._unindex()
10067 self._email=newMail.strip()
10068 self._index()
10069 self._notifyModification()
10071 def getEmail( self ):
10072 return self._email
10074 @Updates ('MaKaC.conference.SubContribParticipation', 'affiliation')
10075 def setAffiliation( self, newAffil ):
10076 self._affiliation = newAffil.strip()
10077 self._notifyModification()
10079 def getAffiliation( self ):
10080 return self._affiliation
10082 @Updates ('MaKaC.conference.SubContribParticipation', 'address')
10083 def setAddress( self, newAddr ):
10084 self._address = newAddr.strip()
10085 self._notifyModification()
10087 def getAddress( self ):
10088 return self._address
10090 @Updates ('MaKaC.conference.SubContribParticipation', 'phone')
10091 def setPhone( self, newPhone ):
10092 self._phone = newPhone.strip()
10093 self._notifyModification()
10095 def getPhone( self ):
10096 return self._phone
10098 @Updates ('MaKaC.conference.SubContribParticipation', 'title')
10099 def setTitle( self, newTitle ):
10100 self._title = newTitle.strip()
10101 self._notifyModification()
10103 def getTitle( self ):
10104 return self._title
10106 def setFax( self, newFax ):
10107 self._fax = newFax.strip()
10108 self._notifyModification()
10110 def getFax( self ):
10111 try:
10112 if self._fax:
10113 pass
10114 except AttributeError:
10115 self._fax=""
10116 return self._fax
10118 def getFullName( self ):
10119 res = self.getFullNameNoTitle()
10120 if self.getTitle() != "":
10121 res = "%s %s"%( self.getTitle(), res )
10122 return res
10124 def getFullNameNoTitle( self ):
10125 res = self.getFamilyName().decode('utf-8').upper().encode('utf-8')
10126 if self.getFirstName() != "":
10127 if res.strip() != "":
10128 res = "%s, %s"%( res, self.getFirstName() )
10129 else:
10130 res = self.getFirstName()
10131 return res
10133 def getAbrName(self):
10134 res = self.getFamilyName()
10135 if self.getFirstName() != "":
10136 if res != "":
10137 res = "%s, "%res
10138 res = "%s%s."%(res, self.getFirstName()[0].upper())
10139 return res
10141 def getDirectFullName( self ):
10142 res = self.getDirectFullNameNoTitle()
10143 if self.getTitle() != "":
10144 res = "%s %s"%( self.getTitle(), res )
10145 return res
10147 def getDirectFullNameNoTitle( self, upper = True ):
10148 return ("%s %s"%(self.getFirstName(), self.getFamilyName().upper() if upper else self.getFamilyName())).strip()
10150 class SubContribution(CommonObjectBase, Locatable):
10154 fossilizes(ISubContributionFossil, ISubContributionWithSpeakersFossil)
10156 def __init__( self, **subContData ):
10157 self.parent = None
10158 self.id = ""
10159 self.title = ""
10160 self.description = ""
10161 self.__schEntry = None
10162 self.duration = timedelta( minutes=15 )
10163 self.speakers = []
10164 self.speakerText = ""
10166 self.materials = {}
10167 self.__materialGenerator = Counter() # Provides material unique
10168 # identifiers whithin the current
10169 self.poster = None # contribution
10170 self.paper = None
10171 self.slides = None
10172 self.video = None
10173 self.poster = None
10174 self.minutes = None
10175 self._authorGen = Counter()
10176 self._keywords = ""
10178 def __str__(self):
10179 if self.parent:
10180 parentId = self.parent.getId()
10181 if self.getConference():
10182 grandpaId = self.getConference().getId()
10183 else:
10184 grandpaId = None
10185 else:
10186 parentId = None
10187 grandpaId = None
10188 return "<SubCont %s:%s:%s@%s>" % (grandpaId, parentId, self.getId(), hex(id(self)))
10190 def updateNonInheritingChildren(self, elem, delete=False):
10191 self.getOwner().updateNonInheritingChildren(elem, delete)
10193 def getAccessController(self):
10194 return self.getOwner().getAccessController()
10196 def getKeywords(self):
10197 try:
10198 return self._keywords
10199 except:
10200 self._keywords = ""
10201 return ""
10203 def setKeywords(self, keywords):
10204 self._keywords = keywords
10206 def getLogInfo(self):
10207 data = {}
10209 data["subject"] = self.getTitle()
10210 data["id"] = self.id
10211 data["title"] = self.title
10212 data["parent title"] = self.getParent().getTitle()
10213 data["description"] = self.description
10214 data["duration"] = "%s"%self.duration
10215 data["minutes"] = self.minutes
10217 for sp in self.speakers :
10218 data["speaker %s"%sp.getId()] = sp.getFullName()
10220 return data
10223 def clone(self, deltaTime, parent, options):
10224 sCont = SubContribution()
10225 sCont.setParent(parent)
10226 sCont.setTitle(self.getTitle())
10227 sCont.setDescription(self.getDescription())
10228 sCont.setKeywords(self.getKeywords())
10229 dur = self.getDuration()
10230 hours = dur.seconds / 3600
10231 minutes = (dur.seconds % 3600) / 60
10232 sCont.setDuration(hours, minutes)
10233 sCont.setReportNumberHolder(self.getReportNumberHolder().clone(self))
10235 # There is no _order attribute in this class
10237 if options.get("authors", False) :
10238 for s in self.getSpeakerList() :
10239 sCont.newSpeaker(s.clone())
10240 sCont.setSpeakerText(self.getSpeakerText())
10242 if options.get("materials", False) :
10243 for m in self.getMaterialList() :
10244 sCont.addMaterial(m.clone(sCont))
10245 if self.getPaper() is not None:
10246 sCont.setPaper(self.getPaper().clone(sCont))
10247 if self.getSlides() is not None:
10248 sCont.setSlides(self.getSlides().clone(sCont))
10249 if self.getVideo() is not None:
10250 sCont.setVideo(self.getVideo().clone(sCont))
10251 if self.getPoster() is not None:
10252 sCont.setPoster(self.getPoster().clone(sCont))
10253 if self.getMinutes() is not None:
10254 sCont.setMinutes(self.getMinutes().clone(sCont))
10257 sCont.notifyModification()
10258 return sCont
10260 def notifyModification(self, raiseEvent = True):
10261 parent = self.getParent()
10262 if parent:
10263 parent.setModificationDate()
10264 if raiseEvent:
10265 self._notify('infoChanged')
10266 self._p_changed = 1
10268 def getCategoriesPath(self):
10269 return self.getConference().getCategoriesPath()
10271 def getLocator( self ):
10272 """Gives back a globaly unique identification encapsulated in a Locator
10273 object for the contribution instance
10276 lconf = self.getOwner().getLocator()
10277 lconf["subContId"] = self.getId()
10278 return lconf
10281 def setId( self, newId ):
10282 self.id = newId
10284 def getId( self ):
10285 return self.id
10287 def getUniqueId( self ):
10288 """returns (string) the unique identifier of the item"""
10289 """used mainly in the web session access key table"""
10290 return "%ssc%s" % (self.getParent().getUniqueId(),self.id)
10292 def setTitle( self, newTitle ):
10293 self.title = newTitle.strip()
10294 self.notifyModification()
10296 def getTitle( self ):
10297 if self.title.strip() == "":
10298 return "(no title)"
10299 return self.title
10301 def setDescription( self, newDesc ):
10302 self.description = newDesc.strip()
10303 self.notifyModification()
10305 def getDescription( self ):
10306 return self.description
10308 def setParent(self,parent):
10309 self.parent = parent
10310 if self.parent == None:
10311 return
10313 def getParent( self ):
10314 return self.parent
10316 def setOwner(self, owner):
10317 self.setParent(owner)
10319 def getOwner( self ):
10320 return self.getParent()
10322 def getConference( self ):
10323 return self.parent.getConference()
10325 def getSession( self ):
10326 return self.parent.getSession()
10328 def getContribution(self):
10329 return self.parent
10331 def getDuration( self ):
10332 return self.duration
10334 def setDuration( self, hours, minutes=0, dur=0 ):
10335 if dur!=0:
10336 self.duration=dur
10337 else:
10338 hours = int( hours )
10339 minutes = int( minutes )
10340 self.duration = timedelta(hours=hours,minutes=minutes )
10341 self.notifyModification()
10343 def getLocation( self ):
10344 return self.getOwner().getLocation()
10346 def getRoom( self ):
10347 return self.getOwner().getRoom()
10349 def getSpeakerById( self, id ):
10352 for spk in self.speakers:
10353 if spk.getId() == id:
10354 return spk
10355 return None
10357 def newSpeaker( self, spk ):
10360 self.speakers.append( spk )
10361 try:
10362 if self._authorGen:
10363 pass
10364 except AttributeError:
10365 self._authorGen=Counter()
10366 newId = spk.getId()
10367 if newId == "":
10368 newId = str( self._authorGen.newCount() )
10369 spk.includeInSubContrib(self, newId)
10370 if self.getConference() is not None:
10371 self.getConference().indexSpeaker(spk)
10372 self.notifyModification()
10374 def removeSpeaker( self, spk ):
10377 if spk not in self.speakers:
10378 return
10379 self.speakers.remove( spk )
10380 if self.getConference() is not None:
10381 self.getConference().unindexSpeaker(spk)
10382 spk.delete()
10383 self.notifyModification()
10385 def recoverSpeaker(self, spk):
10386 self.newSpeaker(spk)
10387 spk.recover()
10389 def isSpeaker( self, spk):
10392 return spk in self._speakers
10394 def getSpeakerList ( self ):
10397 return self.speakers
10399 def getSpeakerText( self ):
10400 #to be removed
10401 try:
10402 if self.speakerText:
10403 pass
10404 except AttributeError, e:
10405 self.speakerText = ""
10406 return self.speakerText
10408 def setSpeakerText( self, newText ):
10409 self.speakerText = newText.strip()
10411 def appendSpeakerText( self, newText ):
10412 self.setSpeakerText( "%s, %s"%(self.getSpeakerText(), newText.strip()) )
10414 # """
10415 # There is no _order attribute in this class -
10416 # the methods below are either obsolate or the feature has not been implemented
10417 # """
10418 # def setOrder( self, order ):
10419 # self._order = order
10420 # self.notifyModification()
10422 # def getOrder(self):
10423 # return self._order
10425 def canIPAccess( self, ip ):
10426 return self.getOwner().canIPAccess(ip)
10428 def isProtected( self ):
10429 return self.hasProtectedOwner()
10431 def getAccessProtectionLevel( self ):
10432 return self.getOwner().getAccessProtectionLevel()
10434 def hasAnyProtection( self ):
10435 """Tells whether a subContribution has any kind of protection over it:
10436 access or domain protection.
10438 return self.getOwner().hasAnyProtection()
10440 def getManagerList( self ):
10441 return self.parent.getManagerList()
10443 def hasProtectedOwner( self ):
10444 if self.getOwner() != None:
10445 return self.getOwner().isProtected()
10446 return False
10448 def getAccessKey( self ):
10449 return self.getOwner().getAccessKey()
10451 def getModifKey( self ):
10452 return self.getConference().getModifKey()
10454 def canView( self, aw ):
10455 """tells whether the specified user has access to the current object
10456 or any of its sub-objects
10458 if self.canAccess( aw ):
10459 return True
10460 return False
10462 def isAllowedToAccess( self, user ):
10463 return self.parent.isAllowedToAccess( user )
10465 def canAccess( self, aw ):
10466 return self.getOwner().canAccess(aw)
10468 def canModify( self, aw ):
10469 return self.canUserModify( aw.getUser() ) or self.getConference().canKeyModify( aw )
10471 def canUserModify( self, av ):
10472 """Tells whether a user is allowed to modify the current contribution:
10473 only if the user is granted to modify the contribution or the user
10474 can modify any of its upper objects (i.e. conference or session).
10476 return self.getParent().canUserModify( av )
10478 def canUserSubmit( self, av ):
10479 return self.getOwner().canUserSubmit( av )
10481 def getAllowedToAccessList( self ):
10482 """Currently the SubContribution class has no access list.
10483 But instead of returning the owner Contribution's access list,
10484 I am returning an empty list. Methods such as getRecursiveAllowedToAccess()
10485 will call the owner Contribution anyway.
10487 return []
10489 def addMaterial( self, newMat ):
10490 newMat.setId( str(self.__materialGenerator.newCount()) )
10491 newMat.setOwner( self )
10492 self.materials[ newMat.getId() ] = newMat
10493 self.notifyModification()
10495 def removeMaterial( self, mat):
10496 if mat.getId() in self.materials.keys():
10497 mat.delete()
10498 self.materials[mat.getId()].setOwner(None)
10499 del self.materials[ mat.getId() ]
10500 self.notifyModification()
10501 elif mat.getId().lower() == 'paper':
10502 self.removePaper()
10503 self.notifyModification()
10504 elif mat.getId().lower() == 'slides':
10505 self.removeSlides()
10506 self.notifyModification()
10507 elif mat.getId().lower() == 'minutes':
10508 self.removeMinutes()
10509 self.notifyModification()
10510 elif mat.getId().lower() == 'video':
10511 self.removeVideo()
10512 self.notifyModification()
10513 elif mat.getId().lower() == 'poster':
10514 self.removePoster()
10515 self.notifyModification()
10517 def recoverMaterial(self, recMat):
10518 # Id must already be set in recMat.
10519 recMat.setOwner( self )
10520 self.materials[ recMat.getId() ] = recMat
10521 recMat.recover()
10522 self.notifyModification()
10524 def getMaterialRegistry(self):
10526 Return the correct material registry for this type
10528 from MaKaC.webinterface.materialFactories import SubContributionMFRegistry
10529 return SubContributionMFRegistry
10531 def getMaterialById( self, matId ):
10532 if matId.lower() == 'paper':
10533 return self.getPaper()
10534 elif matId.lower() == 'slides':
10535 return self.getSlides()
10536 elif matId.lower() == 'video':
10537 return self.getVideo()
10538 elif matId.lower() == 'poster':
10539 return self.getPoster()
10540 elif matId.lower() == 'minutes':
10541 return self.getMinutes()
10542 elif self.materials.has_key(matId):
10543 return self.materials[ matId ]
10544 return None
10546 def getMaterialList( self ):
10547 return self.materials.values()
10549 def getAllMaterialList(self, sort=True):
10550 l = self.getMaterialList()
10551 if self.getPaper():
10552 l.append( self.getPaper() )
10553 if self.getSlides():
10554 l.append( self.getSlides() )
10555 if self.getVideo():
10556 l.append( self.getVideo() )
10557 if self.getMinutes():
10558 l.append( self.getMinutes() )
10559 if self.getPoster():
10560 l.append( self.getPoster() )
10561 if sort:
10562 l.sort(lambda x,y: cmp(x.getTitle(),y.getTitle()))
10563 return l
10565 def setPaper( self, newPaper ):
10566 if self.getPaper() != None:
10567 raise MaKaCError( _("The paper for this subcontribution has already been set"), _("Contribution"))
10568 self.paper=newPaper
10569 self.paper.setOwner( self )
10570 self.notifyModification()
10572 def removePaper( self ):
10573 if self.getPaper() is None:
10574 return
10575 self.paper.delete()
10576 self.paper.setOwner(None)
10577 self.paper = None
10578 self.notifyModification()
10580 def recoverPaper(self, p):
10581 self.setPaper(p)
10582 p.recover()
10584 def getPaper( self ):
10585 return self.paper
10587 def setSlides( self, newSlides ):
10588 if self.getSlides() != None:
10589 raise MaKaCError( _("The slides for this subcontribution have already been set"), _("Contribution"))
10590 self.slides=newSlides
10591 self.slides.setOwner( self )
10592 self.notifyModification()
10594 def removeSlides( self ):
10595 if self.getSlides() is None:
10596 return
10597 self.slides.delete()
10598 self.slides.setOwner( None )
10599 self.slides = None
10600 self.notifyModification()
10602 def recoverSlides(self, s):
10603 self.setSlides(s)
10604 s.recover()
10606 def getSlides( self ):
10607 return self.slides
10609 def setVideo( self, newVideo ):
10610 if self.getVideo() != None:
10611 raise MaKaCError( _("the video for this subcontribution has already been set"))
10612 self.video=newVideo
10613 self.video.setOwner( self )
10614 self.notifyModification()
10616 def removeVideo( self ):
10617 if self.getVideo() is None:
10618 return
10619 self.video.delete()
10620 self.video.setOwner(None)
10621 self.video = None
10622 self.notifyModification()
10624 def recoverVideo(self, v):
10625 self.setVideo(v)
10626 v.recover()
10628 def getVideo( self ):
10629 try:
10630 if self.video:
10631 pass
10632 except AttributeError:
10633 self.video = None
10634 return self.video
10636 def setPoster( self, newPoster ):
10637 if self.getPoster() != None:
10638 raise MaKaCError( _("the poster for this subcontribution has already been set"))
10639 self.poster=newPoster
10640 self.poster.setOwner( self )
10641 self.notifyModification()
10643 def removePoster( self ):
10644 if self.getPoster() is None:
10645 return
10646 self.poster.delete()
10647 self.poster.setOwner(None)
10648 self.poster = None
10649 self.notifyModification()
10651 def recoverPoster(self, p):
10652 self.setPoster(p)
10653 p.recover()
10655 def getPoster( self ):
10656 try:
10657 if self.poster:
10658 pass
10659 except AttributeError:
10660 self.poster = None
10661 return self.poster
10663 def setMinutes( self, newMinutes ):
10664 if self.getMinutes() != None:
10665 raise MaKaCError( _("the Minutes for this subcontribution has already been set"))
10666 self.minutes=newMinutes
10667 self.minutes.setOwner( self )
10668 self.notifyModification()
10670 def createMinutes( self ):
10671 if self.getMinutes() != None:
10672 raise MaKaCError( _("The minutes for this subcontribution have already been created"), _("Sub Contribution"))
10673 self.minutes = Minutes()
10674 self.minutes.setOwner( self )
10675 self.notifyModification()
10676 return self.minutes
10678 def removeMinutes( self ):
10679 if self.getMinutes() is None:
10680 return
10681 self.minutes.delete()
10682 self.minutes.setOwner( None )
10683 self.minutes = None
10684 self.notifyModification()
10686 def recoverMinutes(self, min):
10687 self.removeMinutes() # To ensure that the current minutes are put in
10688 # the trash can.
10689 self.minutes = min
10690 self.minutes.setOwner( self )
10691 min.recover()
10692 self.notifyModification()
10693 return self.minutes
10695 def getMinutes( self ):
10696 #To be removed
10697 try:
10698 if self.minutes:
10699 pass
10700 except AttributeError, e:
10701 self.minutes = None
10702 return self.minutes
10704 def getMasterSchedule( self ):
10705 return self.getOwner().getSchedule()
10707 def delete(self):
10709 self._notify('deleted', self.getOwner())
10711 while len(self.getSpeakerList()) > 0:
10712 self.removeSpeaker(self.getSpeakerList()[0])
10713 for mat in self.getMaterialList():
10714 self.removeMaterial(mat)
10715 self.removePaper()
10716 self.removeSlides()
10717 self.removeVideo()
10718 self.removePoster()
10719 self.removeMinutes()
10720 TrashCanManager().add(self)
10722 #self.unindex()
10724 def recover(self):
10725 TrashCanManager().remove(self)
10727 def getReportNumberHolder(self):
10728 try:
10729 if self._reportNumberHolder:
10730 pass
10731 except AttributeError, e:
10732 self._reportNumberHolder=ReportNumberHolder(self)
10733 return self._reportNumberHolder
10735 def setReportNumberHolder(self, rnh):
10736 self._reportNumberHolder=rnh
10738 class Material(CommonObjectBase):
10739 """This class represents a set of electronic documents (resources) which can
10740 be attached to a conference, a session or a contribution.
10741 A material can be of several types (achieved by specialising this class)
10742 and is like a container of files which have some relation among them.
10743 It contains the minimal set of attributes to store basic meta data and
10744 provides useful operations to access and manage it.
10745 Attributes:
10746 owner -- (Conference, Session or Contribution) Object to which the
10747 material is attached to
10748 id -- (string) Material unique identifier. Normally used to uniquely
10749 identify a material within a conference, session or contribution
10750 title -- (string) Material denomination
10751 description -- (string) Longer text describing in more detail material
10752 intentions
10753 type -- (string) String identifying the material classification
10754 resources -- (PMapping) Collection of resouces grouped within the
10755 material. Dictionary of references to Resource objects indexed
10756 by their unique relative id.
10759 fossilizes(IMaterialMinimalFossil, IMaterialFossil)
10761 def __init__( self, materialData=None ):
10762 self.id = "not assigned"
10763 self.__resources = {}
10764 self.__resourcesIdGen = Counter()
10765 self.title = ""
10766 self.description = ""
10767 self.type = ""
10768 self.owner = None
10769 self.__ac = AccessController(self)
10770 self._mainResource = None
10772 def __cmp__(self, other):
10773 if type(self) is not type(other):
10774 # This is actually dangerous and the ZODB manual says not to do this
10775 # because it relies on memory order. However, this branch should never
10776 # be taken anyway since we do not store different types in the same set
10777 # or use them as keys.
10778 return cmp(hash(self), hash(other))
10779 if self.getConference() == other.getConference():
10780 return cmp(self.getId(), other.getId())
10781 return cmp(self.getConference(), other.getConference())
10783 def updateNonInheritingChildren(self, elem, delete=False):
10784 # We do not want to store the inherited children in a Category because the funcionallity is not used
10785 if not isinstance(self.getOwner(), Category):
10786 self.getAccessController().updateNonInheritingChildren(elem, delete)
10787 self.notify_protection_to_owner(elem, delete)
10789 def notify_protection_to_owner(self, elem, delete=False):
10790 self.getOwner().updateNonInheritingChildren(elem, delete)
10792 def setValues( self, params ):
10793 """Sets all the values of the current material object from a diccionary
10794 containing the following key-value pairs:
10795 title-(str)
10796 description-(str)
10797 Please, note that this method sets ALL values which means that if
10798 the given dictionary doesn't contain any of the keys the value
10799 will set to a default value.
10801 self.setTitle(params.get("title", "NO TITLE ASSIGNED"))
10802 self.setDescription( params.get( "description", "" ) )
10803 self.notifyModification()
10805 def clone ( self, owner):
10806 mat = type(self)()
10807 mat.setTitle(self.getTitle())
10808 mat.setDescription(self.getDescription())
10809 mat.notifyModification()
10811 mat.setId(self.getId())
10812 mat.setOwner(owner)
10813 mat.setType(self.getType())
10815 mat.setProtection(self.getAccessController()._getAccessProtection())
10816 mat.setAccessKey(self.getAccessKey())
10817 rlist = self.getResourceList()
10818 for r in rlist:
10819 newres = r.clone(mat)
10820 mat.addResource(newres)
10822 mat.setMainResource(self.getMainResource())
10824 return mat
10826 def notifyModification( self ):
10827 parent = self.getOwner()
10828 if parent:
10829 parent.notifyModification(raiseEvent = False)
10830 self._p_changed = 1
10832 def getLocator( self ):
10833 if self.owner == None:
10834 return Locator()
10835 lconf = self.owner.getLocator()
10836 lconf["materialId"] = self.getId()
10837 return lconf
10839 def setId( self, newId ):
10840 self.id = str(newId).strip()
10842 def getId( self ):
10843 return self.id
10845 def getUniqueId( self ):
10846 """returns (string) the unique identifier of the item"""
10847 """used mainly in the web session access key table"""
10848 return "%sm%s" % (self.getOwner().getUniqueId(),self.id)
10850 def setOwner(self, newOwner):
10851 self.owner = newOwner
10853 def getOwner( self ):
10854 return self.owner
10856 def getCategory( self ):
10857 if isinstance(self.getOwner(), Category):
10858 return self.getOwner()
10859 return None
10861 def getConference( self ):
10862 owner = self.getOwner()
10863 if owner is None or isinstance(owner, Category):
10864 return None
10865 elif isinstance(owner, Conference):
10866 return owner
10867 else:
10868 return owner.getConference()
10870 def getSession( self ):
10871 if self.getContribution():
10872 return self.getContribution().getSession()
10873 if isinstance(self.getOwner(), Session):
10874 return self.getOwner()
10875 if isinstance(self.getOwner(), SubContribution):
10876 return self.getOwner().getSession()
10877 return None
10879 def getContribution( self ):
10880 if self.getSubContribution():
10881 return self.getSubContribution().getContribution()
10882 if isinstance(self.getOwner(), Contribution):
10883 return self.getOwner()
10884 return None
10886 def getSubContribution( self ):
10887 if isinstance(self.getOwner(), SubContribution):
10888 return self.getOwner()
10889 return None
10891 @Updates (['MaKaC.conference.Material',
10892 'MaKaC.conference.Minutes',
10893 'MaKaC.conference.Paper',
10894 'MaKaC.conference.Slides',
10895 'MaKaC.conference.Video',
10896 'MaKaC.conference.Poster',
10897 'MaKaC.conference.Reviewing'],'title')
10898 def setTitle( self, newTitle ):
10899 self.title = newTitle.strip()
10900 self.notifyModification()
10902 def getTitle( self ):
10903 return self.title
10905 @Updates (['MaKaC.conference.Material',
10906 'MaKaC.conference.Minutes',
10907 'MaKaC.conference.Paper',
10908 'MaKaC.conference.Slides',
10909 'MaKaC.conference.Video',
10910 'MaKaC.conference.Poster',
10911 'MaKaC.conference.Reviewing'], 'description')
10912 def setDescription( self, newDescription ):
10913 self.description = newDescription.strip()
10914 self.notifyModification()
10916 def getDescription( self ):
10917 return self.description
10919 def setType( self, newType ):
10920 self.type = newType.strip()
10921 self.notifyModification()
10923 def getType( self ):
10924 return self.type
10926 def getReviewingState(self):
10927 """ Returns the reviewing state of a material.
10928 The state is represented by an integer:
10929 0 : there's no reviewing state because the material does not belong to a contribution, or the conference
10930 has not reviewing module enabled, or the module is enabled but the mode is "no reviewing"
10931 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
10932 2 : the material is subject to reviewing, but has not been submitted yet by the author
10933 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
10934 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
10935 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
10937 if isinstance(self.owner, Contribution):
10938 conference = self.owner.getConference()
10939 if conference.getConfPaperReview().getChoice() == ConferencePaperReview.NO_REVIEWING: #conference has no reviewing process
10940 return 0
10941 else: #conference has reviewing
10942 #if self.id in reviewableMaterials: #material is reviewable
10943 if isinstance(self, Reviewing): #material is reviewable
10944 lastReview = self.owner.getReviewManager().getLastReview()
10945 if lastReview.isAuthorSubmitted(): #author has submitted
10946 refereeJudgement = lastReview.getRefereeJudgement()
10947 if refereeJudgement.isSubmitted(): #referee has submitted judgement
10948 if refereeJudgement.getJudgement() == "Accept":
10949 return 4
10950 elif refereeJudgement.getJudgement() == "Reject":
10951 return 5
10952 else:
10953 #we should never arrive here because referee judgements that are 'To be corrected'
10954 #or a custom state should imply a new review being created, so the state is back to 2
10955 raise MaKaCError("RefereeJudgement should be 'Accept' or 'Reject' in this method")
10956 else: #referee has not submitted judgement
10957 return 3
10958 else: #author has not submitted
10959 return 2
10960 else: #material is not reviewable
10961 return 1
10962 else: #material does not belong to a contribution
10963 return 0
10965 def _getRepository( self ):
10966 dbRoot = DBMgr.getInstance().getDBConnection().root()
10967 try:
10968 fr = dbRoot["local_repositories"]["main"]
10969 except KeyError, e:
10970 fr = fileRepository.MaterialLocalRepository()
10971 dbRoot["local_repositories"] = OOBTree()
10972 dbRoot["local_repositories"]["main"] = fr
10973 return fr
10975 def hasFile( self, name ):
10976 for f in self.getResourceList():
10977 if f.getName() == name:
10978 return True
10979 return False
10981 def addResource( self, newRes, forcedFileId = None ):
10982 newRes.setOwner( self )
10983 newRes.setId( str( self.__resourcesIdGen.newCount() ) )
10984 newRes.archive( self._getRepository(), forcedFileId = forcedFileId )
10985 self.__resources[newRes.getId()] = newRes
10986 self.notifyModification()
10987 Logger.get('storage').debug("Finished storing resource %s for material %s" % (newRes.getId(), self.getLocator()))
10989 def getResourceList(self, sort=True):
10990 list = self.__resources.values()
10991 if sort:
10992 list.sort(utils.sortFilesByName)
10993 return list
10995 def getNbResources(self ):
10996 return len(self.__resources)
10998 def getResourceById( self, id ):
10999 return self.__resources[id]
11001 def removeResource( self, res ):
11002 if res.getId() in self.__resources.keys():
11003 del self.__resources[ res.getId() ]
11004 res.delete()
11005 self.notifyModification()
11006 if self.getMainResource() is not None and \
11007 self._mainResource.getId() == res.getId():
11008 self._mainResource = None
11010 def recoverResource(self, recRes):
11011 recRes.setOwner(self)
11012 self.__resources[recRes.getId()] = recRes
11013 recRes.recover()
11014 self.notifyModification()
11016 def getMainResource(self):
11017 try:
11018 if self._mainResource:
11019 pass
11020 except AttributeError:
11021 self._mainResource = None
11022 return self._mainResource
11024 def setMainResource(self, mr):
11025 self._mainResource = mr
11027 def delete(self):
11028 self.__ac.unlinkAvatars('access')
11029 for res in self.getResourceList():
11030 self.removeResource( res )
11031 self.notify_protection_to_owner(self, delete=True)
11032 TrashCanManager().add(self)
11034 def recover(self):
11035 TrashCanManager().remove(self)
11037 def canIPAccess( self, ip ):
11038 if not self.__ac.canIPAccess( ip ):
11039 return False
11040 if self.getOwner() != None:
11041 return self.getOwner().canIPAccess(ip)
11042 return True
11044 def isProtected( self ):
11045 # tells if a material is protected or not
11046 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
11048 def getAccessProtectionLevel( self ):
11049 return self.__ac.getAccessProtectionLevel()
11051 def isItselfProtected( self ):
11052 return self.__ac.isItselfProtected()
11055 def hasProtectedOwner( self ):
11056 if self.getOwner() != None:
11057 return self.getOwner().isProtected()
11058 return False
11061 @Updates (['MaKaC.conference.Material',
11062 'MaKaC.conference.Minutes',
11063 'MaKaC.conference.Paper',
11064 'MaKaC.conference.Slides',
11065 'MaKaC.conference.Video',
11066 'MaKaC.conference.Poster',
11067 'MaKaC.conference.Reviewing'], 'protection', lambda(x): int(x))
11069 def setProtection( self, private ):
11070 self.__ac.setProtection( private )
11071 self.notify_protection_to_owner(self)
11072 self._p_changed = 1
11074 def isHidden( self ):
11075 return self.__ac.isHidden()
11077 @Updates (['MaKaC.conference.Material',
11078 'MaKaC.conference.Minutes',
11079 'MaKaC.conference.Paper',
11080 'MaKaC.conference.Slides',
11081 'MaKaC.conference.Video',
11082 'MaKaC.conference.Poster',
11083 'MaKaC.conference.Reviewing'], 'hidden')
11084 def setHidden( self, hidden ):
11085 self.__ac.setHidden( hidden )
11086 self._p_changed = 1
11089 @Updates (['MaKaC.conference.Material',
11090 'MaKaC.conference.Minutes',
11091 'MaKaC.conference.Paper',
11092 'MaKaC.conference.Slides',
11093 'MaKaC.conference.Video',
11094 'MaKaC.conference.Poster',
11095 'MaKaC.conference.Reviewing'], 'accessKey')
11097 def setAccessKey( self, pwd="" ):
11098 self.__ac.setAccessKey(pwd)
11099 self._p_changed = 1
11101 def getAccessKey( self ):
11102 return self.__ac.getAccessKey()
11104 def grantAccess( self, prin ):
11105 self.__ac.grantAccess( prin )
11106 if isinstance(prin, MaKaC.user.Avatar):
11107 prin.linkTo(self, "access")
11108 self._p_changed = 1
11110 def revokeAccess( self, prin ):
11111 self.__ac.revokeAccess( prin )
11112 if isinstance(prin, MaKaC.user.Avatar):
11113 prin.unlinkTo(self, "access")
11114 self._p_changed = 1
11116 def canView( self, aw ):
11117 """tells whether the specified user has access to the current object
11118 or any of its sub-objects
11120 if self.isHidden() and not self.canAccess( aw ):
11121 return False
11122 else:
11123 return True
11125 def isAllowedToAccess( self, user ):
11126 return (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user )) or self.__ac.canUserAccess( user ) or self.canUserModify(user)
11128 def canAccess( self, aw ):
11130 # Allow harvesters (Invenio, offline cache) to access
11131 # protected pages
11132 if self.__ac.isHarvesterIP(aw.getIP()):
11133 return True
11134 #####################################################
11136 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
11137 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
11138 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
11139 return True
11141 canUserAccess = self.isAllowedToAccess( aw.getUser() )
11142 canIPAccess = self.canIPAccess( aw.getIP() )
11143 if not self.isProtected():
11144 return canUserAccess or canIPAccess
11145 else:
11146 canKeyAccess = self.canKeyAccess(aw)
11147 return canUserAccess or canKeyAccess
11149 def canKeyAccess( self, aw ):
11150 sess = aw.getSession()
11151 if not sess:
11152 return False
11153 keys = sess.getVar("accessKeys")
11154 if keys != None:
11155 key = keys.get(self.getUniqueId(),"")
11156 if self.getAccessKey() != "":
11157 return self.__ac.canKeyAccess(key)
11158 elif self.getConference() != None:
11159 return self.getConference().canKeyAccess(aw, key)
11160 return False
11162 def grantModification( self, prin ):
11163 self.__ac.grantModification( prin )
11164 if isinstance(prin, MaKaC.user.Avatar):
11165 prin.linkTo(self, "manager")
11166 self._p_changed = 1
11168 def revokeModification( self, prin ):
11169 self.__ac.revokeModification( prin )
11170 if isinstance(prin, MaKaC.user.Avatar):
11171 prin.unlinkTo(self, "manager")
11172 self._p_changed = 1
11174 def canModify( self, aw ):
11175 return self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw ))
11177 def canUserModify( self, user ):
11178 """Tells whether a user is allowed to modify the current contribution:
11179 only if the user is granted to modify the contribution or the user
11180 can modify any of its upper objects (i.e. conference or session).
11182 return self.getOwner().canUserModify( user )
11184 def getModifKey( self ):
11185 return self.getConference().getModifKey()
11187 def getManagerList( self ):
11188 return self.__ac.getModifierList()
11190 def getAllowedToAccessList( self ):
11191 return self.__ac.getAccessList()
11193 def requireDomain( self, dom ):
11194 self.__ac.requireDomain( dom )
11195 self._p_changed = 1
11197 def freeDomain( self, dom ):
11198 self.__ac.freeDomain( dom )
11199 self._p_changed = 1
11201 def getDomainList( self ):
11202 return self.__ac.getRequiredDomainList()
11204 def getAccessController(self):
11205 return self.__ac
11207 def isBuiltin(self):
11208 return False
11210 class BuiltinMaterial(Material):
11212 Non-customizable material types
11214 def isBuiltin(self):
11215 return True
11218 class Reviewing(BuiltinMaterial):
11220 def __init__( self, materialData = None ):
11221 Material.__init__( self, materialData )
11222 self.id = "reviewing"
11224 def setId( self, newId ):
11225 return
11227 def getContribution(self):
11228 if isinstance(self.getOwner(), Review):
11229 return self.getOwner().getContribution()
11230 return Material.getContribution(self)
11232 class Paper(BuiltinMaterial):
11234 def __init__( self, materialData = None ):
11235 Material.__init__( self, materialData )
11236 self.id = "paper"
11238 def setId( self, newId ):
11239 return
11243 class Slides(BuiltinMaterial):
11245 def __init__( self, materialData = None ):
11246 Material.__init__( self, materialData )
11247 self.id = "slides"
11249 def setId( self, newId ):
11250 return
11254 class Video(BuiltinMaterial):
11256 def __init__( self, materialData = None ):
11257 Material.__init__( self, materialData )
11258 self.id = "video"
11260 def setId( self, newId ):
11261 return
11263 class Poster(BuiltinMaterial):
11265 def __init__( self, materialData = None ):
11266 Material.__init__( self, materialData )
11267 self.id = "poster"
11269 def setId( self, newId ):
11270 return
11272 class Minutes(BuiltinMaterial):
11274 def __init__( self, materialData = None ):
11275 Material.__init__( self, materialData )
11276 self.id = "minutes"
11277 self.title = "Minutes"
11278 self.file = None
11280 def clone ( self, owner):
11281 mat = Minutes()
11282 mat.setTitle(self.getTitle())
11283 mat.setDescription(self.getDescription())
11284 mat.notifyModification()
11286 mat.setId(self.getId())
11287 mat.setOwner(owner)
11288 mat.setType(self.getType())
11290 mat.setProtection(self.getAccessController()._getAccessProtection())
11291 mat.setAccessKey(self.getAccessKey())
11292 lrep = self._getRepository()
11293 flist = lrep.getFiles()
11294 rlist = self.getResourceList()
11295 for r in rlist :
11296 if r.getId()=="minutes":
11297 mat.setText(self.getText())
11298 elif isinstance(r,Link):
11299 newlink = Link()
11300 newlink.setOwner(mat)
11301 newlink.setName(r.getName())
11302 newlink.setDescription(r.getDescription())
11303 newlink.setURL(r.getURL())
11304 mat.addResource(newlink)
11305 elif isinstance(r,LocalFile):
11306 newfile = LocalFile()
11307 newfile.setOwner(mat)
11308 newfile.setName(r.getName())
11309 newfile.setDescription(r.getDescription())
11310 newfile.setFilePath(r.getFilePath())
11311 newfile.setFileName(r.getFileName())
11312 mat.addResource(newfile)
11313 else :
11314 raise Exception( _("Unexpected object type in Resource List : ")+str(type(r)))
11316 mat.setMainResource(self.getMainResource())
11318 return mat
11320 def setId( self, newId ):
11321 return
11323 def setTitle( self, newTitle ):
11324 self.title = newTitle.strip()
11325 self.notifyModification()
11327 def _setFile( self, forcedFileId = None ):
11328 #XXX: unsafe; it must be changed by mkstemp when migrating to python 2.3
11329 tmpFileName = tempfile.mktemp()
11330 fh = open(tmpFileName, "w")
11331 fh.write(" ")
11332 fh.close()
11333 self.file = LocalFile()
11334 self.file.setId("minutes")
11335 self.file.setName("minutes")
11336 self.file.setFilePath(tmpFileName)
11337 self.file.setFileName("minutes.txt")
11338 self.file.setOwner(self)
11339 self.file.archive(self._getRepository(), forcedFileId = forcedFileId)
11341 def setText( self, text, forcedFileId = None ):
11342 if self.file:
11343 self.file.delete()
11344 self._setFile(forcedFileId = forcedFileId)
11345 self.file.replaceContent( text )
11346 self.getOwner().notifyModification()
11348 def getText( self ):
11349 if not self.file:
11350 return ""
11351 return self.file.readBin()
11353 def getResourceList(self, sort=True):
11354 res = Material.getResourceList(self, sort=sort)
11355 if self.file:
11356 res.insert(0, self.file)
11357 return res
11359 def getResourceById( self, id ):
11360 if id.strip() == "minutes":
11361 return self.file
11362 return Material.getResourceById( self, id )
11364 def removeResource(self, res):
11365 Material.removeResource(self, res)
11366 if self.file is not None and res.getId().strip() == "minutes":
11367 self.file = None
11368 res.delete()
11369 self.notifyModification()
11371 def recoverResource(self, recRes):
11372 if recRes.getId() == "minutes":
11373 recRes.setOwner(self)
11374 self.file = recRes
11375 recRes.recover()
11376 self.notifyModification()
11377 else:
11378 Material.recoverResource(self, recRes)
11381 class Resource(CommonObjectBase):
11382 """This is the base class for representing individual resources which can
11383 be included in material containers for lately being attached to
11384 conference objects (i.e. conferences, sessions or contributions). This
11385 class provides basic data and operations to handle this resources.
11386 Resources can be of serveral types (files, links, ...) which means
11387 different specialisations of this class.
11388 Attributes:
11389 id -- (string) Allows to assign the resource a unique identifier. It
11390 is normally used to uniquely identify the resource among other
11391 resources included in a certain material.
11392 name -- (string) Short description about the purpose or the contents
11393 of the resource.
11394 description - (string) detailed and varied information about the
11395 resource.
11396 __owner - (Material) reference to the material object in which the
11397 current resource is included.
11400 fossilizes(IResourceMinimalFossil, IResourceFossil)
11402 def __init__( self, resData = None ):
11403 self.id = "not assigned"
11404 self.name = ""
11405 self.description = ""
11406 self._owner = None
11407 self.__ac = AccessController(self)
11408 self.pdfConversionRequestDate = None
11410 def __cmp__(self, other):
11411 if type(self) is not type(other):
11412 # This is actually dangerous and the ZODB manual says not to do this
11413 # because it relies on memory order. However, this branch should never
11414 # be taken anyway since we do not store different types in the same set
11415 # or use them as keys.
11416 return cmp(hash(self), hash(other))
11417 if self.getConference() == other.getConference():
11418 return cmp(self.getId(), other.getId())
11419 return cmp(self.getConference(), other.getConference())
11421 def clone( self, conf, protection=True ):
11422 res = self.__class__()
11423 res.setName(self.getName())
11424 res.setDescription(self.getDescription())
11425 res.setOwner(conf)
11426 res.notifyModification()
11427 res.setId(self.getId())
11429 if protection:
11430 res.setProtection(self.getAccessController()._getAccessProtection())
11431 #res.__ac = self.getAccessController()
11433 return res
11435 def notifyModification( self ):
11436 parent = self.getOwner()
11437 if parent:
11438 parent.setModificationDate()
11439 self._p_changed = 1
11441 def getLocator( self ):
11442 if self._owner == None:
11443 return Locator()
11444 lconf = self._owner.getLocator()
11445 lconf["resId"] = self.getId()
11446 return lconf
11448 def setId( self, newId ):
11449 self.id = newId.strip()
11451 def getId( self ):
11452 return self.id
11454 def getUniqueId( self ):
11455 """returns (string) the unique identifier of the item
11456 used mainly in the web session access key table
11457 for resources, it is the same as the father material since
11458 only the material can be protected with an access key"""
11459 return self.getOwner().getUniqueId()
11461 def setOwner(self, newOwner):
11462 self._owner = newOwner
11464 def getOwner( self ):
11465 return self._owner
11467 def getCategory( self ):
11468 #raise "%s:%s:%s"%(self.getOwner(), Material, isinstance(self.getOwner, Material))
11470 if isinstance(self.getOwner(), Category):
11471 return self.getOwner()
11472 if isinstance(self.getOwner(), Material):
11473 return self.getOwner().getCategory()
11474 return None
11476 def getConference( self ):
11477 # this check owes itself to the fact that some
11478 # protection checking functions call getConference()
11479 # directly on resources, without caring whether they
11480 # are owned by Conferences or Categories
11481 if self._owner is None or isinstance(self._owner, Category):
11482 return None
11483 else:
11484 return self._owner.getConference()
11486 def getSession( self ):
11487 return self._owner.getSession()
11489 def getContribution( self ):
11490 return self._owner.getContribution()
11492 def getSubContribution( self ):
11493 return self._owner.getSubContribution()
11495 @Updates (['MaKaC.conference.Link',
11496 'MaKaC.conference.LocalFile'], 'name')
11497 def setName( self, newName ):
11498 self.name = newName.strip()
11499 self.notifyModification()
11501 def getName( self ):
11502 return self.name
11504 @Updates (['MaKaC.conference.Link',
11505 'MaKaC.conference.LocalFile'], 'description')
11506 def setDescription( self, newDesc ):
11507 self.description = newDesc.strip()
11508 self.notifyModification()
11510 def getDescription( self ):
11511 return self.description
11513 def archive( self, repository = None, forcedFileId = None ):
11514 """performs necessary operations to ensure the archiving of the
11515 resource. By default is doing nothing as the persistence of the
11516 system already ensures the archiving of the basic resource data"""
11517 return
11519 def delete(self):
11520 if self._owner is not None:
11521 self.notify_protection_to_owner(delete=True)
11522 self._owner.removeResource(self)
11523 self.__ac.unlinkAvatars('access')
11524 self._owner = None
11525 TrashCanManager().add(self)
11527 def recover(self):
11528 TrashCanManager().remove(self)
11530 def canIPAccess( self, ip ):
11531 if not self.__ac.canIPAccess( ip ):
11532 return False
11533 if self.getOwner() != None:
11534 return self.getOwner().canIPAccess(ip)
11535 return True
11537 def isProtected( self ):
11538 # tells if a resource is protected or not
11539 return (self.hasProtectedOwner() + self.getAccessProtectionLevel()) > 0
11541 def getAccessProtectionLevel( self ):
11542 return self.__ac.getAccessProtectionLevel()
11544 def isItselfProtected( self ):
11545 return self.__ac.isItselfProtected()
11547 def hasProtectedOwner( self ):
11548 if self.getOwner() != None:
11549 return self.getOwner().isProtected()
11550 return False
11552 def notify_protection_to_owner(self, delete=False):
11553 # Resources can be attached to other objects (e.g. Registrant),
11554 # but we wish to trigger the notification only when attached to materials (except paper reviewing)
11555 if isinstance(self.getOwner(), Material) and not isinstance(self.getOwner(), Reviewing):
11556 self.getOwner().updateNonInheritingChildren(self, delete)
11558 @Updates (['MaKaC.conference.Link',
11559 'MaKaC.conference.LocalFile'],'protection', lambda(x): int(x))
11561 def setProtection( self, private ):
11562 self.__ac.setProtection( private )
11563 self.notify_protection_to_owner()
11565 def grantAccess( self, prin ):
11566 self.__ac.grantAccess( prin )
11567 if isinstance(prin, MaKaC.user.Avatar):
11568 prin.linkTo(self, "access")
11570 def revokeAccess( self, prin ):
11571 self.__ac.revokeAccess( prin )
11572 if isinstance(prin, MaKaC.user.Avatar):
11573 prin.unlinkTo(self, "access")
11575 def canView( self, aw ):
11576 """tells whether the specified user has access to the current object
11577 or any of its sub-objects
11579 return self.canAccess( aw )
11581 def isAllowedToAccess( self, user ):
11582 return self.__ac.canUserAccess( user ) or self.canUserModify( user ) or (not self.isItselfProtected() and self.getOwner().isAllowedToAccess( user ))
11584 def canAccess( self, aw ):
11585 # Allow harvesters (Invenio, offline cache) to access
11586 # protected pages
11587 if self.__ac.isHarvesterIP(aw.getIP()):
11588 return True
11589 #####################################################
11591 from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin, RCCollaborationPluginAdmin
11592 if RCCollaborationAdmin.hasRights(user = aw.getUser()) or \
11593 RCCollaborationPluginAdmin.hasRights(user=aw.getUser(), plugins='any'):
11594 return True
11596 if not self.canIPAccess(aw.getIP()) and not self.canUserModify(aw.getUser()) and not self.isAllowedToAccess( aw.getUser() ):
11597 return False
11598 if not self.isProtected():
11599 return True
11600 flag = self.isAllowedToAccess( aw.getUser() )
11601 return flag or self.canKeyAccess(aw) or self.getOwner().canKeyAccess(aw) or \
11602 (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == "") or \
11603 (self.getConference() != None and self.getConference().canKeyAccess(aw) and self.getAccessKey() == self.getConference().getAccessKey())
11605 def grantModification( self, prin ):
11606 self.__ac.grantModification( prin )
11608 def revokeModification( self, prin ):
11609 self.__ac.revokeModification( prin )
11611 def canModify( self, aw ):
11612 return self.canUserModify( aw.getUser() ) or (self.getConference() and self.getConference().canKeyModify( aw ))
11614 def canUserModify( self, user ):
11615 """Tells whether a user is allowed to modify the current contribution:
11616 only if the user is granted to modify the contribution or the user
11617 can modify any of its upper objects (i.e. conference or session).
11619 return self.getOwner().canUserModify( user )
11621 def getModifKey( self ):
11622 return self.getConference().getModifKey()
11624 def getManagerList( self ):
11625 return self.__ac.getModifierList()
11627 def getAllowedToAccessList( self ):
11628 return self.__ac.getAccessList()
11630 def getURL( self ):
11631 return ""
11633 def requireDomain( self, dom ):
11634 self.__ac.requireDomain( dom )
11636 def freeDomain( self, dom ):
11637 self.__ac.freeDomain( dom )
11639 def getDomainList( self ):
11640 return self.__ac.getRequiredDomainList()
11642 def getAccessController(self):
11643 return self.__ac
11645 def getAccessKey(self):
11646 if self.getOwner() is not None:
11647 return self.getOwner().getAccessKey()
11648 return ""
11650 def canKeyAccess( self, aw ):
11651 sess = aw.getSession()
11652 if not sess:
11653 return False
11654 accessKey = self.getAccessKey()
11655 keys = sess.getVar("accessKeys")
11656 if keys != None:
11657 if keys.has_key(self.getUniqueId()):
11658 if (accessKey != "" and keys[self.getUniqueId()] == accessKey) or (accessKey == "" and self.getConference().getAccessKey() != "" and keys[self.getUniqueId()] == self.getConference().getAccessKey()):
11659 return True
11660 return False
11662 def getReviewingState(self):
11663 """ Returns the reviewing state of a resource, which is the reviewing state of the material to which it belongs.
11664 The state is represented by an integer:
11665 0 : there's no reviewing state because the resource doesn't belong to a material,
11666 the material does not belong to a contribution, or the conference does not have reviewing.
11667 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
11668 2 : the material is subject to reviewing, but has not been submitted yet by the author
11669 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
11670 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
11671 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
11673 if isinstance(self.getOwner(), Material):
11674 return self.getOwner().getReviewingState()
11675 else: #ressource does not belong to a material
11676 return 0
11678 def setPDFConversionRequestDate( self, newPdfConversionRequestDate ):
11679 self.pdfConversionRequestDate = newPdfConversionRequestDate
11681 def getPDFConversionStatus(self):
11683 if not hasattr(self, "pdfConversionRequestDate"):
11684 self.pdfConversionRequestDate = None
11686 if self.pdfConversionRequestDate is not None and self.pdfConversionRequestDate + timedelta(seconds=50) > nowutc() :
11687 return 'converting'
11688 return None
11690 class Link(Resource):
11691 """Specialises Resource class in order to represent web links. Objects of
11692 this class will contain necessary information to include in a conference
11693 object links to internet resources through a URL.
11694 Params:
11695 url -- (string) Contains the URL to the internet target resource.
11698 fossilizes(ILinkMinimalFossil, ILinkFossil)
11700 def __init__( self, resData = None ):
11701 Resource.__init__( self, resData )
11702 self.url = ""
11704 def clone( self, conf ):
11705 link = Resource.clone(self, conf)
11706 link.setURL(self.getURL())
11707 return link
11709 @Updates ('MaKaC.conference.Link', 'url')
11710 def setURL( self, newURL ):
11711 self.url = newURL.strip()
11712 self.notifyModification()
11714 def getURL( self ):
11715 return self.url
11718 class LocalFile(Resource):
11719 """Specialises Resource class in order to represent files which can be
11720 stored in the system. The user can choose to use the system as an
11721 archive of electronic files so he may want to attach a file which is
11722 in his computer to a conference so it remains there and must be kept
11723 in the system. This object contains the file basic metadata and provides
11724 the necessary operations to ensure the corresponding file is archived
11725 (it uses one of the file repositories of the system to do so) and keeps
11726 the reference for being able to access it afterwards.
11727 Params:
11728 fileName -- (string) Name of the file. Normally the original name of
11729 the user submitted file is kept.
11730 filePath -- (string) If it is set, it contains a local path to the
11731 file submitted by the user and uploaded in the system. This
11732 attribute is only temporary used so it keeps a pointer to a
11733 temporary uploaded file.
11734 __repository -- (FileRep) Once a file is archived, it is kept in a
11735 FileRepository for long term. This attribute contains a pointer
11736 to the file repository where the file is kept.
11737 __archivedId -- (string) It contains a unique identifier for the file
11738 inside the repository where it is archived.
11741 fossilizes(ILocalFileMinimalFossil, ILocalFileFossil, ILocalFileExtendedFossil, ILocalFileAbstractMaterialFossil)
11743 def __init__( self, resData = None ):
11744 Resource.__init__( self, resData )
11745 self.fileName= ""
11746 self.fileType = ""
11747 self.filePath = ""
11748 self.__repository = None
11749 self.__archivedId = ""
11751 def clone( self, conf, protection=True ):
11752 localfile = Resource.clone(self, conf, protection)
11753 localfile.setFilePath(self.getFilePath())
11754 localfile.setFileName(self.getFileName())
11755 return localfile
11757 def setFileName( self, newFileName, checkArchive=True ):
11758 """While the file is not archived sets the file name of the current
11759 object to the one specified (if a full path is specified the
11760 base name is extracted) replacing on it blanks by underscores.
11762 if checkArchive and self.isArchived():
11763 raise MaKaCError( _("The file name of an archived file cannot be changed"), _("File Archiving"))
11764 #Using os.path.basename is not enough as it only extract filenames
11765 # correclty depending on the server platform. So we need to convert
11766 # to the server platform and apply the basename extraction. As I
11767 # couldn't find a python function for this this is done manually
11768 # although it can contain errors
11769 #On windows basename function seems to work properly with unix file
11770 # paths
11771 if newFileName.count("/"):
11772 #unix filepath
11773 newFileName = newFileName.split("/")[-1]
11774 else:
11775 #windows file path: there "/" is not allowed on windows paths
11776 newFileName = newFileName.split("\\")[-1]
11777 self.fileName = newFileName.strip().replace(" ", "_")
11779 def getFileName( self ):
11780 return self.fileName
11782 def getFileType( self ):
11783 fileExtension = os.path.splitext( self.getFileName() )[1]
11784 if fileExtension != "":
11785 fileExtension = fileExtension[1:]
11786 cfg = Config.getInstance()
11787 if cfg.getFileType( fileExtension ) != "":
11788 return cfg.getFileType( fileExtension )
11789 else:
11790 return fileExtension
11792 def setFilePath( self, filePath ):
11793 if self.isArchived():
11794 raise MaKaCError( _("The path of an archived file cannot be changed"), _("File Archiving"))
11795 if not os.access( filePath.strip(), os.F_OK ):
11796 raise Exception( _("File does not exist : %s")%filePath.strip())
11797 self.filePath = filePath.strip()
11799 def getCreationDate( self):
11800 return self.__repository.getCreationDate(self.__archivedId)
11802 def getFilePath( self ):
11803 if not self.isArchived():
11804 return self.filePath
11805 return self.__repository.getFilePath(self.__archivedId)
11807 def getSize( self ):
11808 if not self.isArchived():
11809 return int(os.stat(self.getFilePath())[stat.ST_SIZE])
11810 return self.__repository.getFileSize( self.__archivedId )
11812 def setArchivedId( self, rep, id ):
11813 self.__repository = rep
11814 self.__archivedId = id
11816 def getRepositoryId( self ):
11817 return self.__archivedId
11819 def setRepositoryId(self, id):
11820 self.__archivedId = id
11822 def isArchived( self ):
11823 return self.__repository != None and self.__archivedId != ""
11825 def readBin( self ):
11826 if not self.isArchived():
11827 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11828 return self.__repository.readFile( self.__archivedId )
11830 def replaceContent( self, newContent ):
11831 if not self.isArchived():
11832 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11833 self.__repository.replaceContent( self.__archivedId, newContent )
11835 def archive( self, repository=None, forcedFileId = None ):
11836 if self.isArchived():
11837 raise Exception( _("File is already archived"))
11838 if not repository:
11839 raise Exception( _("Destination repository not set"))
11840 if self.filePath == "":
11841 return _("Nothing to archive")
11842 repository.storeFile( self, forcedFileId = forcedFileId)
11843 self.filePath = ""
11844 self.notifyModification()
11846 def unArchive(self):
11847 # Not used.
11848 self.__repository = None
11849 self.__archivedId = ""
11851 def recover(self):
11852 if not self.isArchived():
11853 raise Exception( _("File is not archived, so it cannot be recovered."))
11854 if not self.__repository:
11855 raise Exception( _("Destination repository not set."))
11856 self.__repository.recoverFile(self)
11857 Resource.recover(self)
11858 self.notifyModification()
11860 def delete( self ):
11861 if not self.isArchived():
11862 os.remove( self.getFilePath() )
11863 try:
11864 self.__repository.retireFile( self )
11865 except AttributeError, e:
11866 pass
11867 Resource.delete( self )
11869 def getRepository(self):
11870 return self.__repository
11872 def __str__( self ):
11873 return self.getFileName()
11875 #getURL is removed at the moment from the LocalFile and the file access
11876 # is completely delegated to the web interface; the web interface will
11877 # have to access the files locally (using the getFilePath) or the readBin
11878 # function.
11879 #However, for the future it could be required to have several file
11880 # repositories so the file access will have to be reviewed.
11881 #def getURL( self ):
11882 # #XXX: Very bad!! We should find a better solution
11883 # c = Config.getInstance()
11884 # return c.getArchivedFileURL( self )
11887 class TCIndex( Persistent ):
11888 """Index for conference track coordinators.
11890 This class allows to index conference track coordinators so the owner
11891 can answer optimally to the query if a user is coordinating
11892 any conference track.
11893 It is implemented by simply using a BTree where the Avatar id is used
11894 as key (because it is unique and non variable) and a list of
11895 coordinated tracks is kept as keys. It is the responsability of the
11896 index owner (conference) to keep it up-to-date i.e. notify track
11897 coordinator additions and removals.
11900 def __init__( self ):
11901 self._idx = OOBTree()
11904 def getTracks( self, av ):
11905 """Gives a list with the tracks a user is coordinating.
11907 if av == None:
11908 return []
11909 return self._idx.get( av.getId(), [] )
11911 def indexCoordinator( self, av, track ):
11912 """Registers in the index a coordinator of a track.
11914 if av == None or track == None:
11915 return
11916 if not self._idx.has_key( av.getId() ):
11917 l = []
11918 else:
11919 l = self._idx[av.getId()]
11920 if track not in l:
11921 l.append(track)
11922 # necessary, otherwise ZODB won't know it needs to update the BTree
11923 self._idx[av.getId()] = l
11924 self.notifyModification()
11926 def unindexCoordinator( self, av, track ):
11927 if av == None or track == None:
11928 return
11929 l = self._idx.get( av.getId(), [] )
11930 if track in l:
11931 l.remove( track )
11932 self._idx[av.getId()] = l
11933 self.notifyModification()
11935 def notifyModification(self):
11936 self._p_changed = 1
11939 class Track(CoreObject):
11941 def __init__( self ):
11942 self.conference = None
11943 self.id = "not assigned"
11944 self.title = ""
11945 self.description = ""
11946 self.subTracks = {}
11947 self.__SubTrackGenerator = Counter()
11948 self._abstracts = OOBTree()
11949 self._coordinators = []
11950 self._contributions = OOBTree()
11951 self._code=""
11953 def __cmp__(self, other):
11954 if type(self) is not type(other):
11955 # This is actually dangerous and the ZODB manual says not to do this
11956 # because it relies on memory order. However, this branch should never
11957 # be taken anyway since we do not store different types in the same set
11958 # or use them as keys.
11959 return cmp(hash(self), hash(other))
11960 if self.getConference() == other.getConference():
11961 return cmp(self.getId(), other.getId())
11962 return cmp(self.getConference(), other.getConference())
11964 def clone(self, conference):
11965 tr = Track()
11966 tr.setConference(conference)
11967 tr.setTitle(self.getTitle())
11968 tr.setCode(self.getCode())
11969 tr.setDescription(self.getDescription())
11971 for co in self.getCoordinatorList() :
11972 tr.addCoordinator(co)
11974 for subtr in self.getSubTrackList() :
11975 tr.addSubTrack(subtr.clone())
11977 return tr
11980 def delete( self ):
11981 """Deletes a track from the system. All the associated abstracts will
11982 also be notified so the track is no longer associated to them.
11984 #XXX: Should we allow to delete a track when there are some abstracts
11985 # or contributions submitted for it?!?!?!?!
11987 # we must notify each abstract in the track about the deletion of the
11988 # track
11989 while len(self._abstracts)>0:
11990 k = self._abstracts.keys()[0]
11991 abstract = self._abstracts[k]
11992 del self._abstracts[k]
11993 abstract.removeTrack( self )
11995 # we must notify each contribution in the track about the deletion of the
11996 # track
11997 while len(self._contributions)>0:
11998 k = self._contributions.keys()[0]
11999 contrib = self._contributions[k]
12000 del self._contributions[k]
12001 contrib.removeTrack( self )
12003 # we must delete and unindex all the possible track coordinators
12004 while len(self._coordinators)>0:
12005 self.removeCoordinator(self._coordinators[0])
12007 # we must notify the conference about the track deletion
12008 if self.conference:
12009 conf = self.conference
12010 self.conference = None
12011 conf.removeTrack( self )
12013 TrashCanManager().add(self)
12015 def recover(self):
12016 TrashCanManager().remove(self)
12018 def canModify( self, aw ):
12019 return self.conference.canModify( aw )
12021 def canUserModify( self, av ):
12022 return self.conference.canUserModify( av )
12024 def canView( self, aw ):
12025 return self.conference.canView( aw )
12027 def notifyModification( self ):
12028 parent = self.getConference()
12029 if parent:
12030 parent.setModificationDate()
12031 self._p_changed = 1
12033 def getLocator( self ):
12034 """Gives back a globaly unique identification encapsulated in a Locator
12035 object for the track instance
12037 if self.conference == None:
12038 return Locator()
12039 lconf = self.conference.getLocator()
12040 lconf["trackId"] = self.getId()
12041 return lconf
12043 def setConference(self, conference):
12044 self.conference = conference
12046 def getConference( self ):
12047 return self.conference
12049 def getOwner( self ):
12050 return self.getConference()
12052 def setId( self, newId ):
12053 self.id = str(newId)
12055 def getId( self ):
12056 return self.id
12058 def setTitle( self, newTitle ):
12059 self.title = newTitle
12060 self.notifyModification()
12062 def getTitle( self ):
12063 return self.title
12065 def setDescription(self, newDescription ):
12066 self.description = newDescription
12067 self.notifyModification()
12069 def getDescription(self):
12070 return self.description
12072 def getCode(self):
12073 try:
12074 if self._code:
12075 pass
12076 except AttributeError:
12077 self._code=self.id
12078 return self._code
12080 def setCode(self,newCode):
12081 self._code=str(newCode).strip()
12083 def __generateNewSubTrackId( self ):
12084 return str(self.__SubTrackGenerator.newCount())
12086 def addSubTrack( self, newSubTrack ):
12087 """Registers the contribution passed as parameter within the session
12088 assigning it a unique id.
12090 if newSubTrack in self.subTracks.values():
12091 return
12092 subTrackId = newSubTrack.getId()
12093 if subTrackId == "not assigned":
12094 subTrackId = self.__generateNewSubTrackId()
12095 self.subTracks[subTrackId] = newSubTrack
12096 newSubTrack.setTrack( self )
12097 newSubTrack.setId( subTrackId )
12098 self.notifyModification()
12100 def removeSubTrack( self, subTrack ):
12101 """Removes the indicated contribution from the session
12103 if subTrack in self.subTracks.values():
12104 del self.subTracks[ subTrack.getId() ]
12105 subTrack.setTrack( None )
12106 subTrack.delete()
12107 self.notifyModification()
12109 def recoverSubTrack(self, subTrack):
12110 self.addSubTrack(subTrack)
12111 subTrack.recover()
12113 def newSubTrack( self ):
12114 st = SubTrack()
12115 self.addSubTrack( st )
12116 return st
12118 def getSubTrackById( self, id ):
12119 if self.subTracks.has_key( id ):
12120 return self.subTracks[ id ]
12121 return None
12123 def getSubTrackList( self ):
12124 return self.subTracks.values()
12126 def getAbstractList( self ):
12129 try:
12130 if self._abstracts:
12131 pass
12132 except AttributeError:
12133 self._abstracts = OOBTree()
12134 return self._abstracts.values()
12136 def getAbstractById( self, id ):
12137 try:
12138 if self._abstracts:
12139 pass
12140 except AttributeError:
12141 self._abstracts = OOBTree()
12142 return self._abstracts.get(str(id).strip())
12144 def hasAbstract( self, abstract ):
12147 try:
12148 if self._abstracts:
12149 pass
12150 except AttributeError:
12151 self._abstracts = OOBTree()
12152 return self._abstracts.has_key( abstract.getId() )
12154 def addAbstract( self, abstract ):
12155 """Adds an abstract to the track abstract list.
12157 Notice that this method doesn't notify the abstract about the track
12158 addition.
12160 if not self.hasAbstract( abstract ):
12161 self._abstracts[ abstract.getId() ] = abstract
12162 #abstract.addTrack( self )
12164 def removeAbstract( self, abstract ):
12165 """Removes an abstract from the track abstract list.
12167 Notice that this method doesn't notify the abstract about the track
12168 removal.
12170 if self.hasAbstract( abstract ):
12171 del self._abstracts[ abstract.getId() ]
12172 #abstract.removeTrack( self )
12174 def addCoordinator( self, av ):
12175 """Grants coordination privileges to user.
12177 Arguments:
12178 av -- (MaKaC.user.Avatar) the user to which
12179 coordination privileges must be granted.
12182 try:
12183 if self._coordinators:
12184 pass
12185 except AttributeError, e:
12186 self._coordinators = []
12187 self.notifyModification()
12189 if not (av in self._coordinators):
12190 self._coordinators.append( av )
12191 self.getConference().addTrackCoordinator( self, av )
12192 av.linkTo(self, "coordinator")
12193 self.notifyModification()
12195 def removeCoordinator( self, av ):
12196 """Revokes coordination privileges to user.
12198 Arguments:
12199 av -- (MaKaC.user.Avatar) user for which coordination privileges
12200 must be revoked
12202 try:
12203 if self._coordinators:
12204 pass
12205 except AttributeError, e:
12206 self._coordinators = []
12207 self.notifyModification()
12209 if av in self._coordinators:
12210 self._coordinators.remove( av )
12211 self.getConference().removeTrackCoordinator( self, av )
12212 av.linkTo(self, "coordinator")
12213 self.notifyModification()
12215 def isCoordinator( self, av ):
12216 """Tells whether the specified user is a coordinator of the track.
12218 Arguments:
12219 av -- (MaKaC.user.Avatar) user to be checke
12221 Return value: (boolean)
12223 try:
12224 if self._coordinators:
12225 pass
12226 except AttributeError, e:
12227 self._coordinators = []
12229 return av in self._coordinators
12231 def getCoordinatorList( self ):
12232 """Return all users which have privileges to coordinate the track.
12234 Return value: (list)
12236 try:
12237 if self._coordinators:
12238 pass
12239 except AttributeError, e:
12240 self._coordinators = []
12242 return self._coordinators
12244 def canCoordinate( self, aw ):
12245 """Tells if a user has coordination privileges.
12247 Only track coordinators have coordination privileges over a track.
12249 Params:
12250 aw -- (MaKaC.accessControl.AccessWrapper) User access
12251 information for which the coordination privileges must be
12252 checked.
12254 Return value: (boolean)
12256 return self.isCoordinator( aw.getUser() ) or self.canModify( aw )
12258 def addContribution( self, newContrib ):
12261 try:
12262 if self._contributions:
12263 pass
12264 except AttributeError:
12265 self._contributions = OOBTree()
12266 if self._contributions.has_key( newContrib.getId() ):
12267 return
12268 self._contributions[ newContrib.getId() ] = newContrib
12269 newContrib.setTrack( self )
12271 def getModifKey( self ):
12272 return self.getConference().getModifKey()
12274 def removeContribution( self, contrib ):
12277 try:
12278 if self._contributions:
12279 pass
12280 except AttributeError:
12281 self._contributions = OOBTree()
12282 if not self._contributions.has_key( contrib.getId() ):
12283 return
12284 del self._contributions[ contrib.getId() ]
12285 contrib.setTrack( None )
12287 def hasContribution( self, contrib ):
12288 try:
12289 if self._contributions:
12290 pass
12291 except AttributeError:
12292 self._contributions = OOBTree()
12293 return self._contributions.has_key( contrib.getId() )
12295 def getContributionList(self):
12296 try:
12297 if self._contributions:
12298 pass
12299 except AttributeError:
12300 self._contributions = OOBTree()
12301 return self._contributions.values()
12303 def canUserCoordinate( self, av ):
12304 return self.isCoordinator( av ) or self.canUserModify( av )
12307 class SubTrack(CoreObject):
12309 def __init__( self ):
12310 self.track = None
12311 self.id = "not assigned"
12312 self.title = ""
12313 self.description = ""
12315 def clone(self):
12316 sub = SubTrack()
12317 sub.setDescription(self.getDescription())
12318 sub.setTitle(self.getTitle())
12320 return sub
12323 def delete(self):
12324 TrashCanManager().add(self)
12326 def recover(self):
12327 TrashCanManager().remove(self)
12329 def canModify( self, aw ):
12330 return self.track.canModify( aw )
12332 def canView( self, aw ):
12333 return self.track.canView( aw )
12335 def notifyModification( self ):
12336 parent = self.getTrack()
12337 if parent:
12338 parent.setModificationDate()
12339 self._p_changed = 1
12341 def getLocator( self ):
12342 """Gives back a globaly unique identification encapsulated in a Locator
12343 object for the session instance
12345 if self.track == None:
12346 return Locator()
12347 lconf = self.track.getLocator()
12348 lconf["subTrackId"] = self.getId()
12349 return lconf
12351 def setTrack(self, track):
12352 self.track = track
12353 if track == None:
12354 return
12356 def getTrack( self ):
12357 return self.track
12359 def getOwner( self ):
12360 return self.getTrack()
12362 def setId( self, newId ):
12363 self.id = str(newId)
12365 def getId( self ):
12366 return self.id
12368 def setTitle( self, newTitle ):
12369 self.title = newTitle
12370 self.notifyModification()
12372 def getTitle( self ):
12373 return self.title
12375 def setDescription(self, newDescription ):
12376 self.description = newDescription
12377 self.notifyModification()
12379 def getDescription(self):
12380 return self.description
12383 class ContributionType(Persistent):
12385 def __init__(self, name, description, conference):
12386 self._id = ""
12387 self._name = name
12388 self._description = description
12389 self._conference = conference
12391 def getId(self):
12392 return self._id
12394 def setId(self, id):
12395 self._id = id
12397 def getName(self):
12398 return self._name
12400 def setName(self, name):
12401 self._name = name
12403 def getDescription(self):
12404 return self._description
12406 def setDescription(self, desc):
12407 self._description = desc
12409 def getConference(self):
12410 return self._conference
12412 def setConference(self, conf):
12413 self._conference = conf
12415 def getLocator( self ):
12416 if self._conference == None:
12417 return Locator()
12418 lconf = self._conference.getLocator()
12419 lconf["contribTypeId"] = self.getId()
12420 return lconf
12422 def canModify(self, aw):
12423 return self._conference.canModify(aw)
12425 def delete(self):
12426 self.setConference(None)
12427 TrashCanManager().add(self)
12429 def recover(self):
12430 TrashCanManager().remove(self)
12432 def clone(self, conference ):
12433 type = ContributionType(self.getName(), self.getDescription(),conference)
12434 return type
12437 class BOAConfig(Persistent):
12438 """Contains the configuration of the Book of Abstracts of a conference
12440 sortByTypes = {"number": L_("ID"),
12441 "name": L_("Title"),
12442 "sessionTitle": L_("Session title"),
12443 "speaker": L_("Presenter"),
12444 "schedule": L_("Schedule")}
12446 correspondingAuthorTypes = {"none": L_("Nobody"),
12447 "submitter": L_("Submitter"),
12448 "speakers": L_("Speakers")}
12450 def __init__(self,conf):
12451 self._conf=conf
12452 self._text=""
12453 self._showIds= False
12454 self._sortBy = "number"
12455 self._correspondingAuthor = "submitter"
12456 self._modificationDS = nowutc()
12457 self._cache = False
12459 def getText(self):
12460 return self._text
12462 def setText(self,newText):
12463 self._text=newText.strip()
12464 self._notifyModification()
12466 def getShowIds(self):
12467 if not hasattr(self, "_showIds"):
12468 self._showIds=False
12469 return self._showIds
12471 def setShowIds(self,showIds):
12472 self._showIds=showIds
12473 self._notifyModification()
12475 def getSortBy(self):
12476 if not hasattr(self, "_sortBy"):
12477 self._sortBy="number"
12478 return self._sortBy
12480 def setSortBy(self,sortBy):
12481 self._sortBy=sortBy
12482 self._notifyModification()
12484 @staticmethod
12485 def getSortByTypes():
12486 return BOAConfig.sortByTypes
12488 def getCorrespondingAuthor(self):
12489 if not hasattr(self, "_correspondingAuthor"):
12490 self._correspondingAuthor = "submitter"
12491 return self._correspondingAuthor
12493 def setCorrespondingAuthor(self, correspondingAuthor):
12494 self._correspondingAuthor = correspondingAuthor
12495 self._notifyModification()
12497 @staticmethod
12498 def getCorrespondingAuthorTypes():
12499 return BOAConfig.correspondingAuthorTypes
12501 def isCacheEnabled(self):
12502 if not hasattr(self, '_cache'):
12503 self._cache = False
12504 return self._cache
12506 def setCache(self, value):
12507 self._cache = value;
12509 def _notifyModification(self):
12510 self._modificationDS = nowutc()
12512 @property
12513 def lastChanged(self):
12514 if not hasattr(self, '_modificationDS'):
12515 self._modificationDS = nowutc()
12516 return self._modificationDS