1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 from itertools
import ifilter
18 from flask_pluginengine
import plugin_context
19 from sqlalchemy
.orm
import lazyload
21 from indico
.modules
.rb
.models
.reservations
import Reservation
22 from MaKaC
.common
.timezoneUtils
import datetimeToUnixTimeInt
23 from MaKaC
.fossils
.subcontribution
import ISubContribParticipationFossil
,\
24 ISubContribParticipationFullFossil
, ISubContributionFossil
, ISubContributionWithSpeakersFossil
25 from MaKaC
.fossils
.contribution
import IContributionParticipationFossil
,\
26 IContributionFossil
, IContributionWithSpeakersFossil
, IContributionParticipationMinimalFossil
, \
27 IContributionWithSubContribsFossil
,\
28 IContributionParticipationTTDisplayFossil
, \
29 IContributionParticipationTTMgmtFossil
30 from MaKaC
.fossils
.conference
import IConferenceMinimalFossil
, \
31 IConferenceEventInfoFossil
, IConferenceFossil
,\
32 ISessionFossil
, ISessionSlotFossil
, IMaterialMinimalFossil
,\
33 IMaterialFossil
, IConferenceParticipationFossil
,\
34 IResourceMinimalFossil
, ILinkMinimalFossil
, ILocalFileMinimalFossil
,\
35 IResourceFossil
, ILinkFossil
, ILocalFileFossil
,\
36 ILocalFileExtendedFossil
, IConferenceParticipationMinimalFossil
,\
37 ICategoryFossil
, ILocalFileAbstractMaterialFossil
38 from MaKaC
.common
.fossilize
import fossilizes
, Fossilizable
39 from MaKaC
.common
.url
import ShortURLMapper
40 from MaKaC
.contributionReviewing
import Review
41 from indico
.modules
.rb
.models
.rooms
import Room
42 from indico
.modules
.rb
.models
.locations
import Location
43 from indico
.modules
.users
import User
44 from indico
.modules
.users
.legacy
import AvatarUserWrapper
45 from indico
.modules
.groups
.legacy
import GroupWrapper
46 from indico
.util
.i18n
import L_
47 from indico
.util
.string
import safe_upper
, safe_slice
, fix_broken_string
, return_ascii
, is_legacy_id
48 from MaKaC
.review
import AbstractFieldContent
55 from datetime
import datetime
, timedelta
56 from flask
import session
, request
, has_request_context
58 from MaKaC
.contributionReviewing
import ReviewManager
59 from MaKaC
.paperReviewing
import ConferencePaperReview
as ConferencePaperReview
60 from MaKaC
.abstractReviewing
import ConferenceAbstractReview
as ConferenceAbstractReview
62 from pytz
import timezone
63 from pytz
import all_timezones
65 from persistent
import Persistent
66 from BTrees
.OOBTree
import OOBTree
, OOTreeSet
67 from BTrees
.OIBTree
import OIBTree
,OISet
,union
69 from MaKaC
.common
import indexes
70 from MaKaC
.common
.timezoneUtils
import nowutc
, maxDatetime
71 import MaKaC
.fileRepository
as fileRepository
72 from MaKaC
.schedule
import (ConferenceSchedule
, SessionSchedule
, SlotSchTypeFactory
, ContribSchEntry
,
73 LinkedTimeSchEntry
, BreakTimeSchEntry
)
74 import MaKaC
.review
as review
75 from MaKaC
.common
import utils
76 from MaKaC
.common
.Counter
import Counter
77 from MaKaC
.common
.ObjectHolders
import ObjectHolder
78 from MaKaC
.common
.Locators
import Locator
79 from MaKaC
.accessControl
import AccessController
80 from MaKaC
.errors
import MaKaCError
, TimingError
, ParentTimingError
, EntryTimingError
, NotFoundError
, FormValuesError
81 from MaKaC
import registration
82 from MaKaC
.evaluation
import Evaluation
83 from MaKaC
.trashCan
import TrashCanManager
84 from MaKaC
.user
import AvatarHolder
85 from MaKaC
.common
import pendingQueues
86 from MaKaC
.common
.info
import HelperMaKaCInfo
87 from MaKaC
.participant
import Participation
88 from MaKaC
.common
.log
import LogHandler
89 from MaKaC
.badge
import BadgeTemplateManager
90 from MaKaC
.poster
import PosterTemplateManager
91 from MaKaC
.common
import mail
92 from MaKaC
.i18n
import _
93 from MaKaC
.common
.PickleJar
import Updates
94 from MaKaC
.schedule
import ScheduleToJson
95 from MaKaC
.webinterface
import urlHandlers
97 from indico
.core
.logger
import Logger
98 from MaKaC
.common
.contextManager
import ContextManager
101 from indico
.modules
.scheduler
import Client
, tasks
102 from indico
.core
import signals
103 from indico
.util
.date_time
import utc_timestamp
, format_datetime
104 from indico
.core
.index
import IIndexableByStartDateTime
, IUniqueIdProvider
, Catalog
105 from indico
.core
.db
import DBMgr
106 from indico
.core
.db
.event
import SupportInfo
107 from indico
.core
.config
import Config
108 from indico
.util
.date_time
import utc_timestamp
109 from indico
.util
.signals
import values_from_signal
110 from indico
.util
.redis
import write_client
as redis_write_client
111 from indico
.util
.user
import unify_user_args
112 from indico
.util
.redis
import avatar_links
113 from indico
.web
.flask
.util
import url_for
116 class CoreObject(Persistent
):
118 CoreObjects are Persistent objects that are employed by Indico's core
121 zope
.interface
.implements(IUniqueIdProvider
,
122 IIndexableByStartDateTime
)
124 def setModificationDate(self
, date
=None):
126 Method called to notify the current object has been modified.
130 self
._modificationDS
= date
132 def __conform__(self
, proto
):
134 if proto
== IIndexableByStartDateTime
:
135 return utc_timestamp(self
.getStartDate())
142 Inherited by objects that imply a physical location:
152 if not self
.getLocation() or not self
.getRoom():
155 location
= self
.getLocation().getName()
156 room
= self
.getRoom().getName()
158 if not location
or not room
:
163 .options(lazyload(Room
.owner
))
164 .filter(Room
.name
== fix_broken_string(room
, True),
165 Location
.name
== fix_broken_string(location
, True))
168 def getLocationParent(self
):
170 Returns the object the location info should be inherited from
173 raise Exception("Unimplemented method")
175 def getLocation(self
):
176 if self
.getOwnLocation():
177 return self
.getOwnLocation()
178 return self
.getInheritedLocation()
180 def getOwnLocation(self
):
181 if len(self
.places
) > 0:
182 return self
.places
[0]
185 def getInheritedLocation(self
):
186 return self
.getLocationParent().getLocation()
188 def getOwnRoom(self
):
189 if len(self
.rooms
) > 0:
194 if self
.getOwnRoom():
195 return self
.getOwnRoom()
196 return self
.getInheritedRoom()
198 def getInheritedRoom(self
):
199 return self
.getLocationParent().getRoom()
201 def setLocation(self
, newLocation
):
202 oldLocation
= self
.getOwnLocation()
203 if newLocation
is None:
204 if len(self
.places
) > 0:
206 elif len(self
.places
) > 0:
207 self
.places
[0] = newLocation
209 self
.places
.append(newLocation
)
210 self
.notifyModification()
212 def setRoom(self
, newRoom
):
213 oldRoom
= self
.getOwnRoom()
215 if len(self
.rooms
) > 0:
217 elif len(self
.rooms
) > 0:
218 self
.rooms
[0] = newRoom
220 self
.rooms
.append(newRoom
)
221 self
.notifyModification()
224 class CommonObjectBase(CoreObject
, Fossilizable
):
226 This class is for holding commonly used methods that are used by several classes.
227 It is inherited by the following classes:
237 def getRecursiveManagerList(self
):
240 # Get the AccessProtectionLevel for this
241 apl
= self
.getAccessProtectionLevel()
246 for av
in self
.getManagerList():
248 for av
in self
.getOwner().getRecursiveManagerList():
251 for av
in self
.getManagerList():
255 for av
in self
.getOwner().getRecursiveManagerList():
260 def getRecursiveAllowedToAccessList(self
, onlyManagers
=False):
261 """Returns a set of Avatar resp. Group objects for those people resp.
262 e-groups allowed to access this object as well as all parent objects.
265 # Initialize set of avatars/groups: this will hold those
266 # people/groups explicitly
267 # allowed to access this object
270 # Get the AccessProtectionLevel for this
271 apl
= self
.getAccessProtectionLevel()
273 # If this object is "absolutely public", then return an empty set
277 # If this object is protected "all by itself", then get the list of
278 # people/groups allowed to access it, plus managers of owner(s)
280 al
= self
.getAllowedToAccessList() + self
.getManagerList() + \
281 self
.getOwner().getRecursiveManagerList()
286 # If access settings are inherited (and PRIVATE) from its owners, look at those.
287 elif apl
== 0 and self
.isProtected():
288 # If event is protected, then get list of people/groups allowed
289 # to access, and add that to the set of avatars.
290 al
= self
.getAllowedToAccessList() + self
.getManagerList()
295 # Add list of avatars/groups allowed to access parents objects.
296 owner
= self
.getOwner()
297 if owner
is not None:
298 owner_al
= owner
.getRecursiveAllowedToAccessList(onlyManagers
=True)
299 if owner_al
is not None:
303 # return set containing whatever avatars/groups we may have collected
306 def canIPAccess(self
, ip
):
307 domains
= self
.getAccessController().getAnyDomainProtection()
309 return any(domain
.belongsTo(ip
) for domain
in domains
)
314 class CategoryManager(ObjectHolder
):
315 idxName
= "categories"
316 counterName
= "CATEGORY"
318 def add(self
, category
):
319 ObjectHolder
.add(self
, category
)
320 # Add category to the name index
321 nameIdx
= indexes
.IndexesHolder().getIndex('categoryName')
322 nameIdx
.index(category
)
324 def remove(self
, category
):
325 ObjectHolder
.remove(self
, category
)
326 # remove category from the name index
327 nameIdx
= indexes
.IndexesHolder().getIndex('categoryName')
328 nameIdx
.unindex(category
)
329 Catalog
.getIdx('categ_conf_sd').remove_category(category
.getId())
333 returns a new id for the category
334 the id must not already exist in the collection
336 id = ObjectHolder
._newId
(self
)
337 while self
.hasKey(id):
338 id = ObjectHolder
._newId
(self
)
342 root
= DBMgr
.getInstance().getDBConnection().root()
343 if not root
.has_key("rootCategory"):
347 root
["rootCategory"] = r
348 return root
["rootCategory"]
350 def getDefaultConference(self
):
351 dconf
= HelperMaKaCInfo
.getMaKaCInfoInstance().getDefaultConference()
353 return HelperMaKaCInfo
.getMaKaCInfoInstance().setDefaultConference(DefaultConference())
358 class Category(CommonObjectBase
):
359 fossilizes(ICategoryFossil
)
365 self
.description
= ""
366 self
.subcategories
= {}
368 self
.conferences
= OOTreeSet()
369 self
._numConferences
= 0
371 self
._defaultStyle
= {"simple_event": "", "meeting": ""}
373 self
.__ac
= AccessController(self
)
374 self
.__confCreationRestricted
= 1
375 self
.__confCreators
= []
376 self
._visibility
= 999
377 self
._statistics
= {"events": None, "contributions": None, "resources": None,
381 #self._materials = {}
383 self
._tasksAllowed
= False
385 self
._taskIdGenerator
= 0
386 self
._tasksPublic
= True
387 self
._tasksCommentPublic
= True
388 self
._tasksManagers
= []
389 self
._tasksCommentators
= []
390 self
._taskAccessList
= []
392 self
.__materialGenerator
= Counter()
393 self
._notifyCreationList
= ""
395 def __cmp__(self
, other
):
396 if type(self
) is not type(other
):
397 # This is actually dangerous and the ZODB manual says not to do this
398 # because it relies on memory order. However, this branch should never
399 # be taken anyway since we do not store different types in the same set
400 # or use them as keys.
401 return cmp(hash(self
), hash(other
))
402 return cmp(self
.getId(), other
.getId())
406 path
= '/'.join(self
.getCategoryPathTitles()[:-1])
407 return '<Category({0}, {1}, {2})>'.format(self
.getId(), self
.getName(), path
)
412 return url_for('misc.index')
414 return url_for('category.categoryDisplay', self
)
416 def getAccessController(self
):
419 def updateNonInheritingChildren(self
, elem
, delete
=False):
422 def getNotifyCreationList(self
):
423 """ self._notifyCreationList is a string containing the list of
424 email addresses to send an email to when a new event is created"""
426 return self
._notifyCreationList
428 self
._notifyCreationList
= ""
429 return self
._notifyCreationList
431 def setNotifyCreationList(self
, value
):
432 self
._notifyCreationList
= value
434 def getUniqueId(self
):
435 return "cat%s" % self
.getId()
437 def setPaper(self
, newPaper
):
438 if self
.getPaper() is not None:
439 raise MaKaCError(_("The paper for this conference has already been set"), _("Conference"))
440 self
.paper
= newPaper
441 self
.paper
.setOwner(self
)
442 self
.notifyModification()
444 def removePaper(self
):
445 if self
.paper
is None:
448 self
.paper
.setOwner(None)
450 self
.notifyModification()
452 def recoverPaper(self
, p
):
460 except AttributeError:
464 def setSlides(self
, newSlides
):
465 if self
.getSlides() is not None:
466 raise MaKaCError(_("The slides for this conference have already been set"), _("Conference"))
467 self
.slides
= newSlides
468 self
.slides
.setOwner(self
)
469 self
.notifyModification()
471 def removeSlides(self
):
472 if self
.slides
is None:
475 self
.slides
.setOwner(None)
477 self
.notifyModification()
479 def recoverSlides(self
, s
):
487 except AttributeError:
491 def setVideo(self
, newVideo
):
492 if self
.getVideo() is not None:
493 raise MaKaCError(_("The video for this conference has already been set"), _("Conference"))
494 self
.video
= newVideo
495 self
.video
.setOwner(self
)
496 self
.notifyModification()
498 def removeVideo(self
):
499 if self
.getVideo() is None:
502 self
.video
.setOwner(None)
504 self
.notifyModification()
506 def recoverVideo(self
, v
):
514 except AttributeError:
518 def setPoster(self
, newPoster
):
519 if self
.getPoster() is not None:
520 raise MaKaCError(_("the poster for this conference has already been set"), _("Conference"))
521 self
.poster
= newPoster
522 self
.poster
.setOwner(self
)
523 self
.notifyModification()
525 def removePoster(self
):
526 if self
.getPoster() is None:
529 self
.poster
.setOwner(None)
531 self
.notifyModification()
533 def recoverPoster(self
, p
):
541 except AttributeError:
545 def setMinutes(self
, newMinutes
):
546 if self
.getMinutes() is not None:
547 raise MaKaCError(_("The Minutes for this conference has already been set"))
548 self
.minutes
= newMinutes
549 self
.minutes
.setOwner(self
)
550 self
.notifyModification()
552 def createMinutes(self
):
553 if self
.getMinutes() is not None:
554 raise MaKaCError(_("The minutes for this conference have already been created"), _("Conference"))
555 self
.minutes
= Minutes()
556 self
.minutes
.setOwner(self
)
557 self
.notifyModification()
560 def removeMinutes(self
):
561 if self
.getMinutes() is None:
563 self
.minutes
.delete()
564 self
.minutes
.setOwner(None)
566 self
.notifyModification()
568 def recoverMinutes(self
, min):
569 self
.removeMinutes() # To ensure that the current minutes are put in
572 self
.minutes
.setOwner(self
)
574 self
.notifyModification()
577 def getMinutes(self
):
582 except AttributeError, e
:
586 def addMaterial(self
, newMat
):
588 newMat
.setId(str(self
.__materialGenerator
.newCount()))
590 self
.__materialGenerator
= Counter()
591 newMat
.setId(self
.__materialGenerator
.newCount())
592 newMat
.setOwner(self
)
593 self
.materials
[newMat
.getId()] = newMat
594 self
.notifyModification()
596 def removeMaterial(self
, mat
):
597 if mat
.getId() in self
.materials
.keys():
599 self
.materials
[mat
.getId()].setOwner(None)
600 del self
.materials
[mat
.getId()]
601 self
.notifyModification()
602 return "done: %s" % mat
.getId()
603 elif mat
.getId().lower() == 'minutes':
605 return "done: %s" % mat
.getId()
606 elif mat
.getId().lower() == 'paper':
608 return "done: %s" % mat
.getId()
609 elif mat
.getId().lower() == 'slides':
611 return "done: %s" % mat
.getId()
612 elif mat
.getId().lower() == 'video':
614 return "done: %s" % mat
.getId()
615 elif mat
.getId().lower() == 'poster':
617 return "done: %s" % mat
.getId()
618 return "not done: %s" % mat
.getId()
620 def recoverMaterial(self
, recMat
):
621 # Id must already be set in recMat.
622 recMat
.setOwner(self
)
623 self
.materials
[recMat
.getId()] = recMat
625 self
.notifyModification()
627 def getMaterialRegistry(self
):
629 Return the correct material registry for this type
631 from MaKaC
.webinterface
.materialFactories
import CategoryMFRegistry
632 return CategoryMFRegistry
634 def getMaterialById(self
, matId
):
635 if matId
.lower() == 'paper':
636 return self
.getPaper()
637 elif matId
.lower() == 'slides':
638 return self
.getSlides()
639 elif matId
.lower() == 'video':
640 return self
.getVideo()
641 elif matId
.lower() == 'poster':
642 return self
.getPoster()
643 elif matId
.lower() == 'minutes':
644 return self
.getMinutes()
645 elif self
.materials
.has_key(matId
):
646 return self
.materials
[matId
]
649 def getMaterialList(self
):
651 return self
.materials
.values()
654 return self
.materials
.values()
656 def getAllMaterialList(self
):
657 l
= self
.getMaterialList()
659 l
.append(self
.getPaper())
661 l
.append(self
.getSlides())
663 l
.append(self
.getVideo())
665 l
.append(self
.getPoster())
666 if self
.getMinutes():
667 l
.append(self
.getMinutes())
670 def getTaskList(self
):
672 return self
._tasks
.values()
675 return self
._tasks
.values()
687 def getTask(self
, taskId
):
688 return self
.getTasks().get(taskId
, None)
690 def _getTasksAllowed(self
):
692 return self
._tasksAllowed
694 self
._tasksAllowed
= False
695 return self
._tasksAllowed
697 def tasksAllowed(self
):
698 if self
.hasSubcategories():
700 return self
._getTasksAllowed
()
702 def setTasksAllowed(self
):
703 if self
.hasSubcategories():
705 self
._getTasksAllowed
()
706 self
._tasksAllowed
= True
707 self
.notifyModification()
710 def setTasksForbidden(self
):
711 if len(self
.getTaskList()) > 0:
713 self
._getTasksAllowed
()
714 self
._tasksAllowed
= False
715 self
.notifyModification()
718 def _getNewTaskId(self
):
720 if self
._taskIdGenerator
:
723 self
._taskIdGenerator
= 0
724 self
._taskIdGenerator
= self
._taskIdGenerator
+ 1
725 return self
._taskIdGenerator
727 def newTask(self
, user
):
730 newTask
= task
.Task(self
, self
._getNewTaskId
(), user
)
731 self
.getTasks()["%s" % newTask
.getId()] = newTask
732 self
.notifyModification()
735 def tasksPublic(self
):
737 return self
._tasksPublic
739 self
._tasksPublic
= True
740 return self
._tasksPublic
742 def setTasksPublic(self
):
744 self
._tasksPublic
= True
746 def setTasksPrivate(self
):
748 self
._tasksPublic
= False
750 def tasksCommentPublic(self
):
752 return self
._tasksCommentPublic
754 self
._tasksCommentPublic
= True
755 return self
._tasksCommentPublic
757 def setTasksCommentPublic(self
):
758 self
.tasksCommentPublic()
759 self
._tasksCommentPublic
= True
761 def setTasksCommentPrivate(self
):
762 self
.tasksCommentPublic()
763 self
._tasksCommentPublic
= False
765 def getTasksManagerList(self
):
767 return self
._tasksManagers
769 self
._tasksManagers
= []
771 return self
._tasksManagers
773 def getTasksManager(self
, index
):
774 length
= len(self
.getTasksManagerList())
775 if index
< 0 or index
>= length
:
777 return self
._tasksManagers
[index
]
779 def addTasksManager(self
, user
):
782 self
.getTasksManagerList().append(user
)
786 def removeTasksManager(self
, index
):
787 length
= len(self
.getTasksManagerList())
788 if index
< 0 or index
>= length
:
790 del self
.getTasksManagerList()[index
]
794 def getTasksCommentatorList(self
):
796 return self
._tasksCommentators
798 self
._tasksCommentators
= []
800 return self
._tasksCommentators
802 def getTasksCommentator(self
, index
):
803 length
= len(self
.getTasksCommentatorList())
804 if index
< 0 or index
>= length
:
806 return self
._tasksCommentators
[index
]
808 def addTasksCommentator(self
, user
):
811 self
.getTasksCommentatorList().append(user
)
815 def removeTasksCommentator(self
, index
):
816 length
= len(self
.getTasksCommentatorList())
817 if index
< 0 or index
>= length
:
819 del self
._tasksCommentators
[index
]
823 def getTasksAccessList(self
):
825 return self
._tasksAccessList
827 self
._tasksAccessList
= []
829 return self
._tasksAccessList
831 def getTasksAccessPerson(self
, index
):
832 length
= len(self
.getTasksAccessList())
833 if index
< 0 or index
>= length
:
835 return self
._tasksAccessList
[index
]
837 def addTasksAccessPerson(self
, user
):
840 self
.getTasksAccessList().append(user
)
844 def removeTasksAccessPerson(self
, index
):
845 length
= len(self
.getTasksAccessList())
846 if index
< 0 or index
>= length
:
848 del self
.getTasksAccessList()[index
]
852 def hasSubcategories(self
):
853 return len(self
.subcategories
.values()) > 0
855 def getVisibility(self
):
857 Returns category visibility, considering that it can be
858 restricted by parent categories
860 owner
= self
.getOwner()
861 visibility
= int(self
._visibility
)
863 # visibility can be restricted by parent categories
865 return max(0, min(visibility
, owner
.getVisibility() + 1))
869 def setVisibility(self
, visibility
=999):
870 self
._visibility
= int(visibility
)
873 def isSuggestionsDisabled(self
):
875 return self
._suggestions
_disabled
876 except AttributeError:
877 self
._suggestions
_disabled
= False
880 def setSuggestionsDisabled(self
, value
):
881 self
._suggestions
_disabled
= value
884 catIdx
= indexes
.IndexesHolder().getIndex('category')
885 catIdx
.reindexCateg(self
)
886 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
887 catDateIdx
.reindexCateg(self
)
888 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
889 catDateAllIdx
.reindexCateg(self
)
893 return self
.owner
is None
895 def getDefaultStyle(self
, type):
897 return self
._defaultStyle
[type]
901 def setDefaultStyle(self
, type, style
, subcatsStyle
=False):
903 self
._defaultStyle
[type] = style
905 self
._defaultStyle
= {"simple_event": "", "meeting": ""}
906 self
._defaultStyle
[type] = style
907 self
.notifyModification()
908 #raise str(subcatsStyle)
911 categ
= self
.getSubCategoryList()
914 cat
.setDefaultStyle(type, style
, subcatsStyle
)
916 ##################################
917 # Fermi timezone awareness #
918 ##################################
919 def getTimezone(self
):
921 if self
._timezone
not in all_timezones
:
922 self
.setTimezone('UTC')
923 return self
._timezone
925 self
.setTimezone('UTC')
928 def setTimezone(self
, tz
):
931 def changeConfTimezones(self
, tz
):
932 for conference
in self
.getConferenceList():
933 conference
.moveToTimezone(tz
)
935 ##################################
936 # Fermi timezone awareness(end) #
937 ##################################
946 def setOrder(self
, order
):
952 def setId(self
, newId
):
953 self
.id = str(newId
.strip())
955 def getLocator(self
):
956 """Gives back (Locator) a globaly unique identification encapsulated
957 in a Locator object for the category instance """
959 d
["categId"] = self
.getId()
962 def getCategory(self
):
968 def setOwner(self
, newOwner
):
969 if self
.getOwner() is not None and newOwner
is not None and self
.getOwner() != newOwner
:
972 self
.owner
= newOwner
974 def getCategoryPath(self
):
976 return [self
.getId()]
978 l
= self
.getOwner().getCategoryPath()
979 l
.append(self
.getId())
982 def iterParents(self
):
984 while not categ
.isRoot():
985 categ
= categ
.getOwner()
988 def getCategoryPathTitles(self
):
993 breadcrumbs
.insert(0, cat
.getTitle())
997 def delete(self
, deleteConferences
=0):
998 """removes completely a category (and all its sub-items) from the
1001 oldOwner
= self
.getOwner()
1004 raise MaKaCError(_("Root category cannot be deleted"), _("Category"))
1005 if not deleteConferences
:
1006 if self
.getNumConferences() > 0:
1007 raise MaKaCError(_("This category still contains some conferences, please remove them first"), _("Category"))
1008 for subcateg
in self
.getSubCategoryList():
1009 subcateg
.delete(deleteConferences
)
1010 for conference
in self
.getConferenceList():
1011 self
.removeConference(conference
, delete
=True)
1012 self
.getOwner()._removeSubCategory
(self
)
1013 CategoryManager().remove(self
)
1014 for prin
in self
.__ac
.getAccessList():
1015 if isinstance(prin
, AvatarUserWrapper
):
1016 prin
.unlinkTo(self
, "access")
1017 for prin
in self
.__ac
.getModifierList():
1018 if isinstance(prin
, AvatarUserWrapper
):
1019 prin
.unlinkTo(self
, "manager")
1020 TrashCanManager().add(self
)
1022 signals
.category
.deleted
.send(self
)
1026 def move(self
, newOwner
):
1027 oldOwner
= self
.getOwner()
1028 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
1029 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
1031 catDateIdx
.unindexCateg(self
)
1032 catDateAllIdx
.unindexCateg(self
)
1034 self
.getOwner()._removeSubCategory
(self
)
1035 newOwner
._addSubCategory
(self
)
1037 catDateIdx
.indexCateg(self
)
1038 catDateAllIdx
.indexCateg(self
)
1040 signals
.category
.moved
.send(self
, old_parent
=oldOwner
, new_parent
=newOwner
)
1045 def setName(self
, newName
):
1047 self
.name
= newName
.strip()
1049 # Reindex when name changes
1050 nameIdx
= indexes
.IndexesHolder().getIndex('categoryName')
1051 nameIdx
.unindex(self
)
1054 signals
.category
.title_changed
.send(self
, old
=oldName
, new
=newName
)
1056 def getDescription(self
):
1057 return self
.description
1059 def setDescription(self
, newDesc
):
1060 self
.description
= newDesc
.strip()
1062 def moveConference(self
, conf
, toCateg
):
1064 Moves a conference from this category to another one
1066 self
.removeConference(conf
)
1067 toCateg
._addConference
(conf
)
1068 signals
.event
.moved
.send(conf
, old_parent
=self
, new_parent
=toCateg
)
1070 def _addSubCategory(self
, newSc
):
1071 #categories can only contain either conferences either other categories
1072 # but can never contain both. For the moment an exception is raised
1073 # but this could be replaced by the following policy: if a
1074 # sub-category is to be added to a category already containing
1075 # conferences then the conferes are moved into the new sub-category
1076 # and it is added to target category.
1077 #first, check that the category is registered if not raise an exception
1078 if len(self
.conferences
) > 0:
1079 for conf
in self
.getConferenceList():
1080 self
.moveConference(conf
, newSc
)
1082 if len(self
.conferences
) > 0:
1083 raise MaKaCError(_("Cannot add subcategory: the current category already contains events"), _("Category"))
1084 newSc
.setOwner(self
)
1085 self
.subcategories
[newSc
.getId()] = newSc
1086 self
._incNumConfs
(newSc
.getNumConferences())
1088 def _removeSubCategory(self
, sc
):
1089 """if the given subcategory belongs to the current category it removes
1090 it from the subcategories list (don't use this method, use delete
1093 if sc
in self
.getSubCategoryList():
1094 self
._decNumConfs
(sc
.getNumConferences())
1095 del self
.subcategories
[sc
.getId()]
1098 def newSubCategory(self
, protection
):
1099 cm
= CategoryManager()
1103 # set the protection
1104 sc
.setProtection(protection
)
1106 Catalog
.getIdx('categ_conf_sd').add_category(sc
.getId())
1107 signals
.category
.created
.send(sc
, parent
=self
)
1109 self
._addSubCategory
(sc
)
1110 sc
.setOrder(self
.getSubCategoryList()[-1].getOrder() + 1)
1114 def _incNumConfs(self
, num
=1):
1115 """Increases the number of conferences for the current category in a given number.
1116 WARNING: Only Categories must use this method!!!"""
1117 self
._numConferences
= self
.getNumConferences()
1118 self
._numConferences
+= num
1119 if self
.getOwner() is not None:
1120 self
.getOwner()._incNumConfs
(num
)
1122 def _decNumConfs(self
, num
=1):
1123 """Decreases the number of conferences for the current category in a given number.
1124 WARNING: Only Categories must use this method!!!"""
1125 self
._numConferences
= self
.getNumConferences()
1126 self
._numConferences
-= num
1127 if self
.getOwner() is not None:
1128 self
.getOwner()._decNumConfs
(num
)
1130 def _addConference(self
, newConf
):
1131 if len(self
.subcategories
) > 0:
1132 raise MaKaCError(_("Cannot add event: the current category already contains some sub-categories"), _("Category"))
1133 if newConf
.getId() == "":
1134 raise MaKaCError(_("Cannot add to a category an event which is not registered"), _("Category"))
1135 self
.conferences
.insert(newConf
)
1136 newConf
.addOwner(self
)
1137 self
._incNumConfs
(1)
1138 self
.indexConf(newConf
)
1140 def getAccessKey(self
):
1143 def getModifKey(self
):
1146 def indexConf(self
, conf
):
1147 # Specific for category changes, calls Conference.indexConf()
1148 # (date-related indexes)
1149 catIdx
= indexes
.IndexesHolder().getIndex('category')
1150 catIdx
.indexConf(conf
)
1153 def unindexConf(self
, conf
):
1154 catIdx
= indexes
.IndexesHolder().getIndex('category')
1155 catIdx
.unindexConf(conf
)
1158 def newConference(self
, creator
, id="", creationDate
=None, modificationDate
=None):
1159 conf
= Conference(creator
, id, creationDate
, modificationDate
)
1160 ConferenceHolder().add(conf
)
1161 self
._addConference
(conf
)
1164 signals
.event
.created
.send(conf
, parent
=self
)
1168 def removeConference(self
, conf
, notify
=True, delete
=False):
1169 if not (conf
in self
.conferences
):
1172 self
.unindexConf(conf
)
1174 self
.conferences
.remove(conf
)
1177 conf
.removeOwner(self
, notify
)
1178 self
._decNumConfs
(1)
1180 def getSubCategoryList(self
):
1181 subcategs
= self
.subcategories
.values()
1183 for categ
in subcategs
:
1184 cl
.append("%04s%s-%s" % (categ
.getOrder(), categ
.getName().replace("-", ""), categ
.getId()))
1188 id = c
.split("-")[1]
1189 res
.append(self
.subcategories
[id])
1192 def iteritems(self
, *args
):
1193 return self
.conferences
.iteritems(*args
)
1195 def itervalues(self
, *args
):
1196 return self
.conferences
.itervalues(*args
)
1198 def getConferenceList(self
, sortType
=1):
1199 """returns the list of conferences included in the current category.
1200 Thanks to the used structure the list is sorted by date.
1201 We can choose other sorting types:
1203 sortType=1--> By date
1204 sortType=2--> Alphabetically
1205 sortType=3--> Alphabetically - Reversed
1208 res
= sorted(self
.conferences
, cmp=Conference
._cmpByDate
)
1211 res
.sort(Conference
._cmpTitle
)
1213 res
.sort(Conference
._cmpTitle
)
1217 def iterConferences(self
):
1218 """returns the iterator for conferences.
1220 return self
.conferences
1222 def iterAllConferences(self
):
1223 """returns the iterator for conferences in all subcategories.
1225 for conf
in self
.conferences
:
1228 for subcateg
in self
.subcategories
.itervalues():
1229 for conf
in subcateg
.iterAllConferences():
1232 def getAllConferenceList(self
):
1233 """returns the list of all conferences included in the current category
1234 and in all its subcategories"""
1235 res
= self
.getConferenceList()
1236 subcategs
= self
.getSubCategoryList()
1238 for subcateg
in subcategs
:
1239 res
.extend(subcateg
.getAllConferenceList())
1242 def getRelativeEvent(self
, which
, conf
=None):
1243 index
= Catalog
.getIdx('categ_conf_sd').getCategory(self
.getId())
1244 if which
== 'first':
1245 return list(index
[index
.minKey()])[0]
1246 elif which
== 'last':
1247 return list(index
[index
.maxKey()])[-1]
1248 elif which
in ('next', 'prev'):
1249 categIter
= index
.itervalues()
1256 nextEvt
= next(categIter
, None)
1262 raise AttributeError("'conf' parameter missing")
1264 raise AttributeError("Unknown argument value: '%s'" % which
)
1266 def _setNumConferences(self
):
1267 self
._numConferences
= 0
1268 if self
.conferences
:
1269 self
._incNumConfs
(len(self
.conferences
))
1271 for sc
in self
.getSubCategoryList():
1272 self
._incNumConfs
(sc
.getNumConferences())
1274 def getNumConferences(self
):
1275 """returns the total number of conferences contained in the current
1276 category and all its sub-categories (if any)"""
1277 #this new approach will speed up considerably the counting of category
1278 # conferences. However, it will give non accurate results for
1279 # conferences within many categories (a conference will be counted
1280 # twice in parent categories).
1281 # Besides this approach will generate much more conflict errors. This
1282 # can be reduced by simply isolating the counter in a separate object.
1284 if self
._numConferences
:
1286 except AttributeError:
1287 self
._setNumConferences
()
1288 return self
._numConferences
1290 def _getRepository(self
):
1291 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
1293 fr
= dbRoot
["local_repositories"]["main"]
1295 fr
= fileRepository
.MaterialLocalRepository()
1296 dbRoot
["local_repositories"] = OOBTree()
1297 dbRoot
["local_repositories"]["main"] = fr
1300 def removeResource(self
, res
):
1303 def setIcon(self
, iconFile
):
1304 iconFile
.setOwner(self
)
1305 iconFile
.setId("icon")
1306 iconFile
.archive(self
._getRepository
())
1307 iconFile
.setProtection(-1)
1308 if self
.getIcon() is not None:
1310 self
._icon
= iconFile
1311 self
.notifyModification()
1317 except AttributeError, e
:
1321 def getIconURL(self
):
1322 if self
.getIcon() is None:
1324 return self
._icon
.getURL()
1326 def removeIcon(self
):
1327 if self
.getIcon() is None:
1331 self
.notifyModification()
1333 def recoverIcon(self
, icon
):
1335 if self
.getIcon() is not None:
1339 self
.notifyModification()
1341 def getManagerList(self
):
1342 return self
.__ac
.getModifierList()
1344 def grantModification(self
, prin
):
1345 self
.__ac
.grantModification(prin
)
1346 if isinstance(prin
, AvatarUserWrapper
):
1347 prin
.linkTo(self
, "manager")
1349 def revokeModification(self
, prin
):
1350 self
.__ac
.revokeModification(prin
)
1351 if isinstance(prin
, AvatarUserWrapper
):
1352 prin
.unlinkTo(self
, "manager")
1354 def canModify(self
, aw_or_user
):
1355 if hasattr(aw_or_user
, 'getUser'):
1356 aw_or_user
= aw_or_user
.getUser()
1357 return self
.canUserModify(aw_or_user
)
1359 def canUserModify(self
, av
):
1361 if self
.getOwner() is not None:
1362 inherited
= self
.getOwner().canUserModify(av
)
1363 return inherited
or self
.__ac
.canModify(av
)
1365 def getAllowedToAccessList(self
):
1366 return self
.__ac
.getAccessList()
1368 def canKeyAccess(self
, aw
):
1369 # Categories don't allow access keys
1372 def isProtected(self
):
1373 return self
.__ac
.isProtected()
1375 def getAccessProtectionLevel(self
):
1376 return self
.__ac
.getAccessProtectionLevel()
1378 def isItselfProtected(self
):
1379 return self
.__ac
.isItselfProtected()
1381 def hasAnyProtection(self
):
1382 if self
.__ac
.isProtected() or len(self
.getDomainList()) > 0:
1384 if self
.getAccessProtectionLevel() == -1: # PUBLIC
1386 if self
.getOwner() is not None:
1387 return self
.getOwner().hasAnyProtection()
1390 def setProtection(self
, private
):
1392 Allows to change the category's access protection
1395 oldProtection
= 1 if self
.isProtected() else -1
1397 self
.__ac
.setProtection(private
)
1398 if oldProtection
!= private
:
1399 signals
.category
.protection_changed
.send(self
, old
=oldProtection
, new
=private
)
1401 def hasProtectedOwner(self
):
1402 return self
.__ac
._getFatherProtection
()
1404 def isAllowedToAccess(self
, av
):
1405 """Says whether an avatar can access a category independently of it is
1406 or not protected or domain filtered
1408 if self
.__ac
.canUserAccess(av
) or self
.canUserModify(av
):
1410 if not self
.isItselfProtected() and self
.getOwner():
1411 return self
.getOwner().isAllowedToAccess(av
)
1413 def canView(self
, aw
):
1414 if self
.canAccess(aw
):
1416 for conf
in self
.getConferenceList():
1417 if conf
.canView(aw
):
1419 for subcateg
in self
.getSubCategoryList():
1420 if subcateg
.canView(aw
):
1424 def canAccess(self
, aw
):
1425 if not self
.hasAnyProtection():
1427 if not self
.isProtected():
1428 # domain checking only triggered if the category is PUBLIC
1429 return self
.canIPAccess(request
.remote_addr
) or \
1430 self
.isAllowedToCreateConference(aw
.getUser()) or \
1431 self
.isAllowedToAccess(aw
.getUser())
1432 return self
.isAllowedToCreateConference(aw
.getUser()) or \
1433 self
.isAllowedToAccess(aw
.getUser())
1435 def grantAccess(self
, prin
):
1436 self
.__ac
.grantAccess(prin
)
1437 if isinstance(prin
, AvatarUserWrapper
):
1438 prin
.linkTo(self
, "access")
1440 def revokeAccess(self
, prin
):
1441 self
.__ac
.revokeAccess(prin
)
1442 if isinstance(prin
, AvatarUserWrapper
):
1443 prin
.unlinkTo(self
, "access")
1445 def isConferenceCreationRestricted(self
):
1446 return self
.__confCreationRestricted
1448 def restrictConferenceCreation(self
):
1449 self
.__confCreationRestricted
= 1
1451 def allowConferenceCreation(self
):
1452 self
.__confCreationRestricted
= 0
1454 def grantConferenceCreation(self
, prin
):
1455 if prin
not in self
.__confCreators
:
1456 self
.__confCreators
.append(prin
)
1457 if isinstance(prin
, AvatarUserWrapper
):
1458 prin
.linkTo(self
, "creator")
1461 def revokeConferenceCreation(self
, prin
):
1462 if prin
in self
.__confCreators
:
1463 self
.__confCreators
.remove(prin
)
1464 if isinstance(prin
, AvatarUserWrapper
):
1465 prin
.unlinkTo(self
, "creator")
1468 def getConferenceCreatorList(self
):
1469 return self
.__confCreators
1471 def isAllowedToCreateConference(self
, av
):
1473 if self
.canUserModify(av
):
1476 # Avatar is directly in the list
1477 if av
in self
.__confCreators
:
1480 # Otherwise, if it is a member of one of the groups in the list...
1481 for group
in self
.__confCreators
:
1482 if isinstance(group
, GroupWrapper
):
1483 if group
.containsUser(av
):
1487 def canCreateConference(self
, av
):
1488 if not self
.isConferenceCreationRestricted():
1490 return self
.isAllowedToCreateConference(av
)
1492 def requireDomain(self
, dom
):
1493 self
.__ac
.requireDomain(dom
)
1494 signals
.category
.domain_access_granted
.send(self
, domain
=dom
)
1496 def freeDomain(self
, dom
):
1497 self
.__ac
.freeDomain(dom
)
1498 signals
.category
.domain_access_revoked
.send(self
, domain
=dom
)
1501 def getDomainList(self
):
1502 return self
.__ac
.getRequiredDomainList()
1504 def getStatistics(self
):
1506 if self
._statistics
:
1508 except AttributeError, e
:
1509 self
._statistics
= {}
1510 return self
._statistics
1512 def notifyModification(self
, raiseEvent
=True):
1513 """Method called to notify the current category has been modified.
1516 signals
.category
.data_changed
.send(self
)
1520 class CustomLocation(Persistent
):
1522 def __init__(self
, **locationData
):
1527 def setValues(self
, data
):
1528 self
.setName(data
.get("name", ""))
1529 self
.setAddress(data
.get("address", ""))
1530 self
.setRoom(data
.get("room", ""))
1532 def getValues(self
):
1534 d
["name"] = self
.getName()
1535 d
["address"] = self
.getAddress()
1536 d
["room"] = self
.getRoom()
1540 newCL
= CustomLocation()
1541 newCL
.setValues(self
.getValues())
1544 def setName(self
, newName
):
1550 def setAddress(self
, newAddress
):
1551 self
.address
= newAddress
1553 def getAddress(self
):
1556 def setRoom(self
, newRoom
):
1563 class CustomRoom(Persistent
):
1568 def setValues(self
, data
):
1569 self
.setName(data
.get("name", ""))
1570 self
.setFullName(data
.get("fullName"))
1572 def getValues(self
):
1574 d
["name"] = self
.getName()
1575 d
["fullName"] = self
.getFullName()
1582 newCR
= CustomRoom()
1583 newCR
.setValues(self
.getValues())
1586 def setName(self
, newName
):
1587 self
.name
= newName
.strip()
1592 def retrieveFullName(self
, location
):
1595 room
= Room
.find_first(Room
.name
== fix_broken_string(self
.name
, True),
1596 Location
.name
== fix_broken_string(location
, True),
1597 _join
=Room
.location
)
1598 self
.fullName
= room
.full_name
if room
else None
1600 def setFullName(self
, newFullName
):
1601 self
.fullName
= newFullName
1603 def getFullName(self
):
1604 if not hasattr(self
, 'fullName'):
1605 self
.fullName
= None
1606 return self
.fullName
1609 class ConferenceParticipation(Persistent
, Fossilizable
):
1611 fossilizes(IConferenceParticipationFossil
, IConferenceParticipationMinimalFossil
)
1617 self
._affiliation
=""
1623 def _notifyModification( self
):
1626 def setValues(self
, data
):
1627 self
.setFirstName(data
.get("firstName", ""))
1628 self
.setFamilyName(data
.get("familyName",""))
1629 self
.setAffiliation(data
.get("affilation",""))
1630 self
.setAddress(data
.get("address",""))
1631 self
.setEmail(data
.get("email",""))
1632 self
.setFax(data
.get("fax",""))
1633 self
.setTitle(data
.get("title",""))
1634 self
.setPhone(data
.get("phone",""))
1635 self
._notifyModification
()
1637 def getValues(self
):
1639 data
["firstName"]=self
.getFirstName()
1640 data
["familyName"]=self
.getFamilyName()
1641 data
["affilation"]=self
.getAffiliation()
1642 data
["address"]=self
.getAddress()
1643 data
["email"]=self
.getEmail()
1644 data
["fax"]=self
.getFax()
1645 data
["title"]=self
.getTitle()
1646 data
["phone"]=self
.getPhone()
1649 def setId(self
, newId
):
1655 def setDataFromAvatar(self
,av
):
1656 # av is an Avatar object.
1659 self
.setFirstName(av
.getName())
1660 self
.setFamilyName(av
.getSurName())
1661 self
.setEmail(av
.getEmail())
1662 self
.setAffiliation(av
.getOrganisation())
1663 self
.setAddress(av
.getAddress())
1664 self
.setPhone(av
.getTelephone())
1665 self
.setTitle(av
.getTitle())
1666 self
.setFax(av
.getFax())
1667 self
._notifyModification
()
1669 def setDataFromOtherCP(self
,cp
):
1670 # cp is a ConferenceParticipation object.
1673 self
.setFirstName(cp
.getFirstName())
1674 self
.setFamilyName(cp
.getFamilyName())
1675 self
.setEmail(cp
.getEmail())
1676 self
.setAffiliation(cp
.getAffiliation())
1677 self
.setAddress(cp
.getAddress())
1678 self
.setPhone(cp
.getPhone())
1679 self
.setTitle(cp
.getTitle())
1680 self
.setFax(cp
.getFax())
1681 self
._notifyModification
()
1684 TrashCanManager().add(self
)
1687 TrashCanManager().remove(self
)
1689 @Updates (['MaKaC.conference.ConferenceParticipation',
1690 'MaKaC.conference.SessionChair',
1691 'MaKaC.conference.SlotChair'], 'firstName')
1692 def setFirstName(self
,newName
):
1694 if tmp
==self
._firstName
:
1697 self
._notifyModification
()
1699 def getFirstName( self
):
1700 return self
._firstName
1702 @Updates (['MaKaC.conference.ConferenceParticipation',
1703 'MaKaC.conference.SessionChair',
1704 'MaKaC.conference.SlotChair'], 'familyName')
1705 def setFamilyName(self
,newName
):
1707 if tmp
==self
._surName
:
1710 self
._notifyModification
()
1712 def getFamilyName( self
):
1713 return self
._surName
1715 @Updates (['MaKaC.conference.ConferenceParticipation',
1716 'MaKaC.conference.SessionChair',
1717 'MaKaC.conference.SlotChair'], 'email')
1718 def setEmail(self
,newMail
):
1720 if tmp
==self
._email
:
1722 self
._email
=newMail
.strip()
1723 self
._notifyModification
()
1725 def getEmail( self
):
1728 @Updates (['MaKaC.conference.ConferenceParticipation',
1729 'MaKaC.conference.SessionChair',
1730 'MaKaC.conference.SlotChair'], 'affiliation')
1731 def setAffiliation(self
,newAffil
):
1732 self
._affiliation
=newAffil
.strip()
1733 self
._notifyModification
()
1735 def getAffiliation(self
):
1736 return self
._affiliation
1738 @Updates (['MaKaC.conference.ConferenceParticipation',
1739 'MaKaC.conference.SessionChair',
1740 'MaKaC.conference.SlotChair'], 'address')
1741 def setAddress(self
,newAddr
):
1742 self
._address
=newAddr
.strip()
1743 self
._notifyModification
()
1745 def getAddress(self
):
1746 return self
._address
1748 @Updates (['MaKaC.conference.ConferenceParticipation',
1749 'MaKaC.conference.SessionChair',
1750 'MaKaC.conference.SlotChair'], 'phone')
1751 def setPhone(self
,newPhone
):
1752 self
._phone
=newPhone
.strip()
1753 self
._notifyModification
()
1758 @Updates (['MaKaC.conference.ConferenceParticipation',
1759 'MaKaC.conference.SessionChair',
1760 'MaKaC.conference.SlotChair'], 'title')
1761 def setTitle(self
,newTitle
):
1762 self
._title
=newTitle
.strip()
1763 self
._notifyModification
()
1768 @Updates (['MaKaC.conference.ConferenceParticipation',
1769 'MaKaC.conference.SessionChair',
1770 'MaKaC.conference.SlotChair'], 'fax')
1771 def setFax(self
,newFax
):
1772 self
._fax
=newFax
.strip()
1773 self
._notifyModification
()
1778 def getFullName( self
):
1779 res
= self
.getFamilyName()
1780 if self
.getFirstName() != "":
1781 if res
.strip() != "":
1782 res
= "%s, %s"%( res
, self
.getFirstName() )
1784 res
= self
.getFirstName()
1785 if self
.getTitle() != "":
1786 res
= "%s %s"%( self
.getTitle(), res
)
1789 def getFullNameNoTitle( self
):
1790 res
= self
.getFamilyName()
1791 if self
.getFirstName() != "":
1792 if res
.strip() != "":
1793 res
= "%s, %s"%( res
, self
.getFirstName() )
1795 res
= self
.getFirstName()
1798 def getDirectFullName( self
):
1799 res
= "%s %s"%( self
.getFirstName(), self
.getFamilyName() )
1801 if self
.getTitle() != "":
1802 res
= "%s %s"%( self
.getTitle(), res
)
1805 def getAbrName(self
):
1806 res
= self
.getFamilyName()
1807 if self
.getFirstName():
1810 res
= "%s%s." % (res
, safe_upper(safe_slice(self
.getFirstName(), 0, 1)))
1814 def _cmpFamilyName( cp1
, cp2
):
1815 o1
= "%s %s"%(cp1
.getFamilyName(), cp1
.getFirstName())
1816 o2
= "%s %s"%(cp2
.getFamilyName(), cp2
.getFirstName())
1817 o1
=o1
.lower().strip()
1818 o2
=o2
.lower().strip()
1819 return cmp( o1
, o2
)
1822 class ConferenceChair(ConferenceParticipation
, Fossilizable
):
1824 fossilizes(IConferenceParticipationFossil
)
1829 ConferenceParticipation
.__init
__(self
)
1831 def _notifyModification( self
):
1832 if self
._conf
!= None:
1833 self
._conf
.notifyModification()
1836 newCC
=ConferenceChair()
1837 newCC
.setValues(self
.getValues())
1840 def getConference(self
):
1846 def includeInConference(self
,conf
,id):
1847 if self
.getConference()==conf
and self
.getId()==id.strip():
1854 ConferenceParticipation
.delete(self
)
1856 def getLocator(self
):
1857 if self
.getConference() is None:
1859 loc
=self
.getConference().getLocator()
1860 loc
["chairId"]=self
.getId()
1863 class SubmitterIndex(Persistent
):
1864 """Index for contribution submitters.
1866 This class allows to index users with submission privileges over the
1867 conference contributions so the owner can answer optimally to the query
1868 if a user has any submission privilege over any contribution
1870 It is implemented by simply using a BTree where the Avatar id is used
1871 as key (because it is unique and non variable) and a list of
1872 contributions over which he has submission privileges is kept as values.
1873 It is the responsability of the index owner (conference contributions)
1874 to keep it up-to-date i.e. notify conference sumitters additions and
1878 def __init__( self
):
1879 self
._idx
= OOBTree()
1880 self
._idxEmail
= OOBTree()
1882 def _getIdxEmail(self
):
1884 return self
._idxEmail
1886 self
._idxEmail
= OOBTree()
1887 return self
._idxEmail
1889 def getContributions(self
,av
):
1890 """Gives a list with the contributions over which a user has
1891 coordination privileges
1895 ret
= self
._idx
.get(av
.getId(),[])
1897 self
._moveEmailtoId
(av
)
1898 ret
= self
._idx
.get(av
.getId(),[])
1901 def index(self
,av
,contrib
):
1902 """Registers in the index a submitter of a contribution.
1904 if av
==None or contrib
==None:
1906 if not self
._idx
.has_key(av
.getId()):
1908 self
._idx
[av
.getId()]=l
1910 l
=self
._idx
[av
.getId()]
1911 if contrib
not in l
:
1913 self
._idx
[av
.getId()]=l
1915 def indexEmail(self
, email
, contrib
):
1916 if not email
or not contrib
:
1918 if not self
._getIdxEmail
().has_key(email
):
1920 self
._getIdxEmail
()[email
] = l
1922 l
= self
._getIdxEmail
()[email
]
1923 if not contrib
in l
:
1925 self
._getIdxEmail
()[email
] = l
1928 def unindex(self
,av
,contrib
):
1929 if av
==None or contrib
==None:
1931 l
=self
._idx
.get(av
.getId(),[])
1934 self
._idx
[av
.getId()]=l
1936 def unindexEmail(self
, email
, contrib
):
1937 if not email
or not contrib
:
1939 if self
._getIdxEmail
().has_key(email
):
1940 l
= self
._getIdxEmail
()[email
]
1944 del self
._getIdxEmail
()[email
]
1946 self
._getIdxEmail
()[email
] = l
1948 def _moveEmailtoId(self
, av
):
1950 email
= av
.getEmail()
1951 if not self
._idx
.has_key(id):
1952 if self
._getIdxEmail
().has_key(email
):
1953 self
._idx
[id] = self
._getIdxEmail
()[email
]
1954 del self
._getIdxEmail
()[email
]
1957 class ReportNumberHolder(Persistent
):
1959 def __init__(self
, owner
):
1966 def addReportNumber(self
, system
, number
):
1967 if system
in self
.getReportNumberKeys() or system
in Config
.getInstance().getReportNumberSystems().keys():
1969 if not number
in self
._reports
[system
]:
1970 self
._reports
[system
].append(number
)
1972 self
._reports
[system
]=[ number
]
1973 self
.notifyModification()
1975 def removeReportNumber(self
, system
, number
):
1976 if self
.hasReportNumbersBySystem(system
):
1977 if number
in self
._reports
[system
]:
1978 self
._reports
[system
].remove(number
)
1979 self
.notifyModification()
1981 def removeReportNumberById(self
, id):
1983 rn
= self
.listReportNumbers()[int(id)]
1984 self
.removeReportNumber(rn
[0], rn
[1])
1988 def hasReportNumbersBySystem(self
, system
):
1989 return self
._reports
.has_key(system
)
1991 def getReportNumbersBySystem(self
, system
):
1992 if self
.hasReportNumbersBySystem(system
):
1993 return self
._reports
[system
]
1996 def getReportNumberKeys(self
):
1997 return self
._reports
.keys()
1999 def listReportNumbersOnKey(self
, key
):
2001 if key
in self
._reports
.keys():
2002 # compatibility with previous versions
2003 if type(self
._reports
[key
]) is str:
2004 self
._reports
[key
] = [ self
._reports
[key
] ]
2005 for number
in self
._reports
[key
]:
2006 reports
.append([key
, number
])
2009 def hasReportNumberOnSystem(self
, system
, number
):
2010 if self
.hasReportNumbersBySystem(system
):
2011 if number
in self
._reports
[system
]:
2015 def listReportNumbers(self
):
2017 keys
= self
._reports
.keys()
2020 # compatibility with previous versions
2021 if type(self
._reports
[key
]) is str:
2022 self
._reports
[key
] = [ self
._reports
[key
] ]
2023 for number
in self
._reports
[key
]:
2024 reports
.append([key
, number
])
2027 def clone(self
, owner
):
2028 newR
=ReportNumberHolder(owner
)
2029 for key
in self
._reports
.keys():
2030 for number
in self
._reports
[key
]:
2031 newR
.addReportNumber(key
, number
)
2034 def notifyModification(self
):
2036 if self
.getOwner() != None:
2037 self
.getOwner().notifyModification()
2040 class Conference(CommonObjectBase
, Locatable
):
2041 """This class represents the real world conferences themselves. Objects of
2042 this class will contain basic data about the confence and will provide
2043 access to other objects representing certain parts of the conferences
2044 (ex: contributions, sessions, ...).
2047 fossilizes(IConferenceFossil
, IConferenceMinimalFossil
, IConferenceEventInfoFossil
)
2049 def __init__(self
, creator
, id="", creationDate
= None, modificationDate
= None):
2050 """Class constructor. Initialise the class attributes to the default
2053 confData -- (Dict) Contains the data the conference object has to
2056 #IndexedObject.__init__(self)
2058 raise MaKaCError( _("A creator must be specified when creating a new Event"), _("Event"))
2059 self
.__creator
= creator
2062 self
.description
= ""
2065 ###################################
2066 # Fermi timezone awareness #
2067 ###################################
2068 self
.startDate
= nowutc()
2069 self
.endDate
= nowutc()
2071 ###################################
2072 # Fermi timezone awareness(end) #
2073 ###################################
2074 self
._screenStartDate
= None
2075 self
._screenEndDate
= None
2076 self
.contactInfo
=""
2077 self
.chairmanText
= ""
2079 self
._chairGen
=Counter()
2082 self
.__sessionGenerator
= Counter() # Provides session unique
2083 # identifiers for this conference
2084 self
.contributions
= {}
2085 self
.__contribGenerator
= Counter() # Provides contribution unique
2086 # identifiers for this conference
2087 self
.programDescription
= ""
2089 self
.__programGenerator
= Counter() # Provides track unique
2090 # identifiers for this conference
2091 self
.__ac
= AccessController(self
)
2093 self
.__materialGenerator
= Counter() # Provides material unique
2094 # identifiers for this conference
2100 self
.__schedule
=None
2103 self
._creationDS
= creationDate
2105 self
._creationDS
= nowutc() #creation timestamp
2106 if modificationDate
:
2107 self
._modificationDS
= modificationDate
2109 self
._modificationDS
= nowutc() #modification timestamp
2112 self
.__alarmCounter
= Counter()
2114 self
.abstractMgr
= review
.AbstractMgr(self
)
2116 self
._trackCoordinators
= TCIndex() #index for the track coordinators
2117 self
._supportInfo
= SupportInfo(self
, "Support")
2118 self
._contribTypes
= {}
2119 self
.___contribTypeGenerator
= Counter()
2120 self
._authorIdx
=AuthorIndex()
2121 self
._speakerIdx
=AuthorIndex()
2122 self
._primAuthIdx
=_PrimAuthIdx(self
)
2123 self
._sessionCoordinators
=SCIndex()
2124 self
._sessionCoordinatorRights
= []
2125 self
._submitterIdx
=SubmitterIndex()
2126 self
._boa
=BOAConfig(self
)
2127 self
._registrationForm
= registration
.RegistrationForm(self
)
2128 self
._evaluationCounter
= Counter()
2129 self
._evaluations
= [Evaluation(self
)]
2130 self
._registrants
= {} #key=registrantId; value=Registrant
2132 self
._registrantGenerator
= Counter()
2135 self
._closed
= False
2136 self
._visibility
= 999
2137 self
._pendingQueuesMgr
=pendingQueues
.ConfPendingQueuesMgr(self
)
2139 self
._participation
= Participation(self
)
2140 self
._logHandler
= LogHandler()
2141 self
._reportNumberHolder
=ReportNumberHolder(self
)
2142 self
._enableSessionSlots
= False
2143 self
._enableSessions
= False
2144 self
._autoSolveConflict
= True
2145 self
.__badgeTemplateManager
= BadgeTemplateManager(self
)
2146 self
.__posterTemplateManager
= PosterTemplateManager(self
)
2148 self
._confPaperReview
= ConferencePaperReview(self
)
2149 self
._confAbstractReview
= ConferenceAbstractReview(self
)
2152 self
._sortUrlTag
= ""
2154 self
._observers
= []
2158 return '<Conference({0}, {1}, {2})'.format(self
.getId(), self
.getTitle(), self
.getStartDate())
2161 def has_legacy_id(self
):
2162 """Returns True if the event has a broken legacy ID.
2164 These IDs are not compatible with new code since they are not
2165 numeric or have a leading zero, resulting in different events
2166 with the same numeric event id.
2168 return is_legacy_id(self
.id)
2171 def all_manager_emails(self
):
2172 """Returns the emails of all managers, including the creator"""
2173 emails
= {self
.getCreator().getEmail()} |
{u
.getEmail() for u
in self
.getManagerList()}
2174 return {e
for e
in emails
if e
}
2177 def _cmpByDate(self
, toCmp
):
2178 res
= cmp(self
.getStartDate(), toCmp
.getStartDate())
2182 return cmp(self
, toCmp
)
2184 def __cmp__(self
, toCmp
):
2185 if isinstance(toCmp
, Conference
):
2186 return cmp(self
.getId(), toCmp
.getId())
2188 return cmp(hash(self
), hash(toCmp
))
2190 def __eq__(self
, toCmp
):
2191 return self
is toCmp
2193 def __ne__(self
, toCmp
):
2194 return not(self
is toCmp
)
2196 def setUrlTag(self
, tag
):
2197 self
._sortUrlTag
= tag
2199 def getUrlTag(self
):
2201 return self
._sortUrlTag
2203 self
._sortUrlTag
= ""
2204 return self
._sortUrlTag
2206 def setComments(self
,comm
=""):
2207 self
._comments
= comm
.strip()
2209 def getComments(self
):
2213 except AttributeError,e
:
2215 return self
._comments
2217 def getConfPaperReview(self
):
2218 if not hasattr(self
, "_confPaperReview"):
2219 self
._confPaperReview
= ConferencePaperReview(self
)
2220 return self
._confPaperReview
2222 def getConfAbstractReview(self
):
2223 if not hasattr(self
, "_confAbstractReview"):
2224 self
._confAbstractReview
= ConferenceAbstractReview(self
)
2225 return self
._confAbstractReview
2227 def getOrgText( self
):
2229 return self
._orgText
2234 def setOrgText( self
, org
="" ):
2237 def cleanCache( self
):
2238 if not ContextManager
.get('clean%s'%self
.getUniqueId(), False):
2239 ScheduleToJson
.cleanConferenceCache(self
)
2240 ContextManager
.set('clean%s'%self
.getUniqueId(), True)
2242 def updateNonInheritingChildren(self
, elem
, delete
=False):
2243 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
2245 def getKeywords(self
):
2247 return self
._keywords
2252 def setKeywords(self
, keywords
):
2253 self
._keywords
= keywords
2255 # Room booking related ===================================================
2257 def getRoomBookingList(self
):
2258 """Returns list of bookings for this conference."""
2259 # In case anyone wonders why this method is still here: Various fossils expect/use it.
2260 if not self
.getId().isdigit():
2262 return Reservation
.find_all(event_id
=int(self
.getId()))
2264 # ========================================================================
2266 def getParticipation(self
):
2268 if self
._participation
:
2270 except AttributeError :
2271 self
._participation
= Participation(self
)
2272 return self
._participation
2274 def getType( self
):
2275 import MaKaC
.webinterface
.webFactoryRegistry
as webFactoryRegistry
2276 wr
= webFactoryRegistry
.WebFactoryRegistry()
2277 wf
= wr
.getFactory(self
)
2284 def getVerboseType( self
):
2285 # Like getType, but returns "Lecture" instead of "simple_type"
2286 type = self
.getType()
2287 if type == "simple_event":
2289 return type.capitalize()
2292 def getLogHandler(self
):
2294 if self
._logHandler
:
2296 except AttributeError :
2297 self
._logHandler
= LogHandler()
2298 return self
._logHandler
2301 def getEnableSessionSlots(self
):
2303 # if self._enableSessionSlots :
2305 #except AttributeError :
2306 # self._enableSessionSlots = True
2307 #if self.getType() == "conference":
2309 #return self._enableSessionSlots
2312 def getEnableSessions(self
):
2314 if self
._enableSessions
:
2316 except AttributeError :
2317 self
._enableSessions
= True
2318 if self
.getType() == "conference":
2320 return self
._enableSessions
2322 def enableSessionSlots(self
):
2323 self
._enableSessionSlots
= True
2325 def disableSessionSlots(self
):
2326 self
._enableSessionSlots
= False
2328 def enableSessions(self
):
2329 self
._enableSessions
= True
2331 def disableSessions(self
):
2332 self
._enableSessions
= False
2334 def setValues(self
, confData
):
2336 Sets SOME values of the current conference object from a dictionary
2337 containing the following key-value pairs:
2343 locationName-(str) => name of the location, if not specified
2344 it will be set to the conference location name.
2345 locationAddress-(str)
2346 roomName-(str) => name of the room, if not specified it will
2347 be set to the conference room name.
2348 Please, note that this method sets SOME values which means that if
2349 needed it can be completed to set more values. Also note that if
2350 the given dictionary doesn't contain all the values, the missing
2351 ones will be set to the default values.
2353 self
.setVisibility(confData
.get("visibility", "999"))
2354 self
.setTitle(confData
.get("title", _("NO TITLE ASSIGNED")))
2355 self
.setDescription(confData
.get("description", ""))
2356 self
.getSupportInfo().setEmail(confData
.get("supportEmail", ""))
2357 self
.setContactInfo(confData
.get("contactInfo", ""))
2358 if confData
.get("locationName", "").strip() == "":
2359 self
.setLocation(None)
2361 #if the location name is defined we must set a new location (or
2362 # modify the existing one) for the conference
2363 loc
= self
.getLocation()
2365 loc
= CustomLocation()
2366 self
.setLocation(loc
)
2367 loc
.setName(confData
["locationName"])
2368 loc
.setAddress(confData
.get("locationAddress", ""))
2369 #same as for the location
2370 if confData
.get("roomName", "").strip() == "":
2373 room
= self
.getRoom()
2377 room
.setName(confData
["roomName"])
2378 self
.notifyModification()
2380 def getVisibility ( self
):
2382 return int(self
._visibility
)
2384 self
._visibility
= 999
2387 def getFullVisibility( self
):
2388 return max(0,min(self
.getVisibility(), self
.getOwnerList()[0].getVisibility()))
2390 def setVisibility( self
, visibility
=999 ):
2391 self
._visibility
= int(visibility
)
2392 catIdx
= indexes
.IndexesHolder().getIndex('category')
2393 catIdx
.reindexConf(self
)
2394 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
2395 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
2396 catDateIdx
.reindexConf(self
)
2397 catDateAllIdx
.reindexConf(self
)
2399 def isClosed( self
):
2403 self
._closed
= False
2406 def setClosed( self
, closed
=True ):
2407 self
._closed
= closed
2409 def indexConf( self
):
2410 # called when event dates change
2411 # see also Category.indexConf()
2413 calIdx
= indexes
.IndexesHolder().getIndex('calendar')
2414 calIdx
.indexConf(self
)
2415 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
2416 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
2417 catDateIdx
.indexConf(self
)
2418 catDateAllIdx
.indexConf(self
)
2419 nameIdx
= indexes
.IndexesHolder().getIndex('conferenceTitle')
2422 Catalog
.getIdx('categ_conf_sd').index_obj(self
)
2424 def unindexConf( self
):
2425 calIdx
= indexes
.IndexesHolder().getIndex('calendar')
2426 calIdx
.unindexConf(self
)
2427 catDateIdx
= indexes
.IndexesHolder().getIndex('categoryDate')
2428 catDateAllIdx
= indexes
.IndexesHolder().getIndex('categoryDateAll')
2429 catDateIdx
.unindexConf(self
)
2430 catDateAllIdx
.unindexConf(self
)
2431 nameIdx
= indexes
.IndexesHolder().getIndex('conferenceTitle')
2432 nameIdx
.unindex(self
)
2434 Catalog
.getIdx('categ_conf_sd').unindex_obj(self
)
2436 def __generateNewContribTypeId( self
):
2437 """Returns a new unique identifier for the current conference sessions
2440 return str(self
.___contribTypeGenerator
.newCount())
2442 self
.___contribTypeGenerator
= Counter()
2443 return str(self
.___contribTypeGenerator
.newCount())
2445 def addContribType(self
, ct
):
2447 if self
._contribTypes
:
2450 self
._contribTypes
= {}
2451 if ct
in self
._contribTypes
.values():
2455 id = self
.__generateNewContribTypeId
()
2457 self
._contribTypes
[id] = ct
2458 self
.notifyModification()
2460 def newContribType(self
, name
, description
):
2461 ct
= ContributionType(name
, description
, self
)
2462 self
.addContribType(ct
)
2465 def getContribTypeList(self
):
2467 return self
._contribTypes
.values()
2469 self
._contribTypes
= {}
2470 self
.notifyModification()
2471 return self
._contribTypes
.values()
2473 def getContribTypeById(self
, id):
2475 if self
._contribTypes
:
2478 self
._contribTypes
= {}
2479 self
.notifyModification()
2480 if id in self
._contribTypes
.keys():
2481 return self
._contribTypes
[id]
2484 def removeContribType(self
, ct
):
2486 if self
._contribTypes
:
2489 self
._contribTypes
= {}
2490 if not ct
in self
._contribTypes
.values():
2492 del self
._contribTypes
[ct
.getId()]
2493 for cont
in self
.getContributionList():
2494 if cont
.getType() == ct
:
2497 self
.notifyModification()
2499 def recoverContribType(self
, ct
):
2500 ct
.setConference(self
)
2501 self
.addContribType(ct
)
2504 def _getRepository( self
):
2505 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
2507 fr
= dbRoot
["local_repositories"]["main"]
2509 fr
= fileRepository
.MaterialLocalRepository()
2510 dbRoot
["local_repositories"] = OOBTree()
2511 dbRoot
["local_repositories"]["main"] = fr
2514 def removeResource( self
, res
):
2518 cid
= self
.getUrlTag()
2521 return Config
.getInstance().getShortEventURL() + cid
2523 def setLogo( self
, logoFile
):
2524 logoFile
.setOwner( self
)
2525 logoFile
.setId( "logo" )
2526 logoFile
.archive( self
._getRepository
() )
2527 if self
._logo
!= None:
2529 self
._logo
= logoFile
2530 self
.notifyModification()
2532 def getLogo( self
):
2535 def getLogoURL( self
):
2537 if self
._logo
== None:
2539 return self
._logo
.getURL()
2540 except AttributeError:
2544 def removeLogo(self
):
2545 if self
._logo
is None:
2549 self
.notifyModification()
2551 def recoverLogo(self
, logo
):
2553 if self
._logo
!= None:
2557 self
.notifyModification()
2559 def getSession(self
):
2562 def getContribution(self
):
2565 def getSubContribution(self
):
2568 def getAbstractMgr(self
):
2569 return self
.abstractMgr
2571 def notifyModification( self
, date
= None, raiseEvent
= True):
2572 """Method called to notify the current conference has been modified.
2574 self
.setModificationDate()
2577 signals
.event
.data_changed
.send(self
, attr
=None, old
=None, new
=None)
2582 def getModificationDate( self
):
2583 """Returns the date in which the conference was last modified"""
2584 return self
._modificationDS
2586 def getAdjustedModificationDate( self
, tz
):
2587 """Returns the date in which the conference was last modified"""
2588 return self
._modificationDS
.astimezone(timezone(tz
))
2590 def getCreationDate( self
):
2591 """Returns the date in which the conference was created"""
2592 return self
._creationDS
2594 def getAdjustedCreationDate( self
, tz
):
2595 """Returns the date in which the conference was created"""
2596 return self
._creationDS
.astimezone(timezone(tz
))
2598 def getCreator( self
):
2599 return self
.__creator
2601 def setCreator( self
, creator
):
2603 self
.__creator
.unlinkTo(self
, "creator")
2604 creator
.linkTo(self
, "creator")
2605 self
.__creator
= creator
2607 def linkCreator(self
):
2608 self
.__creator
.linkTo(self
, "creator")
2611 """returns (string) the unique identifier of the conference"""
2614 def getUniqueId( self
):
2615 """returns (string) the unique identiffier of the item"""
2616 """used mainly in the web session access key table"""
2617 return "a%s" % self
.id
2619 def setId(self
, newId
):
2620 """changes the current unique identifier of the conference to the
2621 one which is specified"""
2622 self
.id = str(newId
)
2624 def getLocator( self
):
2625 """Gives back (Locator) a globaly unique identification encapsulated in
2626 a Locator object for the conference instance """
2628 d
["confId"] = self
.getId()
2631 def getOwner( self
):
2632 if self
.getOwnerList() == []:
2634 return self
.getOwnerList()[0]
2636 def getOwnerList( self
):
2637 return self
.__owners
2639 def getOwnerPath( self
):
2641 owner
= self
.getOwnerList()[0]
2642 while owner
!= None and owner
.getId() != "0":
2644 owner
= owner
.getOwner()
2647 def getOwnerById( self
, key
):
2648 """Returns one specific category which contains the conference.
2650 - key: The "id" of the category.
2652 for owner
in self
.__owners
:
2653 if key
== owner
.getId():
2657 def addOwner( self
, newOwner
):
2658 if newOwner
== None:
2660 self
.__owners
.append( newOwner
)
2661 self
.notifyModification()
2663 def removeOwner( self
, owner
, notify
=True ):
2664 if not (owner
in self
.__owners
):
2666 self
.__owners
.remove( owner
)
2667 owner
.removeConference( self
)
2669 self
.notifyModification()
2671 def getCategoriesPath(self
):
2672 return [self
.getOwnerList()[0].getCategoryPath()]
2674 def notifyContributions(self
):
2676 for c
in self
.getContributionList():
2677 # take care of subcontributions
2678 for sc
in c
.getSubContributionList():
2679 signals
.event
.subcontribution_deleted
.send(sc
, parent
=c
)
2681 signals
.event
.contribution_deleted
.send(c
, parent
=self
)
2683 def delete(self
, user
=None):
2684 """deletes the conference from the system.
2686 signals
.event
.deleted
.send(self
, user
=user
)
2688 self
.notifyContributions()
2690 # will have to remove it from all the owners (categories) and the
2691 # conference registry
2692 ConferenceHolder().remove(self
)
2693 for owner
in self
.__owners
:
2694 owner
.removeConference(self
, notify
=False)
2696 self
.removeAllEvaluations()
2698 for alarm
in self
.getAlarmList():
2699 if not alarm
.getEndedOn():
2700 self
.removeAlarm(alarm
)
2702 # For each conference we have a list of managers. If we delete the conference but we don't delete
2703 # the link in every manager to the conference then, when the manager goes to his "My profile" he
2704 # will see a link to a conference that doesn't exist. Therefore, we need to delete that link as well
2705 for manager
in self
.getManagerList():
2706 if isinstance(manager
, AvatarUserWrapper
):
2707 manager
.unlinkTo(self
, "manager")
2709 creator
= self
.getCreator()
2710 creator
.unlinkTo(self
, "creator")
2712 # Remove all links in redis
2713 if redis_write_client
:
2714 avatar_links
.delete_event(self
)
2716 # Remote short URL mappings
2717 ShortURLMapper().remove(self
)
2719 TrashCanManager().add(self
)
2721 def getConference( self
):
2724 def getObservers(self
):
2725 if not hasattr(self
, "_observers"):
2726 self
._observers
= []
2727 return self
._observers
2729 def setDates( self
, sDate
, eDate
=None, check
=1, moveEntries
=0):
2731 Set the start/end date for a conference
2734 oldStartDate
= self
.getStartDate()
2735 oldEndDate
= self
.getEndDate()
2737 # do some checks first
2740 raise FormValuesError(_("Start date cannot be after the end date"), _("Event"))
2742 elif sDate
== oldStartDate
and eDate
== oldEndDate
:
2743 # if there's nothing to do (yet another obvious case)
2746 # if we reached this point, it means either the start or
2747 # the end date (or both) changed
2748 # If only the end date was changed, moveEntries = 0
2749 if sDate
== oldStartDate
:
2752 # Pre-check for moveEntries
2753 if moveEntries
== 1:
2754 # in case the entries are to be simply shifted
2755 # we should make sure the interval is big enough
2756 # just store the old values for later
2758 oldInterval
= oldEndDate
- oldStartDate
2759 newInterval
= eDate
- sDate
2761 entries
= self
.getSchedule().getEntries()
2762 if oldInterval
> newInterval
and entries
:
2763 eventInterval
= entries
[-1].getEndDate() - entries
[0].getStartDate()
2764 diff
= entries
[0].getStartDate() - oldStartDate
2765 if sDate
+ diff
+ eventInterval
> eDate
:
2767 _("The start/end dates were not changed since the selected "
2768 "timespan is not large enough to accomodate the contained "
2769 "timetable entries and spacings."),
2770 explanation
=_("You should try using a larger timespan."))
2772 # so, we really need to try changing something
2777 self
.setStartDate(sDate
, check
=0, moveEntries
= moveEntries
, index
=False, notifyObservers
= False)
2778 self
.setEndDate(eDate
, check
=0, index
=False, notifyObservers
= False)
2781 self
._checkInnerSchedule
()
2783 # reindex the conference
2787 old_data
= (oldStartDate
, oldEndDate
)
2788 new_data
= (self
.getStartDate(), self
.getEndDate())
2789 if old_data
!= new_data
:
2790 signals
.event
.data_changed
.send(self
, attr
='dates', old
=old_data
, new
=new_data
)
2792 def _checkInnerSchedule( self
):
2793 self
.getSchedule().checkSanity()
2795 def setStartDate(self
, sDate
, check
= 1, moveEntries
= 0, index
= True, notifyObservers
= True):
2796 """ Changes the current conference starting date/time to the one specified by the parameters.
2798 if not sDate
.tzname():
2799 raise MaKaCError("date should be timezone aware")
2800 if sDate
== self
.getStartDate():
2802 ###################################
2803 # Fermi timezone awareness #
2804 ###################################
2805 if not indexes
.BTREE_MIN_UTC_DATE
<= sDate
<= indexes
.BTREE_MAX_UTC_DATE
:
2806 raise FormValuesError(_("The start date must be between {} and {}.").format(
2807 format_datetime(indexes
.BTREE_MIN_UTC_DATE
),
2808 format_datetime(indexes
.BTREE_MAX_UTC_DATE
)))
2809 ###################################
2810 # Fermi timezone awareness #
2811 ###################################
2813 self
.verifyStartDate(sDate
)
2814 oldSdate
= self
.getStartDate()
2815 diff
= sDate
- oldSdate
2819 self
.startDate
= sDate
2820 if moveEntries
and diff
is not None:
2821 # If the start date changed, we move entries inside the timetable
2822 self
.getSchedule()._startDate
=None
2823 self
.getSchedule()._endDate
=None
2824 #if oldSdate.date() != sDate.date():
2825 # entries = self.getSchedule().getEntries()[:]
2827 # entries = self.getSchedule().getEntriesOnDay(sDate.astimezone(timezone(self.getTimezone())))[:]
2828 entries
= self
.getSchedule().getEntries()[:]
2829 self
.getSchedule().moveEntriesBelow(diff
, entries
, check
=check
)
2830 #datetime object is non-mutable so we must "force" the modification
2831 # otherwise ZODB won't be able to notice the change
2832 self
.notifyModification()
2836 # update the time for the alarms to be sent
2837 self
._updateAlarms
()
2839 # Update redis link timestamp
2840 if redis_write_client
:
2841 avatar_links
.update_event_time(self
)
2843 #if everything went well, we notify the observers that the start date has changed
2845 if oldSdate
!= sDate
:
2846 signals
.event
.data_changed
.send(self
, attr
='start_date', old
=oldSdate
, new
=sDate
)
2848 def _updateAlarms(self
):
2850 # are there any alarms? if so, update the relative ones
2851 for alarm
in self
.getAlarmList():
2852 tbef
= alarm
.getTimeBefore()
2854 # only relative alarms
2855 c
.moveTask(alarm
, self
.getStartDate() - tbef
)
2857 def verifyStartDate(self
, sdate
, check
=1):
2858 if sdate
>self
.getEndDate():
2859 raise MaKaCError( _("End date cannot be before the Start date"), _("Event"))
2861 def setStartTime(self
, hours
=0, minutes
=0, notifyObservers
= True):
2862 """ Changes the current conference starting time (not date) to the one specified by the parameters.
2865 sdate
= self
.getStartDate()
2866 self
.startDate
= datetime( sdate
.year
, sdate
.month
, sdate
.day
,
2867 int(hours
), int(minutes
) )
2868 self
.verifyStartDate(self
.startDate
)
2869 self
.notifyModification()
2871 def getStartDate(self
):
2872 """returns (datetime) the starting date of the conference"""
2873 return self
.startDate
2875 def getUnixStartDate(self
):
2876 return datetimeToUnixTimeInt(self
.startDate
)
2878 ###################################
2879 # Fermi timezone awareness #
2880 ###################################
2882 def getAdjustedStartDate(self
,tz
=None):
2884 tz
= self
.getTimezone()
2885 if tz
not in all_timezones
:
2887 return self
.getStartDate().astimezone(timezone(tz
))
2889 ###################################
2890 # Fermi timezone awareness(end) #
2891 ###################################
2893 def setScreenStartDate(self
, date
):
2894 if date
== self
.getStartDate():
2896 self
._screenStartDate
= date
2897 self
.notifyModification()
2899 def getScreenStartDate(self
):
2901 date
= self
._screenStartDate
2903 date
= self
._screenStartDate
= None
2907 return self
.getStartDate()
2909 def getAdjustedScreenStartDate(self
, tz
=None):
2911 tz
= self
.getTimezone()
2912 return self
.getScreenStartDate().astimezone(timezone(tz
))
2914 def calculateDayStartTime(self
, day
):
2915 """returns (date) the start date of the conference on a given day
2916 day is a tz aware datetime"""
2917 if self
.getStartDate().astimezone(day
.tzinfo
).date() == day
.date():
2918 return self
.getStartDate().astimezone(day
.tzinfo
)
2919 return self
.getSchedule().calculateDayStartDate(day
)
2921 def verifyEndDate(self
, edate
):
2922 if edate
<self
.getStartDate():
2923 raise TimingError( _("End date cannot be before the start date"), _("Event"))
2924 if self
.getSchedule().hasEntriesAfter(edate
):
2925 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"))
2927 def setEndDate(self
, eDate
, check
= 1, index
= True, notifyObservers
= True):
2928 """ Changes the current conference end date/time to the one specified by the parameters.
2930 if not eDate
.tzname():
2931 raise MaKaCError("date should be timezone aware")
2932 if eDate
== self
.getEndDate():
2934 if not indexes
.BTREE_MIN_UTC_DATE
<= eDate
<= indexes
.BTREE_MAX_UTC_DATE
:
2935 raise FormValuesError(_("The end date must be between {} and {}.").format(
2936 format_datetime(indexes
.BTREE_MIN_UTC_DATE
),
2937 format_datetime(indexes
.BTREE_MAX_UTC_DATE
)))
2939 self
.verifyEndDate(eDate
)
2943 oldEdate
= self
.endDate
2944 self
.endDate
= eDate
2945 #datetime object is non-mutable so we must "force" the modification
2946 # otherwise ZODB won't be able to notice the change
2947 self
.notifyModification()
2951 #if everything went well, we notify the observers that the start date has changed
2953 if oldEdate
!= eDate
:
2954 signals
.event
.data_changed
.send(self
, attr
='end_date', old
=oldEdate
, new
=eDate
)
2956 def setEndTime(self
, hours
= 0, minutes
= 0, notifyObservers
= True):
2957 """ Changes the current conference end time (not date) to the one specified by the parameters.
2959 edate
= self
.getEndDate()
2960 self
.endDate
= datetime( edate
.year
, edate
.month
, edate
.day
, int(hours
), int(minutes
) )
2961 self
.verifyEndDate(self
.endDate
)
2962 self
.notifyModification()
2965 def getEndDate(self
):
2966 """returns (datetime) the ending date of the conference"""
2969 ##################################
2970 # Fermi timezone awareness #
2971 ##################################
2973 def getAdjustedEndDate(self
,tz
=None):
2975 tz
= self
.getTimezone()
2976 if tz
not in all_timezones
:
2978 return self
.getEndDate().astimezone(timezone(tz
))
2980 ##################################
2981 # Fermi timezone awareness(end) #
2982 ##################################
2984 def setScreenEndDate(self
, date
):
2985 if date
== self
.getEndDate():
2987 self
._screenEndDate
= date
2988 self
.notifyModification()
2990 def getScreenEndDate(self
):
2992 date
= self
._screenEndDate
2994 date
= self
._screenEndDate
= None
2998 return self
.getEndDate()
3000 def getAdjustedScreenEndDate(self
, tz
=None):
3002 tz
= self
.getTimezone()
3003 return self
.getScreenEndDate().astimezone(timezone(tz
))
3005 def isEndDateAutoCal( self
):
3006 """Says whether the end date has been explicitely set for the session
3007 or it must be calculated automatically
3009 return self
._endDateAutoCal
3011 ####################################
3012 # Fermi timezone awareness #
3013 ####################################
3014 def setTimezone(self
, tz
):
3016 oldTimezone
= self
.timezone
3017 except AttributeError:
3021 def getTimezone(self
):
3023 return self
.timezone
3027 def moveToTimezone(self
, tz
):
3028 if self
.getTimezone() == tz
:
3030 sd
=self
.getAdjustedStartDate()
3031 ed
=self
.getAdjustedEndDate()
3032 self
.setTimezone(tz
)
3034 sDate
= timezone(tz
).localize(datetime(sd
.year
, \
3039 eDate
= timezone(tz
).localize(datetime(ed
.year
, \
3044 except ValueError,e
:
3045 raise MaKaCError("Error moving the timezone: %s"%e)
3046 self
.setDates( sDate
.astimezone(timezone('UTC')), \
3047 eDate
.astimezone(timezone('UTC')),
3052 ####################################
3053 # Fermi timezone awareness(end) #
3054 ####################################
3057 """returns (String) the title of the conference"""
3060 def setTitle(self
, title
):
3061 """changes the current title of the conference to the one specified"""
3062 oldTitle
= self
.title
3065 self
.notifyModification()
3067 nameIdx
= indexes
.IndexesHolder().getIndex('conferenceTitle')
3068 nameIdx
.unindex(self
)
3071 if oldTitle
!= title
:
3072 signals
.event
.data_changed
.send(self
, attr
='title', old
=oldTitle
, new
=title
)
3074 def getDescription(self
):
3075 """returns (String) the description of the conference"""
3076 return self
.description
3078 def setDescription(self
, desc
):
3079 """changes the current description of the conference"""
3080 oldDescription
= self
.description
3081 self
.description
= desc
3082 if oldDescription
!= desc
:
3083 signals
.event
.data_changed
.send(self
, attr
='description', old
=oldDescription
, new
=desc
)
3084 self
.notifyModification()
3086 def getSupportInfo(self
):
3087 if not hasattr(self
, "_supportInfo"):
3088 self
._supportInfo
= SupportInfo(self
, "Support")
3089 return self
._supportInfo
3091 def setSupportInfo(self
, supportInfo
):
3092 self
._supportInfo
= supportInfo
3094 def getChairmanText( self
):
3096 if self
.chairmanText
:
3098 except AttributeError, e
:
3099 self
.chairmanText
= ""
3100 return self
.chairmanText
3102 def setChairmanText( self
, newText
):
3103 self
.chairmanText
= newText
.strip()
3105 def appendChairmanText( self
, newText
):
3106 self
.setChairmanText( "%s, %s"%(self
.getChairmanText(), newText
.strip()) )
3107 self
._chairGen
=Counter()
3110 def _resetChairs(self
):
3114 except AttributeError:
3116 for oc
in self
.chairmans
:
3117 newChair
=ConferenceChair()
3118 newChair
.setDataFromAvatar(oc
)
3119 self
._addChair
(newChair
)
3121 def getChairList(self
):
3122 """Method returning a list of the conference chairmans (Avatars)
3127 def _addChair(self
,newChair
):
3128 for chair
in self
._chairs
:
3129 if newChair
.getEmail() != "" and newChair
.getEmail() == chair
.getEmail():
3134 except AttributeError:
3135 self
._chairGen
=Counter()
3136 id = newChair
.getId()
3138 id=int(self
._chairGen
.newCount())
3139 if isinstance(newChair
,ConferenceChair
):
3140 newChair
.includeInConference(self
,id)
3141 self
._chairs
.append(newChair
)
3142 if isinstance(newChair
, AvatarUserWrapper
):
3143 newChair
.linkTo(self
, "chair")
3144 self
.notifyModification()
3146 def addChair(self
,newChair
):
3147 """includes the specified user in the list of conference
3150 self
._addChair
(newChair
)
3152 def removeChair(self
,chair
):
3153 """removes the specified user from the list of conference
3156 if chair
not in self
._chairs
:
3158 self
._chairs
.remove(chair
)
3159 if isinstance(chair
, AvatarUserWrapper
):
3160 chair
.unlinkTo(self
, "chair")
3162 self
.notifyModification()
3164 def recoverChair(self
, ch
):
3168 def getChairById(self
,id):
3170 for chair
in self
._chairs
:
3171 if chair
.getId()==id:
3175 def getAllSessionsConvenerList(self
) :
3177 for session
in self
.getSessionList() :
3178 for convener
in session
.getConvenerList() :
3179 key
= convener
.getEmail()+" "+convener
.getFirstName().lower()+" "+convener
.getFamilyName().lower()
3180 dictionary
.setdefault(key
, set()).add(convener
)
3181 for slot
in session
.getSlotList():
3182 for convener
in slot
.getConvenerList() :
3183 key
= convener
.getEmail()+" "+convener
.getFirstName().lower()+" "+convener
.getFamilyName().lower()
3184 dictionary
.setdefault(key
, set()).add(convener
)
3188 def getContactInfo(self
):
3189 return self
.contactInfo
3191 def setContactInfo(self
, contactInfo
):
3192 self
.contactInfo
= contactInfo
3193 self
.notifyModification()
3195 def getLocationParent( self
):
3197 Returns the object from which the room/location
3198 information should be inherited.
3199 For Conferences, it's None, since they can't inherit
3204 def getLocation( self
):
3205 return self
.getOwnLocation()
3207 def getAddress( self
):
3208 if self
.getOwnLocation():
3209 return self
.getOwnLocation().getAddress()
3213 def getRoom( self
):
3214 return self
.getOwnRoom()
3216 def getLocationList(self
):
3217 """Method returning a list of "location" objects which contain the
3218 information about the different places the conference is gonna
3223 def getFavoriteRooms(self
):
3225 roomList
.extend(self
.getRoomList())
3226 #roomList.extend(map(lambda x: x._getName(), self.getBookedRooms()))
3230 def addLocation(self
, newPlace
):
3231 self
.places
.append( newPlace
)
3232 self
.notifyModification()
3234 def setAccessKey(self
, accessKey
=""):
3235 """sets the access key of the conference"""
3236 self
._accessKey
= accessKey
3237 self
.notifyModification()
3239 def getAccessKey(self
):
3241 return self
._accessKey
3242 except AttributeError:
3243 self
._accessKey
= ""
3244 return self
._accessKey
3246 def setModifKey(self
, modifKey
=""):
3247 """sets the modification key of the conference"""
3248 self
._modifKey
= modifKey
3249 self
.notifyModification()
3251 def getModifKey(self
):
3253 return self
._modifKey
3254 except AttributeError:
3256 return self
._modifKey
3258 def __generateNewSessionId( self
):
3259 """Returns a new unique identifier for the current conference sessions
3261 return str(self
.__sessionGenerator
.newCount())
3263 def addSession(self
,newSession
, check
= 2, id = None):
3264 """Adds a new session object to the conference taking care of assigning
3265 a new unique id to it
3269 1: check and raise error in case of problem
3270 2: check and adapt the owner dates"""
3272 if self
.hasSession(newSession
):
3274 if self
.getSchedule().isOutside(newSession
):
3276 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")
3278 if self
.getSchedule().getStartDate() > newSession
.getStartDate():
3279 self
.setStartDate(newSession
.getStartDate())
3280 if self
.getSchedule().getEndDate() < newSession
.getEndDate():
3281 self
.setEndDate(newSession
.getEndDate())
3284 # Keep ID counter up to date
3285 self
.__sessionGenerator
.newCount()
3287 sessionId
=self
.__generateNewSessionId
()
3288 self
.sessions
[sessionId
]=newSession
3289 newSession
.includeInConference(self
,sessionId
)
3290 #keep the session coordinator index updated
3291 for sc
in newSession
.getCoordinatorList():
3292 self
.addSessionCoordinator(newSession
,sc
)
3293 self
.notifyModification()
3295 def hasSession(self
,session
):
3296 if session
!= None and session
.getConference()==self
and \
3297 self
.sessions
.has_key(session
.getId()):
3301 def removeSession(self
,session
, deleteContributions
=False):
3302 if self
.hasSession(session
):
3303 for sc
in session
.getCoordinatorList():
3304 self
.removeSessionCoordinator(session
,sc
)
3306 if deleteContributions
:
3307 for contrib
in session
.getContributionList():
3310 del self
.sessions
[session
.getId()]
3313 self
.notifyModification()
3315 def recoverSession(self
, session
, check
, isCancelled
):
3316 self
.addSession(session
, check
, session
.getId())
3317 session
.recover(isCancelled
)
3319 def getSessionById( self
, sessionId
):
3320 """Returns the session from the conference list corresponding to the
3321 unique session id specified
3323 return self
.sessions
.get(sessionId
,None)
3325 def getRoomList(self
):
3327 for session
in self
.sessions
.values():
3328 if session
.getRoom()!=None:
3329 roomname
= session
.getRoom().getName()
3330 if roomname
not in roomList
:
3331 roomList
.append(roomname
)
3334 def getSessionList( self
):
3335 """Retruns a list of the conference session objects
3337 return self
.sessions
.values()
3339 def getSessionListSorted( self
):
3340 """Retruns a sorted list of the conference sessions
3343 for entry
in self
.getSchedule().getEntries():
3344 if isinstance(entry
,LinkedTimeSchEntry
) and \
3345 isinstance(entry
.getOwner(),SessionSlot
):
3346 session
=entry
.getOwner().getSession()
3347 if session
not in res
:
3351 def getSessionSlotList(self
):
3352 return [slot
for session
in self
.sessions
.values() for slot
in session
.getSlotList()]
3354 def getNumberOfSessions(self
):
3355 return len(self
.sessions
)
3357 def _generateNewContributionId(self
):
3358 """Returns a new unique identifier for the current conference
3361 return str(self
.__contribGenerator
.newCount())
3363 def genNewAbstractId(self
):
3364 return str(self
.__contribGenerator
.newCount())
3366 def syncContribCounter(self
):
3367 self
.__contribGenerator
.sync(self
.getAbstractMgr()._getOldAbstractCounter
())
3368 return self
.__contribGenerator
._getCount
()
3370 def addContribution(self
,newContrib
,id=""):
3371 """Adds a new contribution object to the conference taking care of
3372 assigning a new unique id to it
3374 if self
.hasContribution(newContrib
):
3376 if isinstance(newContrib
.getCurrentStatus(),ContribStatusWithdrawn
):
3377 raise MaKaCError( _("Cannot add a contribution which has been withdrawn"), _("Event"))
3378 if id is None or id=="":
3379 contribId
=self
._generateNewContributionId
()
3380 while self
.contributions
.has_key(contribId
):
3381 contribId
=self
._generateNewContributionId
()
3384 if self
.contributions
.has_key(contribId
):
3385 raise MaKaCError( _("Cannot add this contribution id:(%s) as it has already been used")%contribId
, _("Event"))
3386 newContrib
.includeInConference(self
,contribId
)
3387 self
.contributions
[contribId
]=newContrib
3388 for auth
in newContrib
.getAuthorList():
3389 self
.indexAuthor(auth
)
3390 for spk
in newContrib
.getSpeakerList():
3391 self
.indexSpeaker(spk
)
3392 for sub
in newContrib
.getSubmitterList():
3393 self
.addContribSubmitter(newContrib
,sub
)
3395 signals
.event
.contribution_created
.send(newContrib
, parent
=self
)
3396 self
.notifyModification()
3398 def hasContribution(self
,contrib
):
3399 return contrib
.getConference()==self
and \
3400 self
.contributions
.has_key(contrib
.getId())
3402 def removeContribution( self
, contrib
, callDelete
=True ):
3403 if not self
.contributions
.has_key( contrib
.getId() ):
3405 for sub
in contrib
.getSubmitterList()[:]:
3406 self
.removeContribSubmitter(contrib
,sub
)
3407 for auth
in contrib
.getPrimaryAuthorList()[:]:
3408 contrib
.removePrimaryAuthor(auth
)
3409 for auth
in contrib
.getCoAuthorList()[:]:
3410 contrib
.removeCoAuthor(auth
)
3411 for spk
in contrib
.getSpeakerList()[:]:
3412 contrib
.removeSpeaker(spk
)
3413 del self
.contributions
[ contrib
.getId() ]
3418 self
.notifyModification()
3420 def recoverContribution(self
, contrib
):
3421 self
.addContribution(contrib
, contrib
.getId())
3424 # Note: this kind of factories should never be used as they only allow to
3425 # create a single type of contributions
3426 def newContribution( self
, id=None ):
3427 """Creates and returns a new contribution object already added to the
3428 conference list (all its data is set to the default)
3431 self
.addContribution( c
, id )
3434 def getOwnContributionById( self
, id ):
3435 """Returns the contribution from the conference list corresponding to
3436 the unique contribution id specified
3438 if self
.contributions
.has_key( id ):
3439 return self
.contributions
[ id ]
3442 def getContributionById( self
, id ):
3443 """Returns the contribution corresponding to the id specified
3445 return self
.contributions
.get(str(id).strip(),None)
3447 def getContributionList(self
):
3448 """Returns a list of the conference contribution objects
3450 return self
.contributions
.values()
3452 def iterContributions(self
):
3453 return self
.contributions
.itervalues()
3455 def getContributionListWithoutSessions(self
):
3456 """Returns a list of the conference contribution objects which do not have a session
3458 return [c
for c
in self
.contributions
.values() if not c
.getSession()]
3461 def getContributionListSorted(self
, includeWithdrawn
=True, key
="id"):
3462 """Returns a list of the conference contribution objects, sorted by key provided
3464 contributions
= self
.contributions
.values()
3465 if not includeWithdrawn
:
3466 contributions
= filter(lambda c
: not isinstance(c
.getCurrentStatus(), ContribStatusWithdrawn
), contributions
)
3467 contributions
.sort(key
= lambda c
: getattr(c
, key
))
3468 return contributions
3470 def getNumberOfContributions(self
, only_scheduled
=False):
3472 return len(filter(lambda c
: c
.isScheduled(), self
.contributions
.itervalues()))
3474 return len(self
.contributions
)
3476 def hasSomethingOnWeekend(self
, day
):
3477 """Checks if the event has a session or contribution on the weekend indicated by `day`.
3479 `day` must be either a saturday or a sunday"""
3480 if day
.weekday() == 5:
3481 weekend
= (day
, day
+ timedelta(days
=1))
3482 elif day
.weekday() == 6:
3483 weekend
= (day
, day
- timedelta(days
=1))
3485 raise ValueError('day must be on a weekend')
3486 return (any(c
.startDate
.date() in weekend
and not isinstance(c
.getCurrentStatus(), ContribStatusWithdrawn
)
3487 for c
in self
.contributions
.itervalues() if c
.startDate
is not None) or
3488 any(s
.startDate
.date() in weekend
for s
in self
.sessions
.itervalues() if s
.startDate
is not None))
3490 def getProgramDescription(self
):
3492 return self
.programDescription
3494 self
.programDescription
= ""
3495 return self
.programDescription
3497 def setProgramDescription(self
, txt
):
3498 self
.programDescription
= txt
3500 def _generateNewTrackId( self
):
3503 return str(self
.__programGenerator
.newCount())
3505 def addTrack( self
, newTrack
):
3508 #XXX: The conference program shoul be isolated in a separated object
3509 if newTrack
in self
.program
:
3512 trackId
= newTrack
.getId()
3513 if trackId
== "not assigned":
3514 trackId
= self
._generateNewTrackId
()
3515 self
.program
.append( newTrack
)
3516 newTrack
.setConference( self
)
3517 newTrack
.setId( trackId
)
3518 self
.notifyModification()
3520 def removeTrack( self
, track
):
3521 if track
in self
.program
:
3523 if track
in self
.program
:
3524 self
.program
.remove( track
)
3525 self
.notifyModification()
3527 def recoverTrack(self
, track
):
3528 self
.addTrack(track
)
3531 def newTrack( self
):
3538 def getTrackById( self
, id ):
3541 for track
in self
.program
:
3542 if track
.getId() == id.strip():
3546 def getTrackList( self
):
3551 def isLastTrack(self
,track
):
3554 return self
.getTrackPos(track
)==(len(self
.program
)-1)
3556 def isFirstTrack(self
,track
):
3559 return self
.getTrackPos(track
)==0
3561 def getTrackPos(self
,track
):
3564 return self
.program
.index(track
)
3566 def moveTrack(self
,track
,newPos
):
3569 self
.program
.remove(track
)
3570 self
.program
.insert(newPos
,track
)
3571 self
.notifyModification()
3573 def moveUpTrack(self
,track
):
3576 if self
.isFirstTrack(track
):
3578 newPos
=self
.getTrackPos(track
)-1
3579 self
.moveTrack(track
,newPos
)
3581 def moveDownTrack(self
,track
):
3584 if self
.isLastTrack(track
):
3586 newPos
= self
.getTrackPos(track
) + 1
3587 self
.moveTrack(track
, newPos
)
3589 def _cmpTracks(self
, t1
, t2
):
3590 o1
= self
.program
.index(t1
)
3591 o2
= self
.program
.index(t2
)
3594 def sortTrackList(self
, l
):
3595 """Sorts out a list of tracks according to the current programme order.
3605 res
.sort(self
._cmpTracks
)
3608 def requireDomain(self
, dom
):
3609 self
.__ac
.requireDomain(dom
)
3610 signals
.event
.domain_access_granted
.send(self
, domain
=dom
)
3612 def freeDomain(self
, dom
):
3613 self
.__ac
.freeDomain(dom
)
3614 signals
.event
.domain_access_revoked
.send(self
, domain
=dom
)
3616 def getDomainList(self
):
3617 return self
.__ac
.getRequiredDomainList()
3619 def isProtected(self
):
3620 """Tells whether a conference is protected for accessing or not
3622 return self
.__ac
.isProtected()
3624 def getAccessProtectionLevel( self
):
3625 return self
.__ac
.getAccessProtectionLevel()
3627 def isItselfProtected( self
):
3628 return self
.__ac
.isItselfProtected()
3630 def hasAnyProtection( self
):
3631 """Tells whether a conference has any kind of protection over it:
3632 access or domain protection.
3634 if self
.isProtected():
3636 if self
.getDomainList():
3639 if self
.getAccessProtectionLevel() == -1:
3642 for owner
in self
.getOwnerList():
3643 if owner
.hasAnyProtection():
3648 def hasProtectedOwner( self
):
3649 return self
.__ac
._getFatherProtection
()
3651 def setProtection( self
, private
):
3653 Allows to change the conference access protection
3656 oldValue
= 1 if self
.isProtected() else -1
3658 self
.getAccessController().setProtection( private
)
3660 if oldValue
!= private
:
3662 signals
.event
.protection_changed
.send(self
, old
=oldValue
, new
=private
)
3664 def grantAccess( self
, prin
):
3665 self
.__ac
.grantAccess( prin
)
3666 if isinstance(prin
, AvatarUserWrapper
):
3667 prin
.linkTo(self
, "access")
3669 def revokeAccess( self
, prin
):
3670 self
.__ac
.revokeAccess( prin
)
3671 if isinstance(prin
, AvatarUserWrapper
):
3672 prin
.unlinkTo(self
, "access")
3674 def canView( self
, aw
):
3675 """tells whether the specified access wrappers has access to the current
3676 object or any of its parts"""
3677 if self
.canAccess( aw
):
3679 for session
in self
.getSessionList():
3680 if session
.canView( aw
):
3682 for contrib
in self
.getContributionList():
3683 if contrib
.canView( aw
):
3687 def isAllowedToAccess( self
, av
):
3688 """tells if a user has privileges to access the current conference
3689 (independently that it is protected or not)
3693 if (av
in self
.getChairList()) or (self
.__ac
.canUserAccess( av
)) or (self
.canUserModify( av
)):
3696 # if the conference is not protected by itself
3697 if not self
.isItselfProtected():
3698 # then inherit behavior from parent category
3699 for owner
in self
.getOwnerList():
3700 if owner
.isAllowedToAccess( av
):
3703 # track coordinators are also allowed to access the conference
3704 for track
in self
.getTrackList():
3705 if track
.isCoordinator( av
):
3708 # paper reviewing team should be also allowed to access
3709 if self
.getConfPaperReview().isInReviewingTeam(av
):
3714 def canAccess( self
, aw
):
3715 """Tells whether an access wrapper is allowed to access the current
3716 conference: when the conference is protected, only if the user is a
3717 chair or is granted to access the conference, when the client ip is
3721 # Allow harvesters (Invenio, offline cache) to access
3723 if has_request_context() and self
.__ac
.isHarvesterIP(request
.remote_addr
):
3726 # Managers have always access
3727 if self
.canModify(aw
):
3730 if self
.isProtected():
3731 if self
.isAllowedToAccess( aw
.getUser() ):
3734 return self
.canKeyAccess(aw
)
3736 # Domain control is triggered just for PUBLIC events
3737 return self
.canIPAccess(request
.remote_addr
)
3739 def canKeyAccess(self
, aw
, key
=None):
3740 accessKey
= self
.getAccessKey()
3743 return key
== accessKey
or session
.get('accessKeys', {}).get(self
.getUniqueId()) == accessKey
3745 def canKeyModify(self
):
3746 modifKey
= self
.getModifKey()
3749 return session
.get('modifKeys', {}).get(self
.id) == modifKey
3751 def grantModification( self
, prin
, sendEmail
=True ):
3753 if isinstance(prin
, ConferenceChair
):
3754 email
= prin
.getEmail()
3755 elif isinstance(prin
, str):
3761 results
=ah
.match({"email":email
}, exact
=1)
3762 #No registered user in Indico with that email
3763 if len(results
) == 0:
3764 self
.__ac
.grantModificationEmail(email
)
3765 self
.getConference().getPendingQueuesMgr().addPendingConfManager(prin
, False)
3766 if sendEmail
and isinstance(prin
, ConferenceChair
):
3767 notif
= pendingQueues
._PendingConfManagerNotification
( [prin
] )
3768 mail
.GenericMailer
.sendAndLog( notif
, self
.getConference() )
3769 #The user is registered in Indico and is activated as well
3770 elif len(results
) == 1 and results
[0] is not None and results
[0].isActivated():
3771 self
.__ac
.grantModification(results
[0])
3772 results
[0].linkTo(self
, "manager")
3774 self
.__ac
.grantModification( prin
)
3775 if isinstance(prin
, AvatarUserWrapper
):
3776 prin
.linkTo(self
, "manager")
3778 def revokeModification( self
, prin
):
3779 self
.__ac
.revokeModification( prin
)
3780 if isinstance(prin
, AvatarUserWrapper
):
3781 prin
.unlinkTo(self
, "manager")
3783 @unify_user_args(legacy
=True)
3784 def canUserModify( self
, av
):
3787 if ( av
== self
.getCreator()) or self
.getAccessController().canModify( av
):
3789 for owner
in self
.getOwnerList():
3790 if owner
.canUserModify( av
):
3794 @unify_user_args(legacy
=True)
3795 def canModify(self
, aw_or_user
):
3796 """Tells whether an access wrapper is allowed to modify the current
3797 conference: only if the user is granted to modify the conference and
3798 he is accessing from an IP address which is not restricted.
3800 if hasattr(aw_or_user
, 'getUser'):
3801 aw_or_user
= aw_or_user
.getUser()
3802 return self
.canUserModify(aw_or_user
) or self
.canKeyModify()
3804 def getManagerList( self
):
3805 return self
.__ac
.getModifierList()
3807 def addToRegistrars(self
, av
):
3808 self
.getRegistrarList().append(av
)
3809 self
.notifyModification()
3810 if isinstance(av
, AvatarUserWrapper
):
3811 av
.linkTo(self
, "registrar")
3813 def removeFromRegistrars(self
, av
):
3814 self
.getRegistrarList().remove(av
)
3815 self
.notifyModification()
3816 if isinstance(av
, AvatarUserWrapper
):
3817 av
.unlinkTo(self
, "registrar")
3819 def isRegistrar(self
, av
):
3823 return any(principal
.containsUser(av
) for principal
in self
.getRegistrarList())
3824 except AttributeError:
3827 def getRegistrarList(self
):
3829 return self
.__registrars
3830 except AttributeError:
3831 self
.__registrars
= []
3832 return self
.__registrars
3834 def canManageRegistration(self
, av
):
3835 return self
.isRegistrar(av
) or self
.canUserModify(av
)
3837 def getAllowedToAccessList( self
):
3838 return self
.__ac
.getAccessList()
3840 def addMaterial( self
, newMat
):
3841 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
3842 newMat
.setOwner( self
)
3843 self
.materials
[ newMat
.getId() ] = newMat
3844 self
.notifyModification()
3846 def removeMaterial( self
, mat
):
3847 if mat
.getId() in self
.materials
.keys():
3849 self
.materials
[mat
.getId()].setOwner(None)
3850 del self
.materials
[ mat
.getId() ]
3851 self
.notifyModification()
3852 elif mat
.getId().lower() == 'paper':
3854 self
.notifyModification()
3855 elif mat
.getId().lower() == 'slides':
3857 self
.notifyModification()
3858 elif mat
.getId().lower() == 'minutes':
3859 self
.removeMinutes()
3860 self
.notifyModification()
3861 elif mat
.getId().lower() == 'video':
3863 self
.notifyModification()
3864 elif mat
.getId().lower() == 'poster':
3866 self
.notifyModification()
3868 def recoverMaterial(self
, recMat
):
3869 # Id must already be set in recMat.
3870 recMat
.setOwner(self
)
3871 self
.materials
[recMat
.getId()] = recMat
3873 self
.notifyModification()
3875 def getMaterialRegistry(self
):
3877 Return the correct material registry for this type
3879 from MaKaC
.webinterface
.materialFactories
import ConfMFRegistry
3880 return ConfMFRegistry
3882 def getMaterialById( self
, matId
):
3883 if matId
.lower() == 'paper':
3884 return self
.getPaper()
3885 elif matId
.lower() == 'slides':
3886 return self
.getSlides()
3887 elif matId
.lower() == 'video':
3888 return self
.getVideo()
3889 elif matId
.lower() == 'poster':
3890 return self
.getPoster()
3891 elif matId
.lower() == 'minutes':
3892 return self
.getMinutes()
3893 elif self
.materials
.has_key(matId
):
3894 return self
.materials
[ matId
]
3897 def getMaterialList( self
):
3898 return self
.materials
.values()
3900 def getAllMaterialList(self
, sort
=True):
3901 l
= self
.getMaterialList()
3903 l
.append( self
.getPaper() )
3904 if self
.getSlides():
3905 l
.append( self
.getSlides() )
3907 l
.append( self
.getVideo() )
3908 if self
.getPoster():
3909 l
.append( self
.getPoster() )
3910 if self
.getMinutes():
3911 l
.append( self
.getMinutes() )
3913 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
3916 def _getMaterialFiles(self
, material
):
3918 Adaption of _getMaterialFiles in WPTPLConferenceDisplay for desired format, objects
3919 seemed mutually exclusive hence use of similar logic here specific to Conference.
3924 for res
in material
.getResourceList():
3926 ftype
= res
.getFileType()
3927 fname
= res
.getFileName()
3928 furl
= urlHandlers
.UHFileAccess
.getURL(res
)
3930 if fname
in processed
:
3931 fname
= "%s - %s" % (fname
, processed
.count(fname
))
3933 processed
.append(res
.getFileName())
3935 # If we are here then the resource is a Link object.
3936 fname
, ftype
, furl
= str(res
.getURL()), "link", str(res
.getURL())
3937 fdesc
= res
.getDescription()
3938 files
.append({'title': fname
,
3939 'description': fdesc
,
3944 def getAllMaterialDict(self
, child
=None):
3946 This method iterates through the children of the conference, creating
3947 a dictionary which maps type to material link URLs.
3950 child
= self
if child
is None else child
3953 node
['title'] = child
.getTitle()
3956 node
['type'] = child
.getType()
3958 # If we land here, it's a session which doesn't have 'getType'
3959 node
['type'] = 'session'
3961 node
['children'] = []
3962 node
['material'] = []
3964 if node
['type'] in ['conference', 'meeting']:
3965 for session
in child
.getSessionList():
3966 node
['children'].append(self
.getAllMaterialDict(session
))
3968 for contrib
in child
.getContributionList():
3969 node
['children'].append(self
.getAllMaterialDict(contrib
))
3971 for material
in child
.getAllMaterialList():
3972 files
= self
._getMaterialFiles
(material
)
3976 materialNode
['type'] = 'material'
3977 materialNode
['title'] = material
.getTitle()
3979 if material
.getTitle() != 'Minutes':
3980 materialNode
['title'] += ' - ' + f
['title']
3982 materialNode
['materialType'] = f
['type']
3983 materialNode
['url'] = str(f
['url'])
3985 node
['material'].append(materialNode
)
3989 def setPaper( self
, newPaper
):
3990 if self
.getPaper() != None:
3991 raise MaKaCError( _("The paper for this conference has already been set"), _("Conference"))
3993 self
.paper
.setOwner( self
)
3994 self
.notifyModification()
3996 def removePaper( self
):
3997 if self
.paper
is None:
4000 self
.paper
.setOwner(None)
4002 self
.notifyModification()
4004 def recoverPaper(self
, p
):
4008 def getPaper( self
):
4012 except AttributeError:
4016 def setSlides( self
, newSlides
):
4017 if self
.getSlides() != None:
4018 raise MaKaCError( _("The slides for this conference have already been set"), _("Conference"))
4019 self
.slides
=newSlides
4020 self
.slides
.setOwner( self
)
4021 self
.notifyModification()
4023 def removeSlides( self
):
4024 if self
.slides
is None:
4026 self
.slides
.delete()
4027 self
.slides
.setOwner( None )
4029 self
.notifyModification()
4031 def recoverSlides(self
, s
):
4035 def getSlides( self
):
4039 except AttributeError:
4043 def setVideo( self
, newVideo
):
4044 if self
.getVideo() != None:
4045 raise MaKaCError( _("The video for this conference has already been set"), _("Conference"))
4047 self
.video
.setOwner( self
)
4048 self
.notifyModification()
4050 def removeVideo( self
):
4051 if self
.getVideo() is None:
4054 self
.video
.setOwner(None)
4056 self
.notifyModification()
4058 def recoverVideo(self
, v
):
4062 def getVideo( self
):
4066 except AttributeError:
4070 def setPoster( self
, newPoster
):
4071 if self
.getPoster() != None:
4072 raise MaKaCError( _("the poster for this conference has already been set"), _("Conference"))
4073 self
.poster
=newPoster
4074 self
.poster
.setOwner( self
)
4075 self
.notifyModification()
4077 def removePoster( self
):
4078 if self
.getPoster() is None:
4080 self
.poster
.delete()
4081 self
.poster
.setOwner(None)
4083 self
.notifyModification()
4085 def recoverPoster(self
, p
):
4089 def getPoster( self
):
4093 except AttributeError:
4097 def setMinutes( self
, newMinutes
):
4098 if self
.getMinutes() != None:
4099 raise MaKaCError( _("The Minutes for this conference has already been set"))
4100 self
.minutes
=newMinutes
4101 self
.minutes
.setOwner( self
)
4102 self
.notifyModification()
4104 def createMinutes( self
):
4105 if self
.getMinutes() != None:
4106 raise MaKaCError( _("The minutes for this conference have already been created"), _("Conference"))
4107 self
.minutes
= Minutes()
4108 self
.minutes
.setOwner( self
)
4109 self
.notifyModification()
4112 def removeMinutes( self
):
4113 if self
.getMinutes() is None:
4115 self
.minutes
.delete()
4116 self
.minutes
.setOwner( None )
4118 self
.notifyModification()
4120 def recoverMinutes(self
, min):
4121 self
.removeMinutes() # To ensure that the current minutes are put in
4124 self
.minutes
.setOwner( self
)
4126 self
.notifyModification()
4129 def getMinutes( self
):
4134 except AttributeError, e
:
4138 def _setSchedule( self
, sch
=None ):
4139 self
.__schedule
=ConferenceSchedule(self
)
4140 for session
in self
.getSessionList():
4141 for slot
in session
.getSlotList():
4142 self
.__schedule
.addEntry(slot
.getConfSchEntry())
4144 def getSchedule( self
):
4146 if not self
.__schedule
:
4148 except AttributeError, e
:
4150 return self
.__schedule
4153 sch
= self
.getSchedule()
4155 sDate
= sch
.calculateStartDate()
4156 eDate
= sch
.calculateEndDate()
4157 self
.setStartDate(sDate
)
4158 self
.setEndDate(eDate
)
4160 def fitSlotsOnDay( self
, day
):
4161 for entry
in self
.getSchedule().getEntriesOnDay(day
) :
4162 if isinstance(entry
.getOwner(), SessionSlot
) :
4163 entry
.getOwner().fit()
4165 def getDisplayMgr(self
):
4167 Return the display manager for the conference
4169 from MaKaC
.webinterface
import displayMgr
4170 return displayMgr
.ConfDisplayMgrRegistery().getDisplayMgr(self
)
4172 def getDefaultStyle( self
):
4173 return self
.getDisplayMgr().getDefaultStyle()
4175 def clone( self
, startDate
, options
, eventManager
=None, userPerformingClone
= None ):
4176 # startDate must be in the timezone of the event (to avoid problems with daylight-saving times)
4177 cat
= self
.getOwnerList()[0]
4178 managing
= options
.get("managing",None)
4179 if managing
is not None:
4182 creator
= self
.getCreator()
4183 conf
= cat
.newConference(creator
)
4184 if managing
is not None :
4185 conf
.grantModification(managing
)
4186 conf
.setTitle(self
.getTitle())
4187 conf
.setDescription(self
.getDescription())
4188 conf
.setTimezone(self
.getTimezone())
4189 for loc
in self
.getLocationList():
4191 conf
.addLocation(loc
.clone())
4192 if self
.getRoom() is not None:
4193 conf
.setRoom(self
.getRoom().clone())
4194 startDate
= timezone(self
.getTimezone()).localize(startDate
).astimezone(timezone('UTC'))
4195 timeDelta
= startDate
- self
.getStartDate()
4196 endDate
= self
.getEndDate() + timeDelta
4197 conf
.setDates( startDate
, endDate
, moveEntries
=1 )
4198 conf
.setContactInfo(self
.getContactInfo())
4199 conf
.setChairmanText(self
.getChairmanText())
4200 conf
.setVisibility(self
.getVisibility())
4201 conf
.setSupportInfo(self
.getSupportInfo().clone(self
))
4202 conf
.setReportNumberHolder(self
.getReportNumberHolder().clone(self
))
4203 for ch
in self
.getChairList():
4204 conf
.addChair(ch
.clone())
4205 ContextManager
.setdefault("clone.unique_id_map", {})[self
.getUniqueId()] = conf
.getUniqueId()
4207 from MaKaC
.webinterface
import displayMgr
4208 selfDispMgr
=displayMgr
.ConfDisplayMgrRegistery().getDisplayMgr(self
)
4209 selfDispMgr
.clone(conf
)
4210 # Contribution Types' List (main detailes of the conference)
4211 for t
in self
.getContribTypeList() :
4212 conf
.addContribType(t
.clone(conf
))
4213 if options
.get("sessions", False):
4214 for entry
in self
.getSchedule().getEntries():
4215 if isinstance(entry
,BreakTimeSchEntry
):
4216 conf
.getSchedule().addEntry(entry
.clone(conf
))
4217 db_root
= DBMgr
.getInstance().getDBConnection().root()
4218 if db_root
.has_key( "webfactoryregistry" ):
4219 confRegistry
= db_root
["webfactoryregistry"]
4221 confRegistry
= OOBTree
.OOBTree()
4222 db_root
["webfactoryregistry"] = confRegistry
4224 # if the event is a meeting or a lecture
4225 if confRegistry
.get(str(self
.getId()), None) is not None :
4227 confRegistry
[str(conf
.getId())] = confRegistry
[str(self
.getId())]
4228 # if it's a conference, no web factory is needed
4229 # Tracks in a conference
4230 if options
.get("tracks",False) :
4231 for tr
in self
.getTrackList() :
4232 conf
.addTrack(tr
.clone(conf
))
4233 # Meetings' and conferences' sessions cloning
4234 if options
.get("sessions",False) :
4235 for s
in self
.getSessionList() :
4236 newSes
= s
.clone(timeDelta
, conf
, options
, session_id
=s
.getId())
4237 ContextManager
.setdefault("clone.unique_id_map", {})[s
.getUniqueId()] = newSes
.getUniqueId()
4238 conf
.addSession(newSes
)
4239 # Materials' cloning
4240 if options
.get("materials",False) :
4241 for m
in self
.getMaterialList() :
4242 conf
.addMaterial(m
.clone(conf
))
4243 if self
.getPaper() is not None:
4244 conf
.setPaper(self
.getPaper().clone(conf
))
4245 if self
.getSlides() is not None:
4246 conf
.setSlides(self
.getSlides().clone(conf
))
4247 if self
.getVideo() is not None:
4248 conf
.setVideo(self
.getVideo().clone(conf
))
4249 if self
.getPoster() is not None:
4250 conf
.setPoster(self
.getPoster().clone(conf
))
4251 if self
.getMinutes() is not None:
4252 conf
.setMinutes(self
.getMinutes().clone(conf
))
4253 # access and modification keys
4254 if options
.get("keys", False) :
4255 conf
.setAccessKey(self
.getAccessKey())
4256 conf
.setModifKey(self
.getModifKey())
4257 # Access Control cloning
4258 if options
.get("access",False) :
4259 conf
.setProtection(self
.getAccessController()._getAccessProtection
())
4260 for mgr
in self
.getManagerList() :
4261 conf
.grantModification(mgr
)
4262 for user
in self
.getAllowedToAccessList() :
4263 conf
.grantAccess(user
)
4264 for right
in self
.getSessionCoordinatorRights():
4265 conf
.addSessionCoordinatorRight(right
)
4266 for domain
in self
.getDomainList():
4267 conf
.requireDomain(domain
)
4268 # conference's registration form
4269 if options
.get("registration",False) :
4270 conf
.setRegistrationForm(self
.getRegistrationForm().clone(conf
))
4272 # conference's evaluation
4273 if options
.get("evaluation",False) :
4274 #Modify this, if you have now many evaluations.
4275 #You will have to clone every evaluations of this conference.
4276 conf
.setEvaluations([self
.getEvaluation().clone(conf
)])
4278 #conference's abstracts
4279 if options
.get("abstracts",False) :
4280 conf
.abstractMgr
= self
.abstractMgr
.clone(conf
)
4281 # conference's alerts
4282 if options
.get("alerts",False) :
4283 for alarm
in self
.getAlarmList() :
4284 # Indico does not clone absoulte alarms
4285 if alarm
._relative
is not None:
4286 # .clone takes care of enqueuing it
4288 # Meetings' and conferences' contributions cloning
4289 if options
.get("contributions",False) :
4290 sch
= conf
.getSchedule()
4291 for cont
in self
.getContributionList():
4292 if cont
.getSession() is None :
4294 nc
= cont
.clone(conf
, options
, timeDelta
)
4295 conf
.addContribution(nc
)
4296 if cont
.isScheduled() :
4297 sch
.addEntry(nc
.getSchEntry())
4298 ContextManager
.setdefault("clone.unique_id_map", {})[cont
.getUniqueId()] = nc
.getUniqueId()
4299 elif cont
.isScheduled():
4300 # meetings...only scheduled
4301 nc
= cont
.clone(conf
, options
, timeDelta
)
4302 conf
.addContribution(nc
)
4303 sch
.addEntry(nc
.getSchEntry())
4304 ContextManager
.setdefault("clone.unique_id_map", {})[cont
.getUniqueId()] = nc
.getUniqueId()
4305 # Participants' module settings and list cloning
4306 if options
.get("participants",False) :
4307 self
.getParticipation().clone(conf
, options
, eventManager
)
4308 conf
.notifyModification()
4310 #we inform the plugins in case they want to add anything to the new conference
4311 EventCloner
.clone_event(self
, conf
)
4314 def newAlarm(self
, when
, enqueue
=True):
4316 if type(when
) == timedelta
:
4323 confRelId
= self
._getNextAlarmId
()
4324 al
= tasks
.AlarmTask(self
, confRelId
,
4325 startDateTime
=dtStart
,
4328 self
.addAlarm(al
, enqueue
)
4331 def removeAlarm(self
, alarm
):
4332 confRelId
= alarm
.getConfRelativeId()
4334 if confRelId
in self
.alarmList
:
4335 del self
.alarmList
[confRelId
]
4341 raise Exception("alarm not in list!")
4343 def _getNextAlarmId(self
):
4344 return self
.__alarmCounter
.newCount()
4346 def addAlarm(self
, alarm
, enqueue
= True):
4351 self
.alarmList
[alarm
.getConfRelativeId()] = alarm
4354 def recoverAlarm(self
, alarm
):
4355 self
.addAlarm(alarm
)
4359 def getAlarmList(self
):
4360 return self
.alarmList
.values()
4362 def getAlarmById(self
, id):
4363 """For given id returns corresponding Alarm or None if not found."""
4364 return self
.alarmList
.get(id, None)
4366 def getCoordinatedTracks( self
, av
):
4367 """Returns a list with the tracks for which a user is coordinator.
4370 if self
._trackCoordinators
:
4372 except AttributeError:
4373 self
._trackCoordinators
= TCIndex()
4374 self
.notifyModification()
4375 return self
._trackCoordinators
.getTracks( av
)
4377 def addTrackCoordinator( self
, track
, av
):
4378 """Makes a user become coordinator for a track.
4381 if self
._trackCoordinators
:
4383 except AttributeError:
4384 self
._trackCoordinators
= TCIndex()
4385 self
.notifyModification()
4386 if track
in self
.program
:
4387 track
.addCoordinator( av
)
4388 self
._trackCoordinators
.indexCoordinator( av
, track
)
4389 self
.notifyModification()
4391 def removeTrackCoordinator( self
, track
, av
):
4392 """Removes a user as coordinator for a track.
4395 if self
._trackCoordinators
:
4397 except AttributeError:
4398 self
._trackCoordinators
= TCIndex()
4399 self
.notifyModification()
4400 if track
in self
.program
:
4401 track
.removeCoordinator( av
)
4402 self
._trackCoordinators
.unindexCoordinator( av
, track
)
4403 self
.notifyModification()
4405 def _rebuildAuthorIndex(self
):
4406 self
._authorIdx
=AuthorIndex()
4407 for contrib
in self
.getContributionList():
4408 if not isinstance(contrib
.getCurrentStatus(),ContribStatusWithdrawn
):
4409 for auth
in contrib
.getAuthorList():
4410 self
._authorIdx
.index(auth
)
4412 def getAuthorIndex(self
):
4416 except AttributeError:
4417 self
._rebuildAuthorIndex
()
4418 return self
._authorIdx
4420 def indexAuthor(self
,auth
):
4421 c
=auth
.getContribution()
4422 if c
.isAuthor(auth
):
4423 if not isinstance(c
.getCurrentStatus(),ContribStatusWithdrawn
):
4424 self
.getAuthorIndex().index(auth
)
4425 if c
.isPrimaryAuthor(auth
):
4426 self
._getPrimAuthIndex
().index(auth
)
4428 def unindexAuthor(self
,auth
):
4429 c
=auth
.getContribution()
4430 if c
.isAuthor(auth
):
4431 self
.getAuthorIndex().unindex(auth
)
4432 if c
.isPrimaryAuthor(auth
):
4433 self
._getPrimAuthIndex
().unindex(auth
)
4435 def _rebuildSpeakerIndex(self
):
4436 self
._speakerIdx
=AuthorIndex()
4437 for contrib
in self
.getContributionList():
4438 if not isinstance(contrib
.getCurrentStatus(),ContribStatusWithdrawn
):
4439 for auth
in contrib
.getSpeakerList():
4440 self
._speakerIdx
.index(auth
)
4441 for subcontrib
in contrib
.getSubContributionList():
4442 for auth
in subcontrib
.getSpeakerList():
4443 self
._speakerIdx
.index(auth
)
4445 def getSpeakerIndex(self
):
4447 if self
._speakerIdx
:
4449 except AttributeError:
4450 self
._rebuildSpeakerIndex
()
4451 return self
._speakerIdx
4453 def indexSpeaker(self
,auth
):
4454 c
=auth
.getContribution()
4455 if not isinstance(c
.getCurrentStatus(),ContribStatusWithdrawn
):
4456 self
.getSpeakerIndex().index(auth
)
4458 def unindexSpeaker(self
,auth
):
4459 c
=auth
.getContribution()
4460 if c
and not isinstance(c
.getCurrentStatus(),ContribStatusWithdrawn
):
4461 self
.getSpeakerIndex().unindex(auth
)
4463 def getRegistrationForm(self
):
4465 if self
._registrationForm
is None:
4466 self
._registrationForm
= registration
.RegistrationForm(self
)
4467 except AttributeError,e
:
4468 self
._registrationForm
= registration
.RegistrationForm(self
)
4469 return self
._registrationForm
4471 def setRegistrationForm(self
,rf
):
4472 self
._registrationForm
= rf
4473 rf
.setConference(self
)
4475 def removeRegistrationForm(self
):
4477 self
._registrationForm
.delete()
4478 self
._registrationForm
.setConference(None)
4479 self
._registrationForm
= None
4480 except AttributeError:
4481 self
._registrationForm
= None
4483 def recoverRegistrationForm(self
, rf
):
4484 self
.setRegistrationForm(rf
)
4487 def getEvaluation(self
, id=0):
4488 ############################################################################
4489 #For the moment only one evaluation per conference is used. #
4490 #In the future if there are more than one evaluation, modify this function.#
4491 ############################################################################
4492 """ Return the evaluation given by its ID or None if nothing found.
4494 id -- id of the wanted evaluation
4496 for evaluation
in self
.getEvaluations():
4497 if str(evaluation
.getId()) == str(id) :
4499 if Config
.getInstance().getDebug():
4500 raise Exception(_("Error with id: expected '%s', found '%s'.")%(id, self
.getEvaluations()[0].getId()))
4502 return self
.getEvaluations()[0]
4504 def getEvaluations(self
):
4505 if not hasattr(self
, "_evaluations"):
4506 self
._evaluations
= [Evaluation(self
)]
4507 return self
._evaluations
4509 def setEvaluations(self
, evaluationsList
):
4510 self
._evaluations
= evaluationsList
4511 for evaluation
in self
._evaluations
:
4512 evaluation
.setConference(self
)
4514 def removeEvaluation(self
, evaluation
):
4515 """remove the given evaluation from its evaluations."""
4516 evaluations
= self
.getEvaluations()
4517 if evaluations
.count(evaluation
)>0:
4518 evaluations
.remove(evaluation
)
4519 evaluation
.removeReferences()
4520 self
.notifyModification()
4522 def removeAllEvaluations(self
):
4523 for evaluation
in self
.getEvaluations():
4524 evaluation
.removeReferences()
4525 self
._evaluations
= []
4526 self
.notifyModification()
4528 def _getEvaluationCounter(self
):
4529 if not hasattr(self
, "_evaluationCounter"):
4530 self
._evaluationCounter
= Counter()
4531 return self
._evaluationCounter
4533 ## Videoconference bookings related
4534 def getBookings(self
):
4538 except AttributeError, e
:
4540 self
.notifyModification()
4541 return self
._bookings
4543 def getBookingsList(self
, sort
= False):
4544 bl
= self
.getBookings().values()
4549 def _getBookingGenerator(self
):
4551 return self
._bookingGenerator
4552 except AttributeError, e
:
4553 self
._bookingGenerator
= Counter()
4554 return self
._bookingGenerator
4556 def getNewBookingId(self
):
4557 return str(self
._getBookingGenerator
().newCount())
4559 def addBooking(self
, bp
):
4560 if (bp
.getId() == ""):
4561 bp
.setId(self
.getNewBookingId())
4562 self
.getBookings()[bp
.getId()] = bp
4563 self
.notifyModification()
4565 def hasBooking(self
,booking
):
4566 return booking
.getConference()==self
and \
4567 self
.getBookings().has_key(booking
.getId())
4569 def removeBooking(self
, booking
):
4570 if self
.hasBooking(booking
):
4571 deletion
= booking
.deleteBooking()
4572 if deletion
[0] != 1:
4573 del self
.getBookings()[booking
.getId()]
4574 self
.notifyModification()
4577 def getBookingByType(self
, type):
4578 if self
.getBookings().has_key(type):
4579 return self
.getBookings()[type]
4582 def getBookingById(self
, id):
4583 if self
.getBookings().has_key(id):
4584 return self
.getBookings()[id]
4587 ## End of Videoconference bookings related
4589 def getRegistrants(self
):
4591 if self
._registrants
:
4593 except AttributeError, e
:
4594 self
._registrants
= {}
4595 self
.notifyModification()
4596 return self
._registrants
4598 def getRegistrantsByEmail(self
, email
=None):
4600 Returns the index of registrants by email OR a specific registrant if an email address
4601 is passed as argument.
4604 if self
._registrantsByEmail
:
4606 except AttributeError, e
:
4607 self
._registrantsByEmail
= self
._createRegistrantsByEmail
()
4608 self
.notifyModification()
4610 return self
._registrantsByEmail
.get(email
)
4611 return self
._registrantsByEmail
4613 def _createRegistrantsByEmail(self
):
4615 for r
in self
.getRegistrantsList():
4616 dicByEmail
[r
.getEmail()] = r
4619 def getRegistrantsList(self
, sort
= False):
4620 rl
= self
.getRegistrants().values()
4622 rl
.sort(registration
.Registrant
._cmpFamilyName
)
4625 def _getRegistrantGenerator(self
):
4627 return self
._registrantGenerator
4628 except AttributeError, e
:
4629 self
._registrantGenerator
= Counter()
4630 return self
._registrantGenerator
4632 def addRegistrant(self
, rp
, user
):
4633 rp
.setId( str(self
._getRegistrantGenerator
().newCount()) )
4635 self
.getRegistrants()[rp
.getId()] = rp
4636 signals
.event
.registrant_changed
.send(self
, user
=user
, registrant
=rp
, action
='added')
4637 self
.notifyModification()
4639 def updateRegistrantIndexByEmail(self
, rp
, newEmail
):
4640 oldEmail
= rp
.getEmail()
4641 if oldEmail
!= newEmail
:
4642 if self
.getRegistrantsByEmail().has_key(oldEmail
):
4643 del self
.getRegistrantsByEmail()[oldEmail
]
4644 self
.getRegistrantsByEmail()[newEmail
] = rp
4645 self
.notifyModification()
4647 def hasRegistrant(self
,rp
):
4648 return rp
.getConference()==self
and \
4649 self
.getRegistrants().has_key(rp
.getId())
4651 def hasRegistrantByEmail(self
, email
):
4652 # Return true if there is someone with the email of the param "email"
4653 return self
.getRegistrantsByEmail().has_key(email
)
4655 def removeRegistrant(self
, id):
4656 part
= self
.getRegistrants()[id]
4657 self
._registrationForm
.notifyRegistrantRemoval(self
.getRegistrants()[id])
4658 del self
.getRegistrantsByEmail()[self
.getRegistrantById(id).getEmail()]
4659 del self
.getRegistrants()[id]
4660 signals
.event
.registrant_changed
.send(self
, user
=part
.getAvatar(), registrant
=part
, action
='removed')
4661 TrashCanManager().add(part
)
4662 self
.notifyModification()
4664 def getRegistrantById(self
, id):
4665 if self
.getRegistrants().has_key(id):
4666 return self
.getRegistrants()[id]
4669 def _getPrimAuthIndex(self
):
4671 if self
._primAuthIdx
:
4673 except AttributeError:
4674 self
._primAuthIdx
=_PrimAuthIdx(self
)
4675 return self
._primAuthIdx
4677 def getContribsMatchingAuth(self
,query
,onlyPrimary
=True):
4678 if str(query
).strip()=="":
4679 return self
.getContributionList()
4680 res
=self
._getPrimAuthIndex
().match(query
)
4681 return [self
.getContributionById(id) for id in res
]
4683 def getCoordinatedSessions( self
, av
):
4684 """Returns a list with the sessions for which a user is coordinator.
4687 if self
._sessionCoordinators
:
4689 except AttributeError:
4690 self
._sessionCoordinators
= SCIndex()
4691 sessions
= self
._sessionCoordinators
.getSessions( av
)
4692 for session
in self
.getSessionList():
4693 if session
not in sessions
and av
!= None:
4694 for email
in av
.getEmails():
4695 if email
in session
.getCoordinatorEmailList():
4696 sessions
.append(session
)
4700 def getManagedSession( self
, av
):
4702 for session
in self
.getSessionList():
4705 for email
in av
.getEmails():
4706 if email
in session
.getAccessController().getModificationEmail():
4709 if av
in session
.getManagerList() or pending
:
4713 def addSessionCoordinator(self
,session
,av
):
4714 """Makes a user become coordinator for a session.
4717 if self
._sessionCoordinators
:
4719 except AttributeError:
4720 self
._sessionCoordinators
= SCIndex()
4721 if self
.sessions
.has_key(session
.getId()):
4722 session
.addCoordinator(av
)
4723 self
._sessionCoordinators
.index(av
,session
)
4724 session
._addCoordinatorEmail
(av
.getEmail())
4726 def removeSessionCoordinator( self
, session
, av
):
4727 """Removes a user as coordinator for a session.
4730 if self
._sessionCoordinators
:
4732 except AttributeError:
4733 self
._sessionCoordinators
= SCIndex()
4734 if self
.sessions
.has_key(session
.getId()):
4735 session
.removeCoordinator( av
)
4736 self
._sessionCoordinators
.unindex(av
,session
)
4737 session
.removeCoordinatorEmail(av
.getEmail())
4739 def _getSubmitterIdx(self
):
4741 return self
._submitterIdx
4742 except AttributeError:
4743 self
._submitterIdx
=SubmitterIndex()
4744 return self
._submitterIdx
4746 def addContribSubmitter(self
,contrib
,av
):
4747 self
._getSubmitterIdx
().index(av
,contrib
)
4749 def removeContribSubmitter(self
,contrib
,av
):
4750 self
._getSubmitterIdx
().unindex(av
,contrib
)
4752 def getContribsForSubmitter(self
,av
):
4753 return self
._getSubmitterIdx
().getContributions(av
)
4755 def getBOAConfig(self
):
4759 except AttributeError:
4760 self
._boa
=BOAConfig(self
)
4763 def getSessionCoordinatorRights(self
):
4765 if self
._sessionCoordinatorRights
:
4767 except AttributeError, e
:
4768 self
._sessionCoordinatorRights
= []
4769 self
.notifyModification()
4770 return self
._sessionCoordinatorRights
4772 def hasSessionCoordinatorRight(self
, right
):
4773 return right
in self
.getSessionCoordinatorRights()
4775 def addSessionCoordinatorRight(self
, right
):
4776 if SessionCoordinatorRights().hasRight(right
) and not self
.hasSessionCoordinatorRight(right
):
4777 self
._sessionCoordinatorRights
.append(right
)
4778 self
.notifyModification()
4780 def removeSessionCoordinatorRight(self
, right
):
4781 if SessionCoordinatorRights().hasRight(right
) and self
.hasSessionCoordinatorRight(right
):
4782 self
._sessionCoordinatorRights
.remove(right
)
4783 self
.notifyModification()
4785 def hasEnabledSection(self
, section
):
4786 # This hack is there since there is no more enable/disable boxes
4787 # in the conference managment area corresponding to those features.
4788 # Until the managment area is improved to get a more user-friendly
4789 # way of enabling/disabling those features, we always make them
4790 # available for the time being, but we keep the previous code for
4791 # further improvements
4794 def getPendingQueuesMgr(self
):
4796 if self
._pendingQueuesMgr
:
4798 except AttributeError, e
:
4799 self
._pendingQueuesMgr
=pendingQueues
.ConfPendingQueuesMgr(self
)
4800 return self
._pendingQueuesMgr
4802 def getAccessController(self
):
4805 def _cmpTitle( c1
, c2
):
4806 o1
= c1
.getTitle().lower().strip()
4807 o2
= c2
.getTitle().lower().strip()
4808 return cmp( o1
, o2
)
4809 _cmpTitle
=staticmethod(_cmpTitle
)
4811 def getReportNumberHolder(self
):
4813 if self
._reportNumberHolder
:
4815 except AttributeError, e
:
4816 self
._reportNumberHolder
=ReportNumberHolder(self
)
4817 return self
._reportNumberHolder
4819 def setReportNumberHolder(self
, rnh
):
4820 self
._reportNumberHolder
=rnh
4822 def getBadgeTemplateManager(self
):
4824 if self
.__badgeTemplateManager
:
4826 except AttributeError:
4827 self
.__badgeTemplateManager
= BadgeTemplateManager(self
)
4828 return self
.__badgeTemplateManager
4830 def setBadgeTemplateManager(self
, badgeTemplateManager
):
4831 self
.__badgeTemplateManager
= badgeTemplateManager
4833 def getPosterTemplateManager(self
):
4835 if self
.__posterTemplateManager
:
4837 except AttributeError:
4838 self
.__posterTemplateManager
= PosterTemplateManager(self
)
4840 return self
.__posterTemplateManager
4842 def setPosterTemplateManager(self
, posterTemplateManager
):
4843 self
.__posterTemplateManager
= posterTemplateManager
4845 class DefaultConference(Conference
):
4846 """ 'default' conference, which stores the
4847 default templates for posters and badges
4850 def indexConf(self
):
4854 admin
= User
.find_first(is_admin
=True)
4856 raise MaKaCError(_("""There are no admin users. The "default" conference that stores the template cannot be created.
4857 Please add at least 1 user to the admin list."""))
4858 Conference
.__init
__(self
, admin
.as_avatar
, "default")
4861 class ConferenceHolder( ObjectHolder
):
4862 """Specialised ObjectHolder dealing with conference objects. It gives a
4863 common entry point and provides simple methods to access and
4864 maintain the collection of stored conferences (DB).
4866 idxName
= "conferences"
4867 counterName
= "CONFERENCE"
4870 id = ObjectHolder
._newId
( self
)
4873 def getById( self
, id, quiet
=False ):
4874 """returns an object from the index which id corresponds to the one
4878 if (id == "default"):
4879 return CategoryManager().getDefaultConference()
4883 if self
._getIdx
().has_key(str(id)):
4884 return self
._getIdx
()[str(id)]
4888 raise NotFoundError(_("The event with id '{}' does not exist or has been deleted").format(id),
4889 title
=_("Event not found"))
4892 class Observer(object):
4893 """ Base class for Observer objects.
4894 Inheriting classes should overload the following boolean class attributes:
4895 _shouldBeTitleNotified
4896 _shouldBeDateChangeNotified
4897 _shouldBeLocationChangeNotified
4898 _shouldBeDeletionNotified
4899 And set them to True if they want to be notified of the corresponding event.
4900 In that case, they also have to implement the corresponding methods:
4901 _notifyTitleChange (for title notification)
4902 _notifyEventDateChanges and _notifyTimezoneChange (for date / timezone notification)
4903 _shouldBeLocationChangeNotified (for location notification)
4904 _notifyDeletion (for deletion notification).
4905 The interface for those methods is also specified in this class. If the corresponding
4906 class attribute is set to False but the method is not implemented, an exception will be thrown.
4908 _shouldBeTitleNotified
= False
4909 _shouldBeDateChangeNotified
= False
4910 _shouldBeLocationChangeNotified
= False
4911 _shouldBeDeletionNotified
= False
4913 def getObserverName(self
):
4914 name
= "'Observer of class" + self
.__class
__.__name
__
4916 conf
= self
.getOwner()
4917 name
= name
+ " of event " + conf
.getId() + "'"
4918 except AttributeError:
4922 def notifyTitleChange(self
, oldTitle
, newTitle
):
4923 if self
._shouldBeTitleNotified
:
4924 self
._notifyTitleChange
(oldTitle
, newTitle
)
4926 def notifyEventDateChanges(self
, oldStartDate
= None, newStartDate
= None, oldEndDate
= None, newEndDate
= None):
4927 if self
._shouldBeDateChangeNotified
:
4928 self
._notifyEventDateChanges
(oldStartDate
, newStartDate
, oldEndDate
, newEndDate
)
4930 def notifyTimezoneChange(self
, oldTimezone
, newTimezone
):
4931 if self
._shouldBeDateChangeNotified
:
4932 self
._notifyTimezoneChange
(oldTimezone
, newTimezone
)
4934 def notifyLocationChange(self
, newLocation
):
4935 if self
._shouldBeLocationChangeNotified
:
4936 self
._notifyLocationChange
(newLocation
)
4938 def notifyDeletion(self
):
4939 if self
._shouldBeDeletionNotified
:
4940 self
._notifyDeletion
()
4942 def _notifyTitleChange(self
, oldTitle
, newTitle
):
4943 """ To be implemented by inheriting classes
4944 Notifies the observer that the Conference object's title has changed
4946 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method _notifyTitleChange")
4948 def _notifyEventDateChanges(self
, oldStartDate
, newStartDate
, oldEndDate
, newEndDate
):
4949 """ To be implemented by inheriting classes
4950 Notifies the observer that the start and / or end dates of the object it is attached to has changed.
4951 If the observer finds any problems during whatever he needs to do as a consequence of
4952 the event dates changing, he should write strings describing the problems
4953 in the 'dateChangeNotificationProblems' context variable (which is a list of strings).
4955 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyStartDateChange")
4957 def _notifyTimezoneChange(self
, oldTimezone
, newTimezone
):
4958 """ To be implemented by inheriting classes.
4959 Notifies the observer that the end date of the object it is attached to has changed.
4960 This method has to return a list of strings describing problems encountered during
4961 whatever the DateChangeObserver object does as a consequence of the notification.
4962 If there are no problems, the DateChangeObserver should return an empty list.
4964 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyTimezoneChange")
4966 def _notifyLocationChange(self
):
4967 """ To be implemented by inheriting classes
4968 Notifies the observer that the location of the object it is attached to has changed.
4970 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyLocationChange")
4972 def _notifyDeletion(self
):
4973 """ To be implemented by inheriting classes
4974 Notifies the observer that the Conference object it is attached to has been deleted
4976 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyDeletion")
4978 class TitleChangeObserver(Observer
):
4979 """ Base class for objects who want to be notified of a Conference object being deleted.
4980 Inheriting classes have to implement the notifyTitleChange method, and probably the __init__ method too.
4983 def notifyTitleChange(self
, oldTitle
, newTitle
):
4984 """ To be implemented by inheriting classes
4985 Notifies the observer that the Conference object's title has changed
4987 raise MaKaCError("Class " + str(self
.__class
__.__name
__) + " did not implement method notifyTitleChange")
4990 class SessionChair(ConferenceParticipation
):
4995 ConferenceParticipation
.__init
__(self
)
4997 def _notifyModification( self
):
4998 if self
._session
!= None:
4999 self
._session
.notifyModification()
5002 chair
= SessionChair()
5003 chair
.setValues(self
.getValues())
5006 def getSession(self
):
5007 return self
._session
5009 def getConference(self
):
5013 return s
.getConference()
5015 def includeInSession(self
,session
,id):
5016 if self
.getSession()==session
and self
.getId()==id.strip():
5018 self
._session
=session
5023 ConferenceParticipation
.delete(self
)
5025 def getLocator(self
):
5026 if self
.getSession() is None:
5028 loc
=self
.getSession().getLocator()
5029 loc
["convId"]=self
.getId()
5032 def isSessionManager(self
):
5034 if self
.getEmail() in self
._session
.getAccessController().getModificationEmail():
5037 for manager
in self
._session
.getManagerList():
5038 if self
.getEmail() == manager
.getEmail():
5042 def isSessionCoordinator(self
):
5043 # pendings coordinators
5044 if self
.getEmail() in self
._session
.getConference().getPendingQueuesMgr().getPendingCoordinatorsKeys():
5047 for coord
in self
._session
.getCoordinatorList():
5048 if self
.getEmail() == coord
.getEmail():
5053 class SlotChair(ConferenceParticipation
):
5058 ConferenceParticipation
.__init
__(self
)
5060 def _notifyModification( self
):
5061 if self
._slot
!= None:
5062 self
._slot
.notifyModification()
5066 chair
.setValues(self
.getValues())
5072 def getSession(self
):
5076 return s
.getSession()
5078 def getConference(self
):
5082 return s
.getConference()
5084 def includeInSlot(self
,slot
,id):
5085 if self
.getSlot()==slot
and self
.getId()==id.strip():
5092 ConferenceParticipation
.delete(self
)
5094 def getLocator(self
):
5095 if self
.getSlot() is None:
5097 loc
=self
.getSlot().getLocator()
5098 loc
["convId"]=self
.getId()
5101 class SessionCoordinatorRights
:
5104 self
._rights
= {"modifContribs": "Modify the contributions",
5105 "unrestrictedSessionTT": "Unrestricted session timetable management"
5108 def hasRight(self
, r
):
5109 return self
._rights
.has_key(r
)
5111 def getRights(self
):
5114 def getRightList(self
, sort
=False):
5115 l
=self
._rights
.values()
5120 def getRightKeys(self
):
5121 return self
._rights
.keys()
5123 def getRight(self
, id):
5124 if self
._rights
.has_key(id):
5125 return self
._rights
[id]
5128 class SCIndex(Persistent
):
5129 """Index for conference session coordinators.
5131 This class allows to index conference session coordinators so the owner
5132 can answer optimally to the query if a user is coordinating
5133 any conference session.
5134 It is implemented by simply using a BTree where the Avatar id is used
5135 as key (because it is unique and non variable) and a list of
5136 coordinated sessions is kept as keys. It is the responsability of the
5137 index owner (conference) to keep it up-to-date i.e. notify session
5138 coordinator additions and removals.
5141 def __init__( self
):
5145 def getSessions(self
,av
):
5146 """Gives a list with the sessions a user is coordinating.
5150 return self
._idx
.get(av
.getId(),[])
5152 def index(self
,av
,session
):
5153 """Registers in the index a coordinator of a session.
5155 if av
== None or session
== None:
5157 if not self
._idx
.has_key(av
.getId()):
5159 self
._idx
[av
.getId()]=l
5161 l
=self
._idx
[av
.getId()]
5162 if session
not in l
:
5164 self
.notifyModification()
5166 def unindex(self
,av
,session
):
5167 if av
==None or session
==None:
5169 l
=self
._idx
.get(av
.getId(),[])
5172 self
.notifyModification()
5174 def notifyModification(self
):
5175 self
._idx
._p
_changed
=1
5178 class Session(CommonObjectBase
, Locatable
):
5179 """This class implements a conference session, being the different parts
5180 in which the conference can be divided and the contributions can be
5181 organised in. The class contains necessary attributes to store session
5182 basic data and provides the operations related to sessions. In
5183 principle, a session has no sense to exist without being related to a
5184 conference but it is allowed for flexibility.
5187 fossilizes(ISessionFossil
)
5190 def __init__(self
, **sessionData
):
5191 """Class constructor. Initialise the class attributes to the default
5194 sessionData -- (Dict) Contains the data the session object has to
5197 self
.conference
=None
5198 self
.id="not assigned"
5201 #################################
5202 # Fermi timezone awareness #
5203 #################################
5204 self
.startDate
= nowutc()
5205 #################################
5206 # Fermi timezone awareness(end) #
5207 #################################
5209 self
.duration
=timedelta(minutes
=1)
5212 self
.conveners
=[] # This attribute must not be used and should disappear someday
5214 self
._convenerGen
=Counter()
5215 self
.convenerText
=""
5216 self
.contributions
={}
5217 self
._contributionDuration
=timedelta(minutes
=20)
5218 self
.__ac
=AccessController(self
)
5220 self
.__materialGenerator
=Counter()
5224 self
.__slotGenerator
=Counter()
5226 self
._coordinators
=OOBTree()
5227 self
._coordinatorsEmail
= []
5229 self
._color
="#e3f2d3"
5230 self
._textColor
="#202020"
5231 self
._textColorToLinks
=False
5232 self
._ttType
=SlotSchTypeFactory
.getDefaultId()
5233 self
._closed
= False
5234 self
._registrationSession
= None
5235 self
._creationDS
= nowutc()
5236 self
._modificationDS
= nowutc()
5239 def __cmp__(self
, other
):
5240 if type(self
) is not type(other
):
5241 # This is actually dangerous and the ZODB manual says not to do this
5242 # because it relies on memory order. However, this branch should never
5243 # be taken anyway since we do not store different types in the same set
5244 # or use them as keys.
5245 return cmp(hash(self
), hash(other
))
5246 if self
.getConference() == other
.getConference():
5247 return cmp(self
.getId(), other
.getId())
5248 return cmp(self
.getConference(), other
.getConference())
5250 def getVerboseType(self
):
5253 def getTimezone( self
):
5254 return self
.getConference().getTimezone()
5256 def updateNonInheritingChildren(self
, elem
, delete
=False, propagate
=True):
5257 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
5258 if propagate
== True:
5259 self
.notify_protection_to_owner(elem
, delete
)
5261 def notify_protection_to_owner(self
, elem
, delete
=False):
5262 """ This methods notifies the owner that the protection has been changed,
5263 so it can update its list of non inheriting children """
5264 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
5266 def getKeywords(self
):
5268 return self
._keywords
5273 def setKeywords(self
, keywords
):
5274 self
._keywords
= keywords
5276 def notifyModification( self
, raiseEvent
= True, date
= None, cleanCache
= True ):
5277 """Method called to notify the current session has been modified.
5279 self
.setModificationDate(date
)
5281 parent
= self
.getConference()
5283 parent
.setModificationDate(date
)
5285 for slot
in self
.getSlotList():
5289 def getModificationDate( self
):
5290 """Returns the date in which the session was last modified"""
5292 return self
._modificationDS
5294 self
._modificationDS
= nowutc()
5295 return self
._modificationDS
5297 def getCreationDate( self
):
5298 """Returns the date in which the session was created"""
5300 return self
._creationDS
5302 self
._creationDS
= nowutc()
5303 return self
._creationDS
5305 def getLogInfo(self
):
5307 data
["subject"] = self
.title
5308 data
["session id"] = self
.id
5309 data
["session code"] = self
._code
5310 data
["title"] = self
.title
5311 data
["description"] = self
.description
5312 data
["start date"] = self
.startDate
5313 data
["duration"] = self
.duration
5314 for p
in self
.places
:
5315 data
["place"] = p
.getName()
5316 for r
in self
.rooms
:
5317 data
["room"] = r
.getName()
5318 for sc
in self
.getConvenerList() :
5319 data
["convener %s"%sc.getId()] = sc
.getFullName()
5320 for co
in self
.getCoordinatorList() :
5321 data
["coordinators %s"%co.getId()] = co
.getFullName()
5325 def getEnableSessionSlots(self
):
5327 return self
.getConference().getEnableSessionSlots()
5331 def cmpSessionByTitle(session1
, session2
):
5332 return cmp(session1
.getTitle(), session2
.getTitle())
5333 cmpSessionByTitle
= staticmethod(cmpSessionByTitle
)
5335 def hasRegistrationSession(self
):
5336 return self
.getRegistrationSession() is not None
5338 def getRegistrationSession(self
):
5340 if self
._registrationSession
:
5342 except AttributeError, e
:
5343 self
._registrationSession
= None
5344 return self
._registrationSession
5346 def setRegistrationSession(self
, rs
):
5347 self
._registrationSession
= rs
5349 def isClosed( self
):
5350 if self
.getConference().isClosed():
5355 self
._closed
= False
5358 def setClosed( self
, closed
=True ):
5359 self
._closed
= closed
5360 self
.notifyModification(cleanCache
= False)
5362 def includeInConference(self
,conf
,newId
):
5363 self
.conference
=conf
5365 for slot
in self
.getSlotList():
5366 conf
.getSchedule().addEntry(slot
.getConfSchEntry(),2)
5367 self
.getConference().addSession(self
)
5368 self
.notifyModification()
5371 while len(self
.getConvenerList()) > 0:
5372 self
.removeConvener(self
.getConvenerList()[0])
5373 while len(self
.getMaterialList()) > 0:
5374 self
.removeMaterial(self
.getMaterialList()[0])
5375 self
.removeMinutes()
5376 for c
in self
.getCoordinatorList()[:]:
5377 self
.removeCoordinator(c
)
5378 while len(self
.contributions
.values())>0:
5379 self
.removeContribution(self
.contributions
.values()[0])
5380 while len(self
.slots
.values())>0:
5381 self
._removeSlot
(self
.slots
.values()[0])
5382 if self
.getConference() is not None:
5383 self
.getConference().removeSession(self
)
5384 if self
.hasRegistrationSession():
5385 self
.getConference().getRegistrationForm().getSessionsForm().removeSession(self
.getId())
5386 self
.getRegistrationSession().setRegistrationForm(None)
5387 TrashCanManager().add(self
.getRegistrationSession())
5388 self
.notify_protection_to_owner(self
, delete
=True)
5389 self
.conference
=None
5390 TrashCanManager().add(self
)
5392 def recover(self
, isCancelled
):
5393 if self
.hasRegistrationSession():
5395 self
.getRegistrationSession().setRegistrationForm(self
.getConference().getRegistrationForm())
5396 self
.getConference().getRegistrationForm().getSessionsForm().addSession(self
.getRegistrationSession())
5397 TrashCanManager().remove(self
.getRegistrationSession())
5398 TrashCanManager().remove(self
)
5400 def getLocator( self
):
5401 """Gives back a globaly unique identification encapsulated in a Locator
5402 object for the session instance
5404 if self
.conference
== None:
5406 lconf
= self
.conference
.getLocator()
5407 lconf
["sessionId"] = self
.getId()
5410 def getConference( self
):
5411 return self
.conference
5413 def getSession( self
):
5416 def getOwner( self
):
5417 return self
.getConference()
5422 def getUniqueId( self
):
5423 """returns (string) the unique identiffier of the item"""
5424 """used mainly in the web session access key table"""
5425 return "%ss%s" % (self
.getConference().getUniqueId(),self
.id)
5427 def getModifKey( self
):
5428 return self
.getConference().getModifKey()
5430 def getAccessKey( self
):
5431 return self
.getConference().getAccessKey()
5433 def getContribDuration(self
):
5435 return self
._contributionDuration
5437 self
._contributionDuration
= timedelta(minutes
=20)
5438 return self
._contributionDuration
5440 def setContribDuration(self
, hour
=0, min=20, dur
=None):
5442 self
._contributionDuration
=dur
5444 self
._contributionDuration
= timedelta(hours
=hour
,minutes
=min)
5447 #if not self.getConference().getEnableSessionSlots():
5448 # self.getSlotList()[0].fit()
5449 self
.setStartDate(self
.getMinSlotStartDate(),0,0)
5450 self
.setEndDate(self
.getMaxSlotEndDate(),0)
5452 def addSlot(self
,newSlot
):
5453 id = newSlot
.getId()
5454 if id == "not assigned":
5455 newSlot
.setId(str(self
.__slotGenerator
.newCount()))
5456 self
.slots
[newSlot
.getId()]=newSlot
5458 self
.getSchedule().addEntry(newSlot
.getSessionSchEntry(),2)
5459 if self
.getConference() is not None:
5460 self
.getConference().getSchedule().addEntry(newSlot
.getConfSchEntry(),2)
5461 self
.notifyModification()
5463 def _removeSlot(self
,slot
):
5464 del self
.slots
[slot
.getId()]
5465 self
.getSchedule().removeEntry(slot
.getSessionSchEntry())
5466 if self
.getConference() is not None:
5467 self
.getConference().getSchedule().removeEntry(slot
.getConfSchEntry())
5470 def removeSlot(self
, slot
, force
=False):
5471 if self
.slots
.has_key(slot
.getId()):
5472 if len(self
.slots
)==1 and not force
:
5473 raise MaKaCError( _("A session must have at least one slot"), _("Session"))
5474 self
._removeSlot
(slot
)
5476 self
.notifyModification()
5478 def recoverSlot(self
, slot
):
5482 def getSlotById(self
,slotId
):
5483 return self
.slots
.get(slotId
,None)
5485 def getSlotList(self
):
5486 return self
.slots
.values()
5488 def getSortedSlotList(self
):
5489 sl
= self
.getSlotList()
5490 sl
.sort(utils
.sortSlotByDate
)
5493 def getMinSlotStartTime(self
):
5495 for slot
in self
.getSlotList():
5496 if slot
.isMoreThanDay():
5498 shour
= slot
.getStartDate().hour
5499 smin
= slot
.getStartDate().minute
5500 if (shour
, smin
) < min:
5504 def getMaxSlotEndTime(self
):
5506 for slot
in self
.getSlotList():
5507 if slot
.isMoreThanDay():
5509 endDate
= slot
.getEndDate()
5510 if (endDate
.hour
, endDate
.minute
) > max:
5511 newEndDate
= endDate
- timedelta(0, 0, 0)
5512 max = (newEndDate
.hour
, newEndDate
.minute
)
5515 def getMinSlotStartDate(self
):
5516 slotList
= self
.getSlotList()
5517 if len(slotList
)==0:
5518 return self
.getStartDate()
5520 sDate
= self
.getEndDate()
5521 for slot
in slotList
:
5522 if slot
.getStartDate() < sDate
:
5523 sDate
= slot
.getStartDate()
5526 def getMaxSlotEndDate(self
):
5527 slotList
= self
.getSlotList()
5528 if len(slotList
)==0:
5529 return self
.getEndDate()
5531 eDate
= self
.getStartDate()
5532 for slot
in slotList
:
5533 if slot
.getEndDate() > eDate
:
5534 eDate
= slot
.getEndDate()
5537 def _getCorrectColor(self
, color
):
5538 if not color
.startswith("#"):
5540 m
= re
.match("^#[0-9A-Fa-f]{6}$", color
)
5545 def _getCorrectBgColor(self
, color
):
5546 color
=self
._getCorrectColor
(color
)
5551 def _getCorrectTextColor(self
, color
):
5552 color
=self
._getCorrectColor
(color
)
5554 return self
._textColor
5557 def setValues( self
, sessionData
,check
=2,moveEntries
=0 ):
5558 """Sets all the values of the current session object from a dictionary
5559 containing the following key-value pairs:
5562 locationName-(str) => name of the location, if not specified
5563 it will be set to the conference location name.
5564 locationAddress-(str)
5565 roomName-(str) => name of the room, if not specified it will
5566 be set to the conference room name.
5567 sDate - (datetime) => starting date of the session, if not
5568 specified it will be set to now.
5569 eDate - (datetime) => ending date of the session, if not
5570 specified the end date will be set to the start one
5571 durHour - (int) => hours of duration for each entry in the session
5573 durMin - (int) => hours of duration for each entry in the session
5578 1: check and raise error in case of problem
5579 2: check and adapt the owner dates
5580 Please, note that this method sets ALL values which means that if
5581 the given dictionary doesn't contain any of the keys the value
5582 will set to a default value.
5585 self
.setTitle( sessionData
.get("title", "NO TITLE ASSIGNED") )
5586 self
.setDescription( sessionData
.get("description", "") )
5587 code
= sessionData
.get("code", "")
5588 if code
.strip() == "":
5589 if self
.getId()=="not assigned":
5590 self
.setCode("no code")
5592 self
.setCode(self
.getId())
5595 bgcolor
= sessionData
.get("backgroundColor", "")
5596 if bgcolor
.strip() != "":
5597 self
.setColor(self
._getCorrectBgColor
(bgcolor
))
5598 textcolor
= sessionData
.get("textColor", "")
5599 if textcolor
.strip() != "":
5600 if sessionData
.has_key("autotextcolor"):
5601 self
.setTextColor(utils
.getTextColorFromBackgroundColor(self
.getColor()))
5603 self
.setTextColor(self
._getCorrectTextColor
(textcolor
))
5604 self
.setTextColorToLinks(sessionData
.has_key("textcolortolinks"))
5606 if "locationName" in sessionData
:
5607 loc
= self
.getOwnLocation()
5609 loc
= CustomLocation()
5610 self
.setLocation( loc
)
5611 loc
.setName( sessionData
["locationName"] )
5612 loc
.setAddress( sessionData
.get("locationAddress", "") )
5614 self
.setLocation(None)
5616 #same as for the location
5617 if "roomName" in sessionData
:
5618 room
= self
.getOwnRoom()
5621 self
.setRoom( room
)
5622 room
.setName( sessionData
["roomName"] )
5626 if sessionData
.get("sDate",None) is not None:
5627 self
.setStartDate(sessionData
["sDate"],check
,moveEntries
=moveEntries
)
5628 if sessionData
.get("eDate",None) is not None:
5629 self
.setEndDate(sessionData
["eDate"],check
)
5630 self
._checkInnerSchedule
()
5631 if sessionData
.get("contribDuration","")!="":
5632 self
._contributionDuration
= sessionData
.get("contribDuration")
5634 self
._contributionDuration
= timedelta(hours
=int(sessionData
.get("durHour",0)), minutes
=int(sessionData
.get("durMin",20)))
5635 self
.notifyModification()
5637 def move(self
, sDate
):
5639 Move a session from the old start date to a new start date, and
5640 it moves all the entries of the session as well, without date validations.
5642 if sDate
is not None:
5643 oldStartDate
=self
.startDate
5644 self
.startDate
=copy
.copy(sDate
)
5645 diff
=self
.startDate
-oldStartDate
5646 # Check date to not be prior conference start date and to not surpass conference end date
5647 # The schedule is returning the datetime object as timezone aware relative to the conference
5648 # timezone. Must adjust the startdate accordingly for comparison. JMF
5649 conftz
= self
.getConference().getTimezone()
5650 if self
.getStartDate() < self
.getConference().getSchedule().getStartDate() or \
5651 self
.getEndDate() > self
.getConference().getSchedule().getEndDate():
5652 raise MaKaCError( _("Impossible to move the session because it would be out of the conference dates"))
5653 for entry
in self
.getSchedule().getEntries():
5654 if isinstance(entry
,LinkedTimeSchEntry
) and \
5655 isinstance(entry
.getOwner(), SessionSlot
):
5656 e
= entry
.getOwner()
5657 e
.move(e
.getStartDate() + diff
)
5658 self
.getSchedule().reSchedule()
5659 self
.getConference().getSchedule().reSchedule()
5660 self
.notifyModification()
5662 def clone(self
, deltaTime
, conf
, options
, session_id
=None):
5664 conf
.addSession(ses
, check
=0, id=session_id
)
5665 ses
.setTitle(self
.getTitle())
5666 ses
.setDescription(self
.getDescription())
5667 startDate
= self
.getStartDate() + deltaTime
5668 ses
.setStartDate(startDate
, check
=1)
5669 ses
.setDuration(dur
=self
.getDuration())
5671 if self
.getOwnLocation() is not None:
5672 ses
.addLocation(self
.getOwnLocation().clone())
5673 if self
.getOwnRoom() is not None:
5674 ses
.setRoom(self
.getOwnRoom().clone())
5675 ses
.setColor(self
.getColor())
5676 ses
.setTextColor(self
.getTextColor())
5677 ses
.setTextColorToLinks(self
.isTextColorToLinks())
5678 ses
.setCode(self
.getCode())
5679 ses
.setContribDuration(dur
=self
.getContribDuration())
5680 ses
.setScheduleType(self
.getScheduleType())
5681 ses
.setComments(self
.getComments())
5683 # Access Control cloning
5684 if options
.get("access", False) :
5685 ses
.setProtection(self
.getAccessController()._getAccessProtection
())
5686 for mgr
in self
.getManagerList() :
5687 ses
.grantModification(mgr
)
5688 for user
in self
.getAllowedToAccessList() :
5689 ses
.grantAccess(user
)
5690 for domain
in self
.getDomainList():
5691 ses
.requireDomain(domain
)
5692 for coord
in self
.getCoordinatorList():
5693 ses
.addCoordinator(coord
)
5695 #slots in timeschedule
5696 for slot
in self
.getSlotList() :
5697 newslot
= slot
.clone(ses
, options
)
5698 ses
.addSlot(newslot
)
5699 ContextManager
.setdefault("clone.unique_id_map", {})[slot
.getUniqueId()] = newslot
.getUniqueId()
5701 ses
.notifyModification()
5706 def setTitle( self
, newTitle
):
5707 self
.title
= newTitle
5708 self
.notifyModification()
5710 def getTitle( self
):
5713 def setDescription(self
, newDescription
):
5714 self
.description
= newDescription
5715 self
.notifyModification()
5717 def getDescription(self
):
5718 return self
.description
5724 except AttributeError:
5728 def setCode(self
,newCode
):
5729 self
._code
=str(newCode
).strip()
5735 except AttributeError:
5736 self
._color
="#e3f2d3"
5740 def setColor(self
,newColor
):
5741 self
._color
=str(newColor
).strip()
5742 self
.notifyModification()
5745 def getTextColor(self
):
5749 except AttributeError:
5750 self
._textColor
="#202020"
5751 return self
._textColor
5753 def setTextColor(self
,newColor
):
5754 self
._textColor
=str(newColor
).strip()
5755 self
.notifyModification()
5757 def isTextColorToLinks(self
):
5759 if self
._textColorToLink
:
5761 except AttributeError:
5762 self
._textColorToLink
=False
5763 return self
._textColorToLink
5765 def setTextColorToLinks(self
, v
):
5766 self
._textColorToLink
=v
5767 self
.notifyModification()
5769 def getStartDate(self
):
5770 return self
.startDate
5772 def getAdjustedStartDate(self
,tz
=None):
5774 tz
= self
.getConference().getTimezone()
5775 if tz
not in all_timezones
:
5777 return self
.startDate
.astimezone(timezone(tz
))
5779 def verifyStartDate(self
, sdate
, check
=2):
5782 1: check and raise error in case of problem (default)
5783 2: check and adapt the owner dates
5786 conf
=self
.getConference()
5788 if conf
is not None and sdate
< conf
.getSchedule().getStartDate():
5790 raise ParentTimingError( _("The session starting date cannot be prior to the event starting date"), _("Session"))
5792 ContextManager
.get('autoOps').append((self
, "OWNER_START_DATE_EXTENDED",
5793 conf
, sdate
.astimezone(timezone(conf
.getTimezone()))))
5794 conf
.setStartDate(sdate
,check
=0,moveEntries
=0)
5796 def setStartDate(self
,newDate
,check
=2,moveEntries
=0):
5798 moveEntries parameter:
5799 0: do not move inner slots
5801 2: do not move but check that session is not out of the conference dates
5804 if not newDate
.tzname():
5805 raise MaKaCError("date should be timezone aware")
5807 self
.verifyStartDate(newDate
,check
)
5808 oldSdate
= self
.getStartDate()
5810 tz
= str(self
.getStartDate().tzinfo
)
5813 diff
= newDate
- oldSdate
5814 self
.startDate
=copy
.copy(newDate
)
5815 if moveEntries
== 1 and diff
is not None and diff
!= timedelta(0):
5816 # If the start date changed, we move entries inside the timetable
5817 newDateTz
= newDate
.astimezone(timezone(tz
))
5818 if oldSdate
.astimezone(timezone(tz
)).date() != newDateTz
.date():
5819 entries
= self
.getSchedule().getEntries()[:]
5821 entries
= self
.getSchedule().getEntriesOnDay(newDateTz
)[:]
5822 self
.getSchedule().moveEntriesBelow(diff
, entries
)
5824 if moveEntries
!= 0 and self
.getConference() and \
5825 not self
.getConference().getEnableSessionSlots() and \
5826 self
.getSlotList() != [] and \
5827 self
.getSlotList()[0].getStartDate() != newDate
:
5828 self
.getSlotList()[0].startDate
= newDate
5831 self
._checkInnerSchedule
()
5832 self
.notifyModification()
5834 def _checkInnerSchedule( self
):
5835 self
.getSchedule().checkSanity()
5837 def getEndDate(self
):
5838 return self
.startDate
+self
.duration
5840 ####################################
5841 # Fermi timezone awareness #
5842 ####################################
5844 def getAdjustedEndDate(self
,tz
=None):
5845 return self
.getAdjustedStartDate(tz
) + self
.duration
5847 ####################################
5848 # Fermi timezone awareness(end) #
5849 ####################################
5851 def verifyEndDate(self
, edate
,check
=1):
5854 1: check and raise error in case of problem
5855 2: check and adapt the owner dates
5858 tz
= timezone(self
.getConference().getTimezone())
5860 tz
= timezone('UTC')
5861 # compare end date with start date
5862 if edate
<=self
.getStartDate():
5864 raise MaKaCError( _("End date cannot be prior to the Start date"), _("Session"))
5866 self
.setStartDate(edate
)
5867 # check conference dates
5868 if (self
.getConference()):
5869 conf
=self
.getConference()
5870 confStartDate
= conf
.getSchedule().getStartDate()
5871 confEndDate
= conf
.getSchedule().getEndDate()
5872 if conf
is not None and (edate
>confEndDate
or edate
<=confStartDate
):
5874 raise ParentTimingError( _("The end date has to be between the event dates (%s - %s)")%\
5875 (confStartDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
5876 confEndDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
5879 if edate
>confEndDate
:
5880 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
5881 self
.getConference(),
5882 edate
.astimezone(tz
)))
5883 self
.getConference().setEndDate(edate
)
5884 if edate
<=confStartDate
:
5885 ContextManager
.get('autoOps').append((self
, "OWNER_START_DATE_EXTENDED",
5886 self
.getConference(),
5887 edate
.astimezone(tz
)))
5888 self
.getConference().setStartDate(edate
)
5889 # check inner schedule
5890 if len(self
.getSlotList()) != 0 and self
.getSlotList()[-1].getSchedule().hasEntriesAfter(edate
):
5891 raise TimingError( _("Cannot change end date: some entries in the session schedule end after the new date"), _("Session"))
5893 def setEndDate(self
,newDate
,check
=2):
5894 if not newDate
.tzname():
5895 raise MaKaCError("date should be timezone aware")
5897 self
.verifyEndDate(newDate
,check
)
5898 self
.duration
=newDate
-self
.getStartDate()
5899 # A session is not always linked to a conference (for eg. at creation time)
5900 #if self.getConference() and not self.getConference().getEnableSessionSlots() and self.getSlotList()[0].getEndDate() != newDate:
5901 # self.getSlotList()[0].duration = self.duration
5902 self
.notifyModification()
5904 def setDates(self
, sDate
, eDate
, check
=1, moveEntries
=0):
5906 tz
= timezone(self
.getConference().getTimezone())
5907 raise FormValuesError(_("The end date ({}) cannot be prior to the start date ({})").format(
5908 eDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'), sDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M')),
5910 self
.setStartDate(sDate
, check
, moveEntries
)
5911 self
.setEndDate(eDate
, check
)
5912 self
._checkInnerSchedule
()
5914 def getDuration(self
):
5915 return self
.duration
5917 def setDuration(self
, hours
=0, minutes
=15, dur
=0):
5919 dur
= timedelta(hours
=int(hours
), minutes
=int(minutes
))
5920 if dur
.seconds
<= 0:
5921 raise FormValuesError(_("The duration cannot be less than zero"), _("Session"))
5923 self
.verifyEndDate(self
.getEndDate())
5924 self
.notifyModification()
5926 def getStartOnDay(self
, day
, tz
=None):
5928 tz
= self
.getConference().getTimezone()
5929 if type(day
) is datetime
:
5930 day
= day
.astimezone(timezone(tz
))
5931 if day
.date() < self
.getStartDate().astimezone(timezone(tz
)).date() or day
.date() > self
.getEndDate().astimezone(timezone(tz
)).date() :
5933 minTime
= self
.getEndDate()
5934 for e
in self
.getSchedule().getEntriesOnDay(day
) :
5935 if e
.getStartDate() < minTime
:
5936 minTime
= e
.getStartDate()
5937 if minTime
== self
.getEndDate() :
5938 minTime
= day
.replace(hour
=8, minute
=0)#datetime.combine(day,time(hour=8, minute=0))
5939 if minTime
< self
.getStartDate() :
5940 return self
.getStartDate()
5943 def getEndOnDay(self
, day
, tz
=None):
5945 tz
= self
.getConference().getTimezone()
5946 if type(day
) is datetime
:
5947 day
= day
.astimezone(timezone(tz
))
5948 if day
.date() < self
.getStartDate().astimezone(timezone(tz
)).date() or day
.date() > self
.getEndDate().astimezone(timezone(tz
)).date() :
5950 maxTime
= self
.getStartDate();
5951 for e
in self
.getSchedule().getEntriesOnDay(day
) :
5952 if e
.getEndDate() > maxTime
:
5953 maxTime
= e
.getEndDate()
5954 if maxTime
== self
.getStartDate() :
5955 maxTime
= day
.replace(hour
=19, minute
=0)#datetime.combine(day,time(19,0))
5956 if maxTime
> self
.getEndDate() :
5957 return self
.getEndDate()
5960 def getLocationParent( self
):
5962 Returns the object from which the room/location
5963 information should be inherited
5965 return self
.getConference()
5967 def getLocationList(self
):
5968 """Method returning a list of "location" objects which contain the
5969 information about the different places the conference is gonna
5974 def addLocation(self
, newPlace
):
5975 self
.places
.append( newPlace
)
5976 self
.notifyModification()
5978 def _resetConveners(self
):
5982 except AttributeError:
5984 for oc
in self
.conveners
:
5985 newConv
=SessionChair()
5986 newConv
.setDataFromAvatar(oc
)
5987 self
._addConvener
(newConv
)
5989 def getConvenerList(self
):
5990 self
._resetConveners
()
5991 return self
._conveners
5993 def getAllConvenerList(self
):
5994 convenerList
= set()
5995 for slot
in self
.getSlotList():
5996 for convener
in slot
.getConvenerList():
5997 convenerList
.add(convener
)
6000 def _addConvener(self
,newConv
):
6001 if newConv
in self
._conveners
:
6004 if self
._convenerGen
:
6006 except AttributeError:
6007 self
._convenerGen
=Counter()
6008 id = newConv
.getId()
6010 id=int(self
._convenerGen
.newCount())
6011 newConv
.includeInSession(self
,id)
6012 self
._conveners
.append(newConv
)
6013 self
.notifyModification()
6015 def addConvener(self
,newConv
):
6016 self
._resetConveners
()
6017 self
._addConvener
(newConv
)
6018 if isinstance(newConv
, AvatarUserWrapper
):
6019 conv
.unlinkTo(self
, "convener")
6021 def removeConvener(self
,conv
):
6022 self
._resetConveners
()
6023 if conv
not in self
._conveners
:
6025 #--Pending queue: remove pending Convener waiting to became manager if anything
6026 self
.getConference().getPendingQueuesMgr().removePendingManager(conv
)
6028 #--Pending queue: remove pending Convener waiting to became coordinator if anything
6029 self
.getConference().getPendingQueuesMgr().removePendingCoordinator(conv
)
6031 self
._conveners
.remove(conv
)
6032 if isinstance(conv
, AvatarUserWrapper
):
6033 conv
.linkTo(self
, "convener")
6035 self
.notifyModification()
6037 def recoverConvener(self
, con
):
6038 self
.addConvener(con
)
6041 def getConvenerById(self
,id):
6043 for conv
in self
._conveners
:
6044 if conv
.getId()==id:
6048 def getConvenerText( self
):
6051 if self
.convenerText
:
6053 except AttributeError, e
:
6054 self
.convenerText
= ""
6055 return self
.convenerText
6057 def setConvenerText( self
, newText
):
6058 self
.convenerText
= newText
.strip()
6060 def appendConvenerText( self
, newText
):
6061 self
.setConvenerText( "%s, %s"%(self
.getConvenerText(), newText
.strip()) )
6063 def addContribution(self
, newContrib
, id=None):
6064 """Registers the contribution passed as parameter within the session
6065 assigning it a unique id.
6067 if self
.hasContribution(newContrib
):
6069 self
.getConference().addContribution(newContrib
,id)
6070 self
.contributions
[newContrib
.getId()]=newContrib
6071 newContrib
.setSession(self
)
6073 self
.updateNonInheritingChildren(newContrib
)
6074 for child
in newContrib
.getAccessController().getNonInheritingChildren():
6075 self
.updateNonInheritingChildren(child
)
6077 self
.notifyModification()
6079 def hasContribution(self
,contrib
):
6080 return contrib
.getSession()==self
and \
6081 self
.contributions
.has_key(contrib
.getId())
6083 def removeContribution(self
,contrib
):
6084 """Removes the indicated contribution from the session
6086 if not self
.hasContribution(contrib
):
6088 if contrib
.isScheduled():
6089 # unschedule the contribution
6090 sch
=contrib
.getSchEntry().getSchedule()
6091 sch
.removeEntry(contrib
.getSchEntry())
6092 del self
.contributions
[contrib
.getId()]
6094 self
.updateNonInheritingChildren(contrib
, delete
=True, propagate
=False)
6095 for child
in contrib
.getAccessController().getNonInheritingChildren():
6096 self
.updateNonInheritingChildren(child
, delete
=True, propagate
=False)
6098 contrib
.setSession(None)
6100 self
.notifyModification()
6102 def newContribution( self
, params
= None, id=None ):
6106 self
.addContribution( c
, id )
6109 def getContributionById(self
,id):
6111 if self
.contributions
.has_key( id ):
6112 return self
.contributions
[ id ]
6115 def getContributionList( self
):
6116 return self
.contributions
.values()
6118 def getNumberOfContributions(self
, only_scheduled
=False):
6120 return len(filter(lambda c
: c
.isScheduled(), self
.contributions
.itervalues()))
6122 return len(self
.contributions
)
6124 def isProtected(self
):
6125 # tells if a session is protected or not
6126 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
6128 def getAccessProtectionLevel( self
):
6129 return self
.__ac
.getAccessProtectionLevel()
6131 def isItselfProtected( self
):
6132 return self
.__ac
.isItselfProtected()
6134 def hasAnyProtection( self
):
6135 """Tells whether a session has any kind of protection over it:
6136 access or domain protection.
6138 if self
.__ac
.isProtected():
6140 if self
.getDomainList():
6142 if self
.getAccessProtectionLevel() == -1:
6145 return self
.getOwner().hasAnyProtection()
6147 def hasProtectedOwner( self
):
6148 if self
.getOwner() != None:
6149 return self
.getOwner().isProtected()
6152 def setProtection( self
, private
):
6153 self
.__ac
.setProtection( private
)
6154 self
.notify_protection_to_owner(self
)
6156 def grantAccess( self
, prin
):
6157 self
.__ac
.grantAccess( prin
)
6158 if isinstance(prin
, AvatarUserWrapper
):
6159 prin
.linkTo(self
, "access")
6161 def revokeAccess( self
, prin
):
6162 self
.__ac
.revokeAccess( prin
)
6163 if isinstance(prin
, AvatarUserWrapper
):
6164 prin
.unlinkTo(self
, "access")
6166 def canView( self
, aw
):
6167 """tells whether the specified user has access to the current object
6168 or any of its sub-objects
6170 if self
.canAccess( aw
):
6173 for contrib
in self
.getContributionList():
6174 if contrib
.canView( aw
):
6178 def isAllowedToAccess( self
, user
):
6181 if user
in self
.getCoordinatorList() or self
.__ac
.canUserAccess( user
) \
6182 or self
.canUserModify( user
) or (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess(user
)):
6186 def canAccess( self
, aw
):
6187 # Allow harvesters (Invenio, offline cache) to access
6189 if has_request_context() and self
.__ac
.isHarvesterIP(request
.remote_addr
):
6191 #####################################################
6193 # Managers have always access
6194 if self
.canModify(aw
):
6197 flag_allowed_to_access
= self
.isAllowedToAccess(aw
.getUser())
6198 if not self
.canIPAccess(request
.remote_addr
) and not self
.canUserModify(aw
.getUser()) and \
6199 not flag_allowed_to_access
:
6201 if not self
.isProtected():
6203 return flag_allowed_to_access
or self
.conference
.canKeyAccess(aw
)
6205 def grantModification(self
, sb
, sendEmail
=True):
6206 if isinstance(sb
, SessionChair
) or isinstance(sb
, SlotChair
):
6208 results
= ah
.match({"email": sb
.getEmail()}, exact
=1)
6211 if sb
.getEmail().lower().strip() in [j
.lower().strip() for j
in i
.getEmails()]:
6214 if r
is not None and r
.isActivated():
6215 self
.__ac
.grantModification(r
)
6216 r
.linkTo(self
, "manager")
6217 elif sb
.getEmail() != "":
6218 modificationEmailGranted
= self
.__ac
.grantModificationEmail(sb
.getEmail())
6219 if modificationEmailGranted
and sendEmail
:
6220 notif
= pendingQueues
._PendingManagerNotification
( [sb
] )
6221 mail
.GenericMailer
.sendAndLog( notif
, self
.getConference() )
6223 self
.__ac
.grantModification( sb
)
6224 if isinstance(sb
, AvatarUserWrapper
):
6225 sb
.linkTo(self
, "manager")
6227 def revokeModification( self
, prin
):
6228 self
.__ac
.revokeModification( prin
)
6229 if isinstance(prin
, AvatarUserWrapper
):
6230 prin
.unlinkTo(self
, "manager")
6232 def canModify(self
, aw_or_user
):
6233 if hasattr(aw_or_user
, 'getUser'):
6234 aw_or_user
= aw_or_user
.getUser()
6235 return self
.canUserModify(aw_or_user
) or self
.getConference().canKeyModify()
6237 def canUserModify( self
, av
):
6238 """Tells whether a user is allowed to modify the current session:
6239 only if the user is granted to modify the session or the user
6240 can modify the corresponding conference.
6242 return self
.getConference().canUserModify( av
) or self
.__ac
.canModify( av
)
6244 def getManagerList( self
):
6245 return self
.__ac
.getModifierList()
6247 def getAllowedToAccessList( self
):
6248 return self
.__ac
.getAccessList()
6250 def addMaterial( self
, newMat
):
6251 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
6252 newMat
.setOwner( self
)
6253 self
.materials
[ newMat
.getId() ] = newMat
6254 self
.notifyModification()
6256 def removeMaterial( self
, mat
):
6257 if mat
.getId() in self
.materials
.keys():
6259 self
.materials
[mat
.getId()].setOwner(None)
6260 del self
.materials
[ mat
.getId() ]
6261 self
.notifyModification()
6262 return "done: %s"%mat
.getId()
6263 elif mat
.getId().lower() == 'minutes':
6264 self
.removeMinutes()
6265 return "done: %s"%mat
.getId()
6266 return "not done: %s"%mat
.getId()
6268 def recoverMaterial(self
, recMat
):
6269 # Id must already be set in recMat.
6270 recMat
.setOwner( self
)
6271 self
.materials
[ recMat
.getId() ] = recMat
6273 self
.notifyModification()
6275 def getMaterialRegistry(self
):
6277 Return the correct material registry for this type
6279 from MaKaC
.webinterface
.materialFactories
import SessionMFRegistry
6280 return SessionMFRegistry
6282 def getMaterialById( self
, matId
):
6283 if matId
.lower() == 'minutes':
6284 return self
.getMinutes()
6285 elif self
.materials
.has_key(matId
):
6286 return self
.materials
[ matId
]
6289 def getMaterialList( self
):
6290 return self
.materials
.values()
6292 def getAllMaterialList(self
, sort
=True):
6293 l
= self
.getMaterialList()
6294 if self
.getMinutes():
6295 l
.append( self
.getMinutes() )
6297 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
6300 def _setSchedule(self
):
6301 self
.__schedule
=SessionSchedule(self
)
6302 sl
=self
.getSlotList()
6303 for slot
in self
.getSlotList():
6304 self
.__schedule
.addEntry(slot
.getSchEntry())
6306 def getSchedule( self
):
6308 if self
.__schedule
is None or not isinstance(self
.__schedule
,SessionSchedule
):
6310 except AttributeError, e
:
6312 return self
.__schedule
6314 def getMasterSchedule( self
):
6315 return self
.getOwner().getSchedule()
6317 def requireDomain( self
, dom
):
6318 self
.__ac
.requireDomain( dom
)
6320 def freeDomain( self
, dom
):
6321 self
.__ac
.freeDomain( dom
)
6323 def getDomainList( self
):
6324 return self
.__ac
.getRequiredDomainList()
6326 def setComments(self
,comm
):
6327 self
._comments
= comm
.strip()
6329 def getComments(self
):
6333 except AttributeError,e
:
6335 return self
._comments
6337 def createMinutes( self
):
6338 if self
.getMinutes() != None:
6339 raise MaKaCError( _("The minutes for this session have already been created"), _("Session"))
6340 self
.minutes
= Minutes()
6341 self
.minutes
.setOwner( self
)
6342 self
.notifyModification()
6345 def removeMinutes( self
):
6346 if self
.minutes
is None:
6348 self
.minutes
.delete()
6349 self
.minutes
.setOwner( None )
6351 self
.notifyModification()
6353 def recoverMinutes(self
, min):
6354 self
.removeMinutes() # To ensure that the current minutes are put in
6357 self
.minutes
.setOwner( self
)
6359 self
.notifyModification()
6362 def getMinutes( self
):
6367 except AttributeError, e
:
6372 def _addCoordinator(self
, av
):
6373 if av
is None or self
._coordinators
.has_key(av
.getId()):
6375 self
._coordinators
[av
.getId()]=av
6376 if self
.getConference() is not None:
6377 self
.getConference().addSessionCoordinator(self
,av
)
6379 def getCoordinatorEmailList(self
):
6381 return self
._coordinatorsEmail
6383 self
._coordinatorsEmail
= []
6384 return self
._coordinatorsEmail
6386 def _addCoordinatorEmail(self
, email
):
6387 if email
not in self
.getCoordinatorEmailList():
6388 self
.getCoordinatorEmailList().append(email
)
6390 def removeCoordinatorEmail(self
, email
):
6391 if email
in self
.getCoordinatorEmailList():
6392 self
.getCoordinatorEmailList().remove(email
)
6395 def addCoordinator( self
, sb
, sendEmail
=True ):
6396 """Grants coordination privileges to user.
6399 sb -- It can be either:
6400 (AvatarUserWrapper) the user to which
6401 coordination privileges must be granted.
6403 (MaKaC.conference.SessionChair) a non-existing which
6404 has to become indico user before to be granted with privileges.
6407 if self
._coordinators
:
6409 except AttributeError, e
:
6410 self
._coordinators
=OOBTree()
6412 if isinstance(sb
, SessionChair
):
6414 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
6418 if sb
.getEmail().lower().strip() in [j
.lower().strip() for j
in i
.getEmails()]:
6422 if r
is not None and r
.isActivated():
6424 self
._addCoordinator
(r
)
6425 r
.linkTo(self
, "coordinator")
6427 self
.getConference().getPendingQueuesMgr().addPendingCoordinator(sb
)
6429 self
._addCoordinator
(sb
)
6430 if isinstance(sb
, AvatarUserWrapper
):
6431 sb
.linkTo(self
, "coordinator")
6433 def removeCoordinator( self
, av
):
6434 """Revokes coordination privileges to user.
6437 av -- (AvatarUserWrapper) user for which coordination privileges
6441 if self
._coordinators
:
6443 except AttributeError, e
:
6444 self
._coordinators
=OOBTree()
6446 if av
is None or not self
._coordinators
.has_key(av
.getId()):
6448 del self
._coordinators
[av
.getId()]
6449 if isinstance(av
, AvatarUserWrapper
):
6450 av
.unlinkTo(self
, "coordinator")
6451 if self
.getConference() is not None:
6452 self
.getConference().removeSessionCoordinator(self
,av
)
6454 def isCoordinator( self
, av
):
6455 """Tells whether the specified user is a coordinator of the session.
6458 av -- (AvatarUserWrapper) user to be checked
6460 Return value: (boolean)
6463 if self
._coordinators
:
6465 except AttributeError, e
:
6466 self
._coordinators
=OOBTree()
6467 if (av
is not None) and self
._coordinators
.has_key(av
.getId()):
6470 if isinstance(av
, AvatarUserWrapper
):
6471 for email
in av
.getEmails():
6472 if email
in self
.getCoordinatorEmailList():
6473 self
.addCoordinator(av
)
6474 self
.removeCoordinatorEmail(email
)
6478 def hasConvenerByEmail(self
, email
):
6479 for convener
in self
.getConvenerList():
6480 if email
== convener
.getEmail():
6485 def getCoordinatorList( self
):
6486 """Return all users which have privileges to coordinate the session.
6488 Return value: (list)
6491 if self
._coordinators
:
6493 except AttributeError, e
:
6494 self
._coordinators
=OOBTree()
6496 return self
._coordinators
.values()
6498 def canCoordinate(self
,aw
, right
=""):
6499 """Tells if a user has coordination privileges.
6501 Only session coordinators have coordination privileges over a
6505 aw -- (MaKaC.accessControl.AccessWrapper) User access
6506 information for which the coordination privileges must be
6509 Return value: (boolean)
6512 return self
.isCoordinator(aw
.getUser()) and self
.getConference().hasSessionCoordinatorRight(right
)
6513 return self
.isCoordinator(aw
.getUser())
6516 def getScheduleType(self
):
6520 except AttributeError:
6521 self
._ttType
=SlotSchTypeFactory
.getDefaultId()
6524 def setScheduleType(self
,t
):
6528 except AttributeError:
6529 self
._ttType
=SlotSchTypeFactory
.getDefaultId()
6530 t
=str(t
).strip().lower()
6531 if t
not in SlotSchTypeFactory
.getIdList() or t
==self
._ttType
:
6534 for slot
in self
.getSlotList():
6535 slot
.setScheduleType(t
)
6537 def getAccessController(self
):
6541 def _cmpTitle( s1
, s2
):
6542 s1
=s1
.getTitle().lower().strip()
6543 s2
=s2
.getTitle().lower().strip()
6544 return cmp( s1
, s2
)
6545 _cmpTitle
=staticmethod(_cmpTitle
)
6548 class SessionSlot(Persistent
, Fossilizable
, Locatable
):
6550 fossilizes(ISessionSlotFossil
)
6552 def __init__(self
,session
,**sessionSlotData
):
6553 self
.session
= session
6554 self
.id = "not assigned"
6557 self
.duration
= timedelta(minutes
=1)
6560 self
._conveners
= []
6561 self
._convenerGen
=Counter()
6562 self
._schedule
=SlotSchTypeFactory
.getDefaultKlass()(self
)
6563 self
._sessionSchEntry
=LinkedTimeSchEntry(self
)
6564 self
._confSchEntry
=LinkedTimeSchEntry(self
)
6565 self
._contributionDuration
= None
6567 def getTimezone( self
):
6568 return self
.getConference().getTimezone()
6570 def getLogInfo(self
):
6572 data
["id"] = self
.id
6573 data
["title"] = self
.title
6574 data
["session"] = self
.session
.getTitle()
6575 data
["start date"] = self
.startDate
6576 data
["duration"] = self
.duration
6578 for p
in self
.places
:
6579 data
["place %s"%i] = p
.getName()
6582 for r
in self
.rooms
:
6583 data
["room %s"%i] = r
.getName()
6585 for c
in self
._conveners
:
6586 data
["convener %s"%c.getId()] = c
.getFullName()
6589 def clone(self
,session
, options
):
6591 slot
= SessionSlot(session
)
6592 slot
.session
= session
6593 slot
.setTitle(self
.getTitle())
6594 timeDifference
= session
.getConference().getStartDate() - self
.getSession().getConference().getStartDate()
6595 slot
.setStartDate(self
.getStartDate() + timeDifference
)
6596 slot
.setDuration(dur
=self
.getDuration(), check
=2)
6599 if self
.getOwnLocation() is not None:
6600 slot
.setLocation(self
.getOwnLocation().clone())
6602 if self
.getOwnRoom() is not None:
6603 slot
.setRoom(self
.getOwnRoom().clone())
6606 for ch
in self
.getOwnConvenerList() :
6607 slot
.addConvener(ch
.clone())
6609 #populate the timetable
6610 if options
.get("contributions", False) :
6611 for entry
in self
.getEntries() :
6612 if isinstance(entry
, BreakTimeSchEntry
) :
6613 newentry
= entry
.clone(slot
)
6614 slot
.getSchedule().addEntry(newentry
,0)
6615 elif isinstance(entry
, ContribSchEntry
) :
6616 contrib
= entry
.getOwner()
6617 newcontrib
= contrib
.clone(session
, options
, timeDifference
)
6618 slot
.getSchedule().addEntry(newcontrib
.getSchEntry(),0)
6619 ContextManager
.setdefault("clone.unique_id_map", {})[contrib
.getUniqueId()] = newcontrib
.getUniqueId()
6621 slot
.setContribDuration(0, 0, self
.getContribDuration())
6622 slot
.notifyModification(cleanCache
= False)
6628 sets the start date of the slot to the start date of the first son
6629 and the end date to the end date of the last son
6631 sch
= self
.getSchedule()
6632 entries
= sch
.getEntries()
6633 if len(entries
) > 0:
6634 self
.setStartDate(entries
[0].getStartDate(),0,0)
6635 self
.setEndDate(sch
.calculateEndDate(), check
=0)
6637 def recalculateTimes( self
, type, diff
):
6639 recalculate and reschedule the contributions of the session slot with a time "diff" of separation.
6641 if type=="duration":
6642 entries
= self
.getSchedule().getEntries()[:]
6644 while i
<len(entries
):
6646 if i
+1 == len(entries
):
6647 dur
=self
.getEndDate()-entry
.getStartDate()
6649 nextentry
=entries
[i
+1]
6650 dur
=nextentry
.getStartDate()-entry
.getStartDate()-diff
6651 if dur
<timedelta(0):
6652 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())
6653 entry
.setDuration(dur
=dur
)
6655 if len(entries
) != 0 and self
.getEndDate() < entry
.getEndDate():
6656 self
.setEndDate(entry
.getEndDate(),2)
6657 elif type=="startingTime":
6658 st
= self
.getStartDate()
6659 entries
= self
.getSchedule().getEntries()[:]
6660 for entry
in entries
:
6661 entry
.setStartDate(st
,0,0)
6662 # add diff to last item end date if and only if the item is
6664 #if not isinstance(entry, BreakTimeSchEntry):
6665 # st=entry.getEndDate()+diff
6667 # st=entry.getEndDate()
6668 st
=entry
.getEndDate()+diff
6669 if len(entries
) != 0 and self
.getEndDate() < st
:
6670 self
.setEndDate(st
,2)
6672 def setValues(self
,data
,check
=2, moveEntriesBelow
=0):
6675 1: check and raise error in case of problem
6676 2: check and adapt the owner dates
6679 # In order to move the entries below, it is needed to know the diff (we have to move them)
6680 # and the list of entries to move. It's is needed to take those datas in advance because they
6681 # are going to be modified before the moving.
6682 if moveEntriesBelow
== 1:
6683 oldStartDate
=copy
.copy(self
.getStartDate())
6684 oldDuration
=copy
.copy(self
.getDuration())
6685 i
=self
.getConfSchEntry().getSchedule().getEntries().index(self
.getConfSchEntry())+1
6686 entriesList
= self
.getConfSchEntry().getSchedule().getEntries()[i
:]
6687 self
.title
=data
.get("title", "NO TITLE ASSIGNED")
6688 # Do we move all entries in the slot
6689 move
= int(data
.get("move",0))
6691 if "locationName" in data
:
6692 loc
= self
.getOwnLocation()
6694 loc
= CustomLocation()
6695 self
.setLocation( loc
)
6696 loc
.setName( data
["locationName"] )
6697 loc
.setAddress( data
.get("locationAddress", "") )
6699 self
.setLocation( None )
6701 if "roomName" in data
:
6702 room
= self
.getOwnRoom()
6705 self
.setRoom( room
)
6706 room
.setName( data
["roomName"] )
6708 self
.setRoom( None )
6709 sDate
= eDate
= None
6710 confTZ
= self
.getOwner().getConference().getTimezone()
6711 if data
.get("sDate",None) is not None:
6712 sd
= data
.get("sDate")
6713 sDate
= timezone(confTZ
).localize(datetime(sd
.year
,sd
.month
,sd
.day
,sd
.hour
,sd
.minute
))
6714 elif data
.get("sYear","")!="" and data
.get("sMonth","")!="" and \
6715 data
.get("sDay","")!="" and data
.get("sHour","")!="" and \
6716 data
.get("sMinute","")!="":
6717 sDate
= timezone(confTZ
).localize(datetime(int(data
["sYear"]),int(data
["sMonth"]),
6718 int(data
["sDay"]),int(data
["sHour"]),
6719 int(data
["sMinute"])))
6720 if data
.get("eDate",None) is not None:
6721 ed
= data
.get("eDate")
6722 eDate
= timezone(confTZ
).localize(datetime(ed
.year
,ed
.month
,ed
.day
,ed
.hour
,ed
.minute
))
6723 elif data
.get("eYear","")!="" and data
.get("eMonth","")!="" and \
6724 data
.get("eDay","")!="" and data
.get("eHour","")!="" and \
6725 data
.get("eMinute","")!="":
6726 eDate
= timezone(confTZ
).localize(datetime(int(data
["eYear"]),int(data
["eMonth"]),
6727 int(data
["eDay"]),int(data
["eHour"]),
6728 int(data
["eMinute"])))
6729 if sDate
!= None and eDate
!= None:
6730 sDateUTC
= sDate
.astimezone(timezone('UTC'))
6731 eDateUTC
= eDate
.astimezone(timezone('UTC'))
6732 self
.setDates(sDateUTC
,eDateUTC
,check
,moveEntries
=move
)
6734 sDateUTC
= sDate
.astimezone(timezone('UTC'))
6735 self
.setStartDate(sDateUTC
,check
,moveEntries
=move
)
6736 if data
.get("durHours","")!="" and data
.get("durMins","")!="":
6737 self
.setDuration(hours
=data
["durHours"],minutes
=data
["durMins"],check
=check
)
6738 if data
.get("contribDurHours","")!="" and data
.get("contribDurMins","")!="":
6739 self
.setContribDuration(int(data
["contribDurHours"]),int(data
["contribDurMins"]))
6740 elif data
.get("contribDuration","")!="":
6741 self
.setContribDuration(dur
=data
.get("contribDuration"))
6743 self
.setContribDuration(None,None)
6744 conveners
= data
.get("conveners",None)
6745 if conveners
is not None:
6746 self
.clearConvenerList()
6747 for conv
in conveners
:
6749 sc
.setTitle(conv
.getTitle())
6750 sc
.setFirstName(conv
.getFirstName())
6751 sc
.setFamilyName(conv
.getFamilyName())
6752 sc
.setAffiliation(conv
.getAffiliation())
6753 sc
.setEmail(conv
.getEmail())
6754 self
.addConvener(sc
)
6755 if moveEntriesBelow
== 1:
6756 diff
= (self
.getStartDate() - oldStartDate
) + (self
.getDuration() - oldDuration
)
6757 self
.getSchedule().moveEntriesBelow(diff
, entriesList
)
6758 self
._checkInnerSchedule
()
6759 self
.notifyModification()
6761 def _checkInnerSchedule( self
):
6762 self
.getSchedule().checkSanity()
6764 def setContribDuration(self
, hour
=0, min=0, dur
=None):
6765 self
._contributionDuration
= None
6767 self
._contributionDuration
=dur
6768 elif hour
!= None and min != None:
6769 self
._contributionDuration
= timedelta(hours
=hour
,minutes
=min)
6771 def getContribDuration(self
):
6773 Duration by default for contributions within the slots.
6776 if self
._contributionDuration
:
6778 except AttributeError, e
:
6779 self
._contributionDuration
= None
6780 return self
._contributionDuration
6782 def notifyModification( self
, cleanCache
= True, cleanCacheEntries
= False):
6783 self
.getSession().notifyModification(cleanCache
= False)
6785 self
.cleanCache(cleanCacheEntries
)
6788 def cleanCache(self
, cleanCacheEntries
= False):
6789 if not ContextManager
.get('clean%s'%self
.getUniqueId(), False):
6790 ScheduleToJson
.cleanCache(self
)
6791 ContextManager
.set('clean%s'%self
.getUniqueId(), True)
6792 if cleanCacheEntries
:
6793 for entry
in self
.getSchedule().getEntries():
6794 entry
.getOwner().cleanCache(cleanConference
= False)
6796 def getLocator( self
):
6797 l
=self
.getSession().getLocator()
6798 l
["slotId"]=self
.getId()
6801 def getConference( self
):
6802 return self
.getSession().getConference()
6804 def getSession(self
):
6810 def getContributionList(self
):
6811 return [e
.getOwner() for e
in ifilter(lambda e
: isinstance(e
, ContribSchEntry
),
6812 self
.getSchedule().getEntries())]
6814 def _setSchedule(self
, klass
):
6815 old_sch
= self
.getSchedule()
6816 self
._schedule
= klass(self
)
6817 #after removing old entries, one could try to fit them into the new
6818 # schedule, but there are several things to consider which are left
6819 # for later implementation (breaks, entries not fitting in the
6821 while len(old_sch
.getEntries()) > 0:
6822 entry
= old_sch
.getEntries()[0]
6823 old_sch
.removeEntry(entry
)
6824 self
.notifyModification()
6826 def getSchedule(self
):
6827 return self
._schedule
6829 def getMasterSchedule( self
):
6830 return self
.getOwner().getSchedule()
6832 def getConfSchEntry( self
):
6834 if self
._confSchEntry
:
6836 except AttributeError:
6837 self
._confSchEntry
=LinkedTimeSchEntry(self
)
6838 return self
._confSchEntry
6840 def getSessionSchEntry( self
):
6842 if self
._sessionSchEntry
:
6844 except AttributeError:
6845 self
._sessionSchEntry
=self
._schEntry
6846 return self
._sessionSchEntry
6848 def setId( self
, newId
):
6850 self
.notifyModification()
6855 def getUniqueId( self
):
6856 """Returns (string) the unique identiffier of the item.
6857 Used mainly in the web session access key table"""
6858 return "%sl%s" % (self
.getSession().getUniqueId(),self
.id)
6860 def setTitle( self
, newTitle
):
6862 self
.notifyModification()
6864 def getTitle( self
):
6868 except AttributeError,e
:
6872 def getFullTitle( self
):
6873 return self
.getSession().getTitle() + (": " + self
.getTitle() if self
.getTitle() else "")
6876 return "slot %s"%self
.getId()
6878 def getDescription(self
):
6879 return self
.getSession().getDescription()
6881 def setDates(self
, sDate
, eDate
, check
=2, moveEntries
=0):
6884 1: check and raise error in case of problem
6885 2: check and adapt the owner dates"""
6888 raise FormValuesError(_("End date cannot be prior to Start date"), _("Slot"))
6890 self
.setStartDate(sDate
, check
, moveEntries
, checkDuration
=False)
6891 self
.setDuration(0, 0, 0, eDate
-sDate
, check
)
6892 self
.notifyModification()
6894 def getEntries(self
):
6895 entriesList
= self
.getSchedule().getEntries()
6898 def move(self
, sDate
):
6899 diff
=sDate
-self
.startDate
6900 self
.startDate
= sDate
6901 for slotEntry
in self
.getSchedule().getEntries():
6902 if isinstance(slotEntry
, BreakTimeSchEntry
):
6903 slotEntry
.startDate
= slotEntry
.getStartDate() + diff
6905 se
= slotEntry
.getOwner()
6906 se
.startDate
= se
.getStartDate() + diff
6907 self
.getSchedule().reSchedule()
6909 def verifyStartDate(self
, sDate
,check
=2):
6912 1: check and raise error in case of problem
6913 2: check and adapt the owner dates"""
6915 tz
= timezone(self
.getConference().getTimezone())
6917 if sDate
< self
.getSession().getStartDate():
6919 raise ParentTimingError(_("The slot \"%s\" cannot start (%s) before its parent session starts (%s)")%\
6920 (self
.getTitle(), sDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
6921 self
.getSession().getStartDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
6924 self
.getSession().setStartDate(sDate
, check
, 0)
6926 def setStartDate(self
,sDate
,check
=2,moveEntries
=0,checkDuration
=True):
6929 1: check and raise error in case of problem
6930 2: check and adapt the owner dates"""
6933 if not sDate
.tzname():
6934 raise MaKaCError("date should be timezone aware")
6936 #If not using .fit() at the end of this method, comment it out
6937 #if self.getSession().getStartDate() > sDate:
6938 # self.getSession().duration += self.getSession().getStartDate() - sDate
6939 self
.verifyStartDate(sDate
,check
)
6941 # calculate the difference betwwen old and new date
6943 if self
.startDate
is not None:
6944 difference
= sDate
- self
.getStartDate()
6946 self
.startDate
=copy
.copy(sDate
)
6948 if difference
!= None and difference
!= timedelta(0) and moveEntries
:
6949 ContextManager
.get('autoOps').append((self
, "ENTRIES_MOVED",
6950 self
, sDate
.astimezone(timezone(self
.getTimezone()))))
6951 self
.getSchedule().moveEntriesBelow(difference
,self
.getSchedule().getEntries()[:])
6953 if self
.getConference() and not self
.getConference().getEnableSessionSlots() and self
.getSession().getStartDate() != sDate
:
6954 self
.getSession().setStartDate(sDate
, check
, 0)
6955 if check
!= 0 and self
.getSession() and checkDuration
:
6956 self
.verifyDuration(self
.getDuration(), check
=check
)
6958 # synchronize with other timetables
6959 self
.getSessionSchEntry().synchro()
6960 self
.getConfSchEntry().synchro()
6961 self
.getSession().fit()
6962 self
.notifyModification()
6964 def setEndDate(self
,eDate
,check
=2):
6965 if not eDate
.tzname():
6966 raise MaKaCError("date should be timezone aware")
6968 self
.verifyDuration(eDate
-self
.startDate
, check
)
6969 self
.setDuration(dur
=eDate
-self
.startDate
,check
=check
)
6970 if self
.getConference() and not self
.getConference().getEnableSessionSlots() and self
.getSession().getEndDate() != eDate
:
6971 self
.getSession().setEndDate(eDate
, check
)
6972 self
.getSession().fit()
6973 self
.notifyModification()
6975 def getStartDate( self
):
6976 return self
.startDate
6978 def getAdjustedStartDate(self
,tz
=None):
6980 tz
= self
.getConference().getTimezone()
6981 if tz
not in all_timezones
:
6983 return self
.startDate
.astimezone(timezone(tz
))
6985 def getEndDate( self
):
6986 if self
.startDate
is None:
6988 return self
.startDate
+self
.duration
6990 def getAdjustedEndDate( self
, tz
=None ):
6992 tz
= self
.getConference().getTimezone()
6993 if tz
not in all_timezones
:
6995 if self
.getEndDate():
6996 return self
.getEndDate().astimezone(timezone(tz
))
6999 def getDuration( self
):
7000 return self
.duration
7002 def isMoreThanDay(self
):
7003 if self
.getDuration() >= timedelta(days
=1):
7007 def verifyDuration(self
, dur
, check
=1):
7010 1: check and raise error in case of problem
7011 2: check and adapt the owner dates"""
7013 tz
= timezone(self
.getConference().getTimezone())
7014 if dur
<= timedelta(0):
7015 raise FormValuesError(_("The duration cannot be less than zero"), _("Slot"))
7017 raise FormValuesError(_("The duration cannot be more than one day"), _("Slot"))
7018 if self
.startDate
is not None:
7019 sessionStartDate
= self
.getSession().getStartDate()
7020 sessionEndDate
= self
.getSession().getEndDate()
7021 # end date has to be between the session dates
7022 eDate
= self
.startDate
+ dur
7023 if eDate
> sessionEndDate
:
7025 raise EntryTimingError(_("The session slot cannot end (%s) after its parent session (%s)") \
7026 % (eDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
7027 sessionEndDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
7030 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
7031 self
.getSession(), eDate
.astimezone(tz
)))
7032 self
.getSession().setEndDate(eDate
,check
)
7033 if eDate
.astimezone(tz
).date() > self
.startDate
.astimezone(tz
).date():
7034 raise TimingError( _("The time slot must end on the same day it has started"), _("Slot"))
7035 # do not modify if slot entries will be affected
7036 sch
= self
.getSchedule()
7037 entries
= sch
.getEntries()
7039 if eDate
< sch
.calculateEndDate():
7040 raise TimingError(_("The session slot cannot end at (%s) because there is a contribution (%s) ending after that time. ")%\
7041 (eDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
7042 sch
.calculateEndDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
7045 def setDuration(self
, days
=0,hours
=0,minutes
=0,dur
=0,check
=1):
7048 1: check and raise error in case of problem
7049 2: check and adapt the owner dates"""
7052 dur
= timedelta(days
=int(days
),hours
=int(hours
),minutes
=int(minutes
))
7053 if dur
==0 and check
==2:
7054 ContextManager
.get('autoOps').append((self
, "DURATION_SET",
7056 dur
= timedelta(minutes
=1)
7057 if dur
> timedelta(days
=1) and check
==2:
7058 pass#dur = timedelta(days=1)
7060 self
.verifyDuration(dur
, check
)
7062 self
.getSessionSchEntry().synchro()
7063 self
.getConfSchEntry().synchro()
7064 self
.getSession().fit()
7065 self
.notifyModification()
7067 def getLocationParent( self
):
7069 Returns the object from which the room/location
7070 information should be inherited
7072 return self
.session
.conference
7075 signals
.event
.session_slot_deleted
.send(self
)
7076 self
.getSchedule().clear()
7077 if self
.getSession() is not None:
7078 self
.getSession().removeSlot(self
)
7080 TrashCanManager().add(self
)
7083 TrashCanManager().remove(self
)
7085 def getAccessController( self
):
7086 return self
.getSession().getAccessController()
7088 def canAccess(self
,aw
):
7089 return self
.getSession().canAccess(aw
)
7091 def canView(self
,aw
):
7092 return self
.getSession().canView(aw
)
7094 def isProtected(self
):
7095 return self
.getSession().isProtected()
7097 def getAccessKey( self
):
7098 return self
.getSession().getAccessKey()
7100 def setScheduleType(self
,id):
7101 id=str(id).strip().lower()
7102 currentId
=SlotSchTypeFactory
.getId(self
.getSchedule())
7103 if id not in SlotSchTypeFactory
.getIdList() or id==currentId
:
7105 self
._setSchedule
(SlotSchTypeFactory
.getScheduleKlass(id))
7107 def getConvenerList(self
):
7111 except AttributeError:
7112 self
._conveners
= []
7113 if self
._conveners
== []:
7114 return self
.getSession().getConvenerList()
7115 return self
._conveners
7117 def addConvener(self
,newConv
):
7118 if newConv
in self
._conveners
:
7121 if self
._convenerGen
:
7123 except AttributeError:
7124 self
._convenerGen
=Counter()
7125 id = newConv
.getId()
7127 id=int(self
._convenerGen
.newCount())
7128 newConv
.includeInSlot(self
,id)
7129 self
._conveners
.append(newConv
)
7130 self
.notifyModification()
7132 def removeConvener(self
,conv
):
7133 if conv
not in self
._conveners
:
7135 self
._conveners
.remove(conv
)
7137 self
.notifyModification()
7139 def recoverConvener(self
, con
):
7140 self
.addConvener(con
)
7143 def getConvenerById(self
,id):
7145 for conv
in self
._conveners
:
7146 if conv
.getId()==id:
7150 def getOwnConvenerList(self
):
7154 except AttributeError:
7155 self
._conveners
= []
7156 return self
._conveners
7158 def clearConvenerList(self
):
7159 while len(self
.getOwnConvenerList()) > 0:
7160 self
._conveners
.pop()
7161 self
.notifyModification()
7165 if self
.getSession() is not None:
7166 res
=self
.getSession().getColor()
7169 def getTextColor(self
):
7171 if self
.getSession() is not None:
7172 res
=self
.getSession().getTextColor()
7175 def getAllMaterialList(self
, sort
=True):
7176 return self
.getSession().getAllMaterialList(sort
=sort
)
7178 def getRecursiveAllowedToAccessList(self
):
7179 return self
.getSession().getRecursiveAllowedToAccessList()
7181 def canModify(self
, aw_or_user
):
7182 return self
.getSession().canModify(aw_or_user
)
7185 class ContributionParticipation(Persistent
, Fossilizable
):
7187 fossilizes(IContributionParticipationFossil
, IContributionParticipationMinimalFossil
,\
7188 IContributionParticipationTTDisplayFossil
,\
7189 IContributionParticipationTTMgmtFossil
)
7191 def __init__( self
):
7192 self
._contrib
= None
7194 self
._firstName
= ""
7197 self
._affiliation
= ""
7203 def _notifyModification( self
):
7204 if self
._contrib
!= None:
7205 self
._contrib
.notifyModification()
7207 def setValues(self
, data
):
7208 self
.setFirstName(data
.get("firstName", ""))
7209 self
.setFamilyName(data
.get("familyName",""))
7210 self
.setAffiliation(data
.get("affilation",""))
7211 self
.setAddress(data
.get("address",""))
7212 self
.setEmail(data
.get("email",""))
7213 self
.setFax(data
.get("fax",""))
7214 self
.setTitle(data
.get("title",""))
7215 self
.setPhone(data
.get("phone",""))
7216 self
._notifyModification
()
7218 def getValues(self
):
7220 data
["firstName"]=self
.getFirstName()
7221 data
["familyName"]=self
.getFamilyName()
7222 data
["affilation"]=self
.getAffiliation()
7223 data
["address"]=self
.getAddress()
7224 data
["email"]=self
.getEmail()
7225 data
["fax"]=self
.getFax()
7226 data
["title"]=self
.getTitle()
7227 data
["phone"]=self
.getPhone()
7231 part
= ContributionParticipation()
7232 part
.setValues(self
.getValues())
7235 def setDataFromAvatar(self
,av
):
7236 # av is an Avatar object.
7239 self
.setFirstName(av
.getName())
7240 self
.setFamilyName(av
.getSurName())
7241 self
.setEmail(av
.getEmail())
7242 self
.setAffiliation(av
.getOrganisation())
7243 self
.setAddress(av
.getAddress())
7244 self
.setPhone(av
.getTelephone())
7245 self
.setTitle(av
.getTitle())
7246 self
.setFax(av
.getFax())
7247 self
._notifyModification
()
7249 def setDataFromOtherCP(self
,cp
):
7250 # cp is a ContributionParticipation object.
7253 self
.setFirstName(cp
.getFirstName())
7254 self
.setFamilyName(cp
.getFamilyName())
7255 self
.setEmail(cp
.getEmail())
7256 self
.setAffiliation(cp
.getAffiliation())
7257 self
.setAddress(cp
.getAddress())
7258 self
.setPhone(cp
.getPhone())
7259 self
.setTitle(cp
.getTitle())
7260 self
.setFax(cp
.getFax())
7261 self
._notifyModification
()
7263 def includeInContribution( self
, contrib
, id ):
7264 if self
.getContribution() == contrib
and self
.getId()==id.strip():
7266 self
._contrib
= contrib
7270 self
._contrib
= None
7271 TrashCanManager().add(self
)
7274 TrashCanManager().remove(self
)
7276 def setId(self
, newId
):
7282 def getContribution( self
):
7283 return self
._contrib
7285 def getConference(self
):
7286 return self
._contrib
.getConference()
7288 def getLocator(self
):
7289 if self
.getContribution() is None:
7291 loc
=self
.getContribution().getLocator()
7292 loc
["authorId"]=self
.getId()
7296 contrib
=self
.getContribution()
7297 if contrib
is not None:
7298 conf
=contrib
.getConference()
7299 if conf
is not None:
7300 conf
.unindexAuthor(self
)
7301 conf
.unindexSpeaker(self
)
7304 contrib
=self
.getContribution()
7305 if contrib
is not None:
7306 conf
=contrib
.getConference()
7307 if conf
is not None:
7308 conf
.indexAuthor(self
)
7309 conf
.indexSpeaker(self
)
7311 @Updates ('MaKaC.conference.ContributionParticipation', 'firstName')
7312 def setFirstName( self
, newName
):
7314 if tmp
==self
._firstName
:
7319 self
._notifyModification
()
7321 def getFirstName( self
):
7322 return self
._firstName
7324 def getName( self
):
7325 return self
._firstName
7328 @Updates ('MaKaC.conference.ContributionParticipation', 'familyName')
7329 def setFamilyName( self
, newName
):
7331 if tmp
==self
._surName
:
7336 self
._notifyModification
()
7338 def getFamilyName( self
):
7339 return self
._surName
7341 def getSurName( self
):
7342 return self
._surName
7345 @Updates ('MaKaC.conference.ContributionParticipation', 'email')
7346 def setEmail( self
, newMail
):
7348 if tmp
==self
._email
:
7351 self
._email
=newMail
.strip()
7353 self
._notifyModification
()
7355 def getEmail( self
):
7358 @Updates ('MaKaC.conference.ContributionParticipation', 'affiliation')
7359 def setAffiliation( self
, newAffil
):
7360 self
._affiliation
= newAffil
.strip()
7361 self
._notifyModification
()
7363 def getAffiliation( self
):
7364 if self
._affiliation
.lower() == "unknown":
7366 return self
._affiliation
7368 @Updates ('MaKaC.conference.ContributionParticipation', 'address')
7369 def setAddress( self
, newAddr
):
7370 self
._address
= newAddr
.strip()
7371 self
._notifyModification
()
7373 def getAddress( self
):
7374 return self
._address
7376 @Updates('MaKaC.conference.ContributionParticipation', 'phone')
7377 def setPhone( self
, newPhone
):
7378 self
._phone
= newPhone
.strip()
7379 self
._notifyModification
()
7381 def getPhone( self
):
7384 @Updates ('MaKaC.conference.ContributionParticipation', 'title')
7385 def setTitle( self
, newTitle
):
7386 self
._title
= newTitle
.strip()
7387 self
._notifyModification
()
7389 def getTitle( self
):
7392 @Updates ('MaKaC.conference.ContributionParticipation', 'fax')
7393 def setFax( self
, newFax
):
7394 self
._fax
= newFax
.strip()
7395 self
._notifyModification
()
7401 except AttributeError:
7405 def getDirectFullName( self
):
7406 res
= self
.getDirectFullNameNoTitle()
7407 if self
.getTitle() != "":
7408 res
= "%s %s"%( self
.getTitle(), res
)
7411 def getDirectFullNameNoTitle(self
, upper
=True):
7412 familyName
= safe_upper(self
.getFamilyName()) if upper
else self
.getFamilyName()
7413 return "{0} {1}".format(self
.getFirstName(), familyName
).strip()
7415 def getFullName(self
):
7416 res
= self
.getFullNameNoTitle()
7418 res
= "%s %s" % (self
.getTitle(), res
)
7421 def getFullNameNoTitle(self
):
7422 res
= safe_upper(self
.getFamilyName())
7423 if self
.getFirstName():
7425 res
= "%s, %s" % (res
, self
.getFirstName())
7427 res
= self
.getFirstName()
7430 def getAbrName(self
):
7431 res
= self
.getFamilyName()
7432 if self
.getFirstName():
7435 res
= "%s%s." % (res
, safe_upper(self
.getFirstName()[0]))
7438 def isSubmitter(self
):
7439 if self
.getContribution() is None:
7441 return self
.getContribution().canUserSubmit(self
)
7443 def isPendingSubmitter(self
):
7444 if self
.getContribution() is None:
7446 if self
.getContribution().getConference() is None:
7448 return self
.getContribution().getConference().getPendingQueuesMgr().isPendingSubmitter(self
)
7450 def isInAuthorList(self
):
7451 # Sometimes authors are not in the author index for an unknown reason.
7452 # In this case we don't want to link to the author page since opening it would fail
7453 return self
.getConference().getAuthorIndex().getByAuthorObj(self
) is not None
7456 def _cmpFamilyName(cp1
, cp2
):
7457 o1
= "%s %s"%(cp1
.getFamilyName(), cp1
.getFirstName())
7458 o2
= "%s %s"%(cp2
.getFamilyName(), cp2
.getFirstName())
7459 o1
=o1
.lower().strip()
7460 o2
=o2
.lower().strip()
7461 return cmp( o1
, o2
)
7464 class AuthorIndex(Persistent
):
7469 def _getKey(self
,author
):
7470 k
= "%s %s %s"%(author
.getFamilyName().lower(),author
.getFirstName().lower(),author
.getEmail().lower())
7473 def index(self
,author
):
7474 key
=self
._getKey
(author
)
7475 if not self
._idx
.has_key(key
):
7480 self
.notifyModification()
7482 def unindex(self
,author
):
7483 key
=self
._getKey
(author
)
7484 if self
._idx
.has_key(key
):
7485 if author
in self
._idx
[key
]:
7489 if len(self
._idx
[key
])<=0:
7491 self
.notifyModification()
7493 def getParticipations(self
):
7494 return self
._idx
.values()
7496 def getById(self
, id):
7497 return self
._idx
.get(id,None)
7499 def getByAuthorObj(self
, auth
):
7500 return self
.getById(self
._getKey
(auth
))
7502 def getParticipationKeys(self
):
7503 return self
._idx
.keys()
7505 def notifyModification(self
):
7506 self
._idx
._p
_changed
= 1
7509 def iteritems(self
):
7510 return self
._idx
.iteritems()
7512 def match(self
, criteria
, exact
=0):
7513 self
._options
= ['organisation', 'surName', 'name', 'email']
7515 for item
in self
.getParticipations():
7518 for f
,v
in criteria
.items():
7519 if f
== 'organisation' and v
!= '':
7520 if (exact
== 0 and item
[0].getAffiliation().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getAffiliation().lower() != v
.lower()):
7524 if f
== 'surName' and v
!= '':
7525 if (exact
== 0 and item
[0].getSurName().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getSurName().lower() != v
.lower()):
7529 if f
== 'name' and v
!= '':
7530 if (exact
== 0 and item
[0].getName().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getName().lower() != v
.lower()):
7534 if f
== 'email' and v
!= '':
7535 if (exact
== 0 and item
[0].getEmail().lower().find(v
.lower()) == -1) or (exact
== 1 and item
[0].getEmail().lower() != v
.lower()):
7539 if len(ok
) > 0 and not False in ok
:
7543 class _AuthIdx(Persistent
):
7545 def __init__(self
,conf
):
7549 def _getKey(self
,auth
):
7550 return "%s %s"%(auth
.getFamilyName().lower(),auth
.getFirstName().lower())
7552 def index(self
,auth
):
7553 if auth
.getContribution() is None:
7554 raise MaKaCError( _("Cannot index an author of a contribution which has not been included in a Conference"), _("Author Index"))
7555 if auth
.getContribution().getConference()!=self
._conf
:
7556 raise MaKaCError( _("cannot index an author of a contribution which does not belong to this Conference"), _("Author Index"))
7557 key
=self
._getKey
(auth
)
7558 contribId
=str(auth
.getContribution().getId())
7559 if not self
._idx
.has_key(key
):
7560 self
._idx
[key
]=OIBTree()
7561 if not self
._idx
[key
].has_key(contribId
):
7562 self
._idx
[key
][contribId
]=0
7563 self
._idx
[key
][contribId
]+=1
7565 def unindex(self
,auth
):
7566 if auth
.getContribution() is None:
7567 raise MaKaCError( _("Cannot unindex an author of a contribution which is not included in a conference"), _("Author Index"))
7568 if auth
.getContribution().getConference()!=self
._conf
:
7569 raise MaKaCError( _("Cannot unindex an author of a contribution which does not belong to this conference"), _("Author Index"))
7570 key
=self
._getKey
(auth
)
7571 if not self
._idx
.has_key(key
):
7573 contribId
=str(auth
.getContribution().getId())
7574 self
._idx
[key
][contribId
]-=1
7575 if self
._idx
[key
][contribId
]<=0:
7576 del self
._idx
[key
][contribId
]
7577 if len(self
._idx
[key
])<=0:
7580 def match(self
,query
):
7581 query
=query
.lower().strip()
7583 for k
in self
._idx
.keys():
7584 if k
.find(query
)!=-1:
7585 res
=union(res
,self
._idx
[k
])
7589 class _PrimAuthIdx(_AuthIdx
):
7591 def __init__(self
,conf
):
7592 _AuthIdx
.__init
__(self
,conf
)
7593 for contrib
in self
._conf
.getContributionList():
7594 for auth
in contrib
.getPrimaryAuthorList():
7598 class Contribution(CommonObjectBase
, Locatable
):
7599 """This class implements a conference contribution, being the concrete
7600 contributes of the conference participants. The class contains
7601 necessary attributes to store contribution basic meta data and provides
7602 the useful operations to access and manage them. A contribution can be
7603 attached either to a session or to a conference.
7606 fossilizes(IContributionFossil
, IContributionWithSpeakersFossil
, IContributionWithSubContribsFossil
)
7608 def __init__(self
, **contribData
):
7610 self
._session
= None
7614 self
.description
= ""
7615 self
.startDate
= None
7616 self
.duration
= timedelta(0)
7618 self
.speakerText
= ""
7621 self
._boardNumber
= ""
7622 self
._resetSchEntry
()
7623 self
.__ac
= AccessController(self
)
7625 self
.__materialGenerator
= Counter()
7627 self
.__subContGenerator
= Counter()
7633 self
.reviewing
= None
7634 self
._authorGen
= Counter()
7635 self
._authors
= OOBTree()
7636 self
._primaryAuthors
= []
7637 self
._coAuthors
= []
7641 self
._status
= ContribStatusNotSch(self
)
7642 #List of allowed users to submit material
7643 self
._submitters
= []
7644 self
._submittersEmail
= []
7645 self
._modificationDS
= nowutc()
7647 self
._reviewManager
= ReviewManager(self
)
7649 def __cmp__(self
, other
):
7650 if type(self
) is not type(other
):
7651 # This is actually dangerous and the ZODB manual says not to do this
7652 # because it relies on memory order. However, this branch should never
7653 # be taken anyway since we do not store different types in the same set
7654 # or use them as keys.
7655 return cmp(hash(self
), hash(other
))
7656 if self
.getConference() == other
.getConference():
7657 return cmp(self
.getId(), other
.getId())
7658 return cmp(self
.getConference(), other
.getConference())
7662 parent_id
= self
.parent
.getId() if self
.parent
else None
7663 return '<Contribution({}, {}, {})>'.format(self
.getId(), self
.getTitle(), parent_id
)
7665 def getVerboseType(self
):
7666 return 'Contribution'
7668 def getTimezone(self
):
7669 return self
.getConference().getTimezone()
7671 def getReviewManager(self
):
7672 if not hasattr(self
, "_reviewManager"):
7673 self
._reviewManager
= ReviewManager(self
)
7674 return self
._reviewManager
7676 def updateNonInheritingChildren(self
, elem
, delete
=False):
7677 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
7678 self
.notify_protection_to_owner(elem
, delete
)
7680 def notify_protection_to_owner(self
, elem
, delete
=False):
7681 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
7683 def getKeywords(self
):
7685 return self
._keywords
7690 def setKeywords(self
, keywords
):
7691 if type(keywords
) is list:
7692 self
._keywords
= keywords
[0]
7694 self
._keywords
= keywords
7695 self
.notifyModification(cleanCache
=False)
7697 def getFields(self
, valueonly
=False):
7701 except AttributeError:
7706 return dict((k
, v
.value
if isinstance(v
, AbstractFieldContent
) else v
) for k
, v
in self
._fields
.iteritems())
7708 def removeField(self
, field
):
7709 if field
in self
.getFields():
7710 del self
.getFields()[field
]
7711 self
.notifyModification()
7713 def setField(self
, fid
, v
):
7714 if isinstance(v
, AbstractFieldContent
):
7717 self
.getFields()[fid
].value
= v
7719 # `AttritbuteError` may happen if the field is not yet an AbstractFieldContent
7721 # `KeyError` means that the attribute doesn't exist in the contrib, in which
7722 # case it should be created anyway
7723 except (AttributeError, KeyError):
7724 afm
= self
.getConference().getAbstractMgr().getAbstractFieldsMgr()
7725 for f
in afm
.getFields():
7726 if f
.getId() == fid
:
7727 self
.getFields()[fid
] = AbstractFieldContent(f
, v
)
7729 self
.notifyModification()
7731 def getField(self
, field
):
7732 if field
in self
.getFields():
7733 value
= self
.getFields()[field
]
7734 if type(value
) is list:
7735 return "".join(value
)
7743 def getLogInfo(self
):
7745 data
["subject"] = self
.getTitle()
7746 data
["id"] = self
.id
7747 data
["title"] = self
.title
7748 data
["parent title"] = self
.parent
.getTitle()
7749 if self
._session
is not None:
7750 data
["session title"] = self
._session
.getTitle()
7751 data
["description"] = self
.description
7752 if self
.getConference():
7753 afm
= self
.getConference().getAbstractMgr().getAbstractFieldsMgr()
7754 for f
in afm
.getFields():
7756 data
[id] = self
.getField(id)
7757 data
["start date"] = "%s" % self
.startDate
7758 data
["duration"] = "%s" % self
.duration
7759 if self
._track
is not None:
7760 data
["track"] = self
._track
.getTitle()
7761 if self
._type
is not None:
7762 data
["type"] = self
._type
7763 data
["speaker text"] = self
.speakerText
7764 if self
.place
is not None:
7765 data
["place"] = self
.place
.getName()
7766 if self
.room
is not None:
7767 data
["room"] = self
.room
.getName()
7768 data
["board number"] = self
._boardNumber
7769 for sc
in self
.getSubContributionList():
7770 data
["subcontribution %s" % sc
.getId()] = sc
.getTitle()
7771 for pa
in self
._primaryAuthors
:
7772 data
["primary author %s" % pa
.getId()] = pa
.getFullName()
7773 for ca
in self
._coAuthors
:
7774 data
["co-author %s" % ca
.getId()] = ca
.getFullName()
7775 for sp
in self
._speakers
:
7776 data
["speaker %s" % sp
.getId()] = sp
.getFullName()
7777 for s
in self
.getSubmitterList():
7778 if isinstance(s
, AvatarUserWrapper
):
7779 data
["submitter"] = s
.getFullName()
7781 data
["submitter"] = s
.getName()
7784 def setValues(self
, data
, check
=2, moveEntriesBelow
=0):
7785 """Sets all the values of the current contribution object from a
7786 dictionary containing the following key-value pairs:
7789 locationName-(str) => name of the location, if not specified
7790 it will be set to the parent location name.
7791 locationAddress-(str)
7792 roomName-(str) => name of the room, if not specified it will
7793 be set to the parent room name.
7794 year, month, day, sHour, sMinute - (str) => components of the
7795 starting date of the session, if not specified it will
7797 durationHours, durationMinutes - (str)
7801 1: check and raise error in case of problem
7802 2: check and adapt the owner dates
7805 1: moveEntries below the contribution
7806 Please, note that this method sets ALL values which means that if
7807 the given dictionary doesn't contain any of the keys the value
7808 will set to a default value.
7811 # In order to move the entries below, it is needed to know the diff (we have to move them)
7812 # and the list of entries to move. It's is needed to take those datas in advance because they
7813 # are going to be modified before the moving.
7814 if moveEntriesBelow
== 1:
7815 oldStartDate
= copy
.copy(self
.getStartDate())
7816 oldDuration
= copy
.copy(self
.getDuration())
7817 i
= self
.getSchEntry().getSchedule().getEntries().index(self
.getSchEntry())+1
7818 entriesList
= self
.getSchEntry().getSchedule().getEntries()[i
:]
7819 if data
.has_key("title"):
7820 self
.setTitle(data
["title"])
7821 if data
.has_key("keywords"):
7822 self
.setKeywords(data
["keywords"])
7823 if data
.has_key("description"):
7824 self
.setDescription(data
["description"])
7825 if data
.has_key("type") and self
.getConference():
7826 self
.setType(self
.getConference().getContribTypeById(data
["type"]))
7827 if self
.getConference():
7828 afm
= self
.getConference().getAbstractMgr().getAbstractFieldsMgr()
7829 for f
in afm
.getFields():
7831 if data
.has_key("f_%s" % id):
7832 self
.setField(id, data
["f_%s" % id])
7834 if "locationName" in data
:
7835 loc
= self
.getOwnLocation()
7837 loc
= CustomLocation()
7838 self
.setLocation(loc
)
7839 loc
.setName(data
["locationName"])
7840 loc
.setAddress(data
.get("locationAddress", ""))
7842 self
.setLocation(None)
7844 #same as for the location
7845 if "roomName" in data
:
7846 room
= self
.getOwnRoom()
7850 room
.setName(data
["roomName"])
7851 room
.retrieveFullName(data
.get("locationName", ""))
7856 if self
.getConference():
7857 tz
= self
.getConference().getTimezone()
7858 if data
.get("targetDay", "") != "" and data
.get("sHour", "") != "" and data
.get("sMinute", "") != "" and check
== 2:
7859 ############################################
7860 # Fermi timezone awareness #
7861 ############################################
7862 me
= timezone(tz
).localize(datetime(int(data
["targetDay"][0:4]),
7863 int(data
["targetDay"][5:7]), int(data
["targetDay"][8:])))
7864 sdate
= timezone(tz
).localize(datetime(me
.year
, me
.month
,
7865 me
.day
, int(data
["sHour"]), int(data
["sMinute"])))
7866 self
.setStartDate(sdate
.astimezone(timezone('UTC')), check
=2)
7867 if data
.get("sYear", "") != "" and data
.get("sMonth", "") != "" and \
7868 data
.get("sDay", "") != "" and data
.get("sHour", "") != "" and \
7869 data
.get("sMinute", "") != "":
7870 self
.setStartDate(timezone(tz
).localize(datetime(int(data
["sYear"]),
7871 int(data
["sMonth"]), int(data
["sDay"]),
7872 int(data
["sHour"]), int(data
["sMinute"]))).astimezone(timezone('UTC')),
7874 ############################################
7875 # Fermi timezone awareness(end) #
7876 ############################################
7877 if data
.get("durTimedelta", "") != "":
7878 self
.setDuration(check
=check
, dur
=data
["durTimedelta"])
7879 elif data
.get("durHours", "") != "" and data
.get("durMins", "") != "":
7880 self
.setDuration(data
["durHours"], data
["durMins"], check
)
7882 h
= data
.get("durHours", "").strip()
7883 m
= data
.get("durMins", "").strip()
7884 if h
!= "" or m
!= "":
7887 if h
!= "0" or m
!= "0":
7888 self
.setDuration(int(h
), int(m
), check
)
7889 if data
.has_key("boardNumber"):
7890 self
.setBoardNumber(data
.get("boardNumber", ""))
7891 if moveEntriesBelow
== 1:
7892 diff
= (self
.getStartDate() - oldStartDate
) + (self
.getDuration() - oldDuration
)
7893 self
.getConference().getSchedule().moveEntriesBelow(diff
, entriesList
)
7894 self
.notifyModification()
7896 def clone(self
, parent
, options
, deltaTime
= 0):
7897 cont
= Contribution()
7898 parent
.addContribution(cont
)
7899 cont
.setTitle( self
.getTitle() )
7900 cont
.setDescription( self
.getDescription() )
7901 for k
, v
in self
.getFields().items():
7903 cont
.setKeywords( self
.getKeywords() )
7905 deltaTime
= parent
.getStartDate() - self
.getOwner().getStartDate()
7908 if self
.startDate
is not None :
7909 startDate
= self
.getStartDate() + deltaTime
7910 cont
.setStartDate( startDate
)
7912 cont
.setDuration( dur
=self
.getDuration() )
7914 if self
.getOwnLocation() is not None:
7915 cont
.setLocation(self
.getOwnLocation().clone())
7916 if self
.getOwnRoom() is not None:
7917 cont
.setRoom(self
.getOwnRoom().clone())
7918 cont
.setBoardNumber(self
.getBoardNumber())
7919 cont
.setReportNumberHolder(self
.getReportNumberHolder().clone(self
))
7921 cont
.setStatus(self
.getCurrentStatus())
7923 if self
.getType() is not None :
7924 for ct
in cont
.getConference().getContribTypeList() :
7925 if ct
.getName() == self
.getType().getName() :
7929 if options
.get("tracks", False) :
7930 if self
.getTrack() is not None :
7931 for tr
in cont
.getConference().getTrackList() :
7932 if tr
.getTitle() == self
.getTrack().getTitle() :
7938 if options
.get("access", False) :
7939 cont
.setProtection(self
.getAccessController()._getAccessProtection
())
7940 for u
in self
.getAllowedToAccessList() :
7942 for mgr
in self
.getManagerList() :
7943 cont
.grantModification(mgr
)
7944 for sub
in self
.getSubmitterList() :
7945 cont
.grantSubmission(sub
)
7946 for domain
in self
.getDomainList():
7947 cont
.requireDomain(domain
)
7949 if options
.get("authors", False) :
7950 for a
in self
.getPrimaryAuthorList() :
7951 cont
.addPrimaryAuthor(a
.clone())
7952 for ca
in self
.getCoAuthorList() :
7953 cont
.addCoAuthor(ca
.clone())
7954 for sp
in self
.getSpeakerList():
7955 cont
.newSpeaker(sp
.clone())
7956 cont
.setSpeakerText(self
.getSpeakerText())
7958 if options
.get("materials", False) :
7959 for m
in self
.getMaterialList() :
7960 cont
.addMaterial(m
.clone(cont
))
7961 if self
.getPaper() is not None:
7962 cont
.setPaper(self
.getPaper().clone(cont
))
7963 if self
.getSlides() is not None:
7964 cont
.setSlides(self
.getSlides().clone(cont
))
7965 if self
.getVideo() is not None:
7966 cont
.setVideo(self
.getVideo().clone(cont
))
7967 if self
.getPoster() is not None:
7968 cont
.setPoster(self
.getPoster().clone(cont
))
7969 if self
.getMinutes() is not None:
7970 cont
.setMinutes(self
.getMinutes().clone(cont
))
7971 if self
.getReviewing() is not None:
7972 cont
.setReviewing(self
.getReviewing().clone(cont
))
7974 if options
.get("subcontribs", False) :
7975 for sc
in self
.getSubContributionList() :
7976 cont
.addSubContribution(sc
.clone(cont
, self
, options
))
7979 def notifyModification( self
, date
= None, raiseEvent
= True, cleanCache
= True):
7980 self
.setModificationDate(date
)
7983 signals
.event
.contribution_data_changed
.send(self
)
7988 parent
= self
.getParent()
7990 parent
.setModificationDate()
7993 def cleanCache(self
, cleanConference
= True):
7994 # Do not clean cache if already cleaned
7995 if not ContextManager
.get('clean%s'%self
.getUniqueId(), False):
7996 ScheduleToJson
.cleanCache(self
)
7997 ContextManager
.set('clean%s'%self
.getUniqueId(), cleanConference
)
7999 def getCategoriesPath(self
):
8000 return self
.getConference().getCategoriesPath()
8002 def getModifKey( self
):
8003 return self
.getConference().getModifKey()
8005 def getAccessKey( self
):
8006 return self
.getConference().getAccessKey()
8008 def getLocator( self
):
8009 """Gives back a globaly unique identification encapsulated in a Locator
8010 object for the contribution instance
8012 if self
.getConference() == None:
8014 lconf
= self
.getConference().getLocator()
8015 if self
.getSession() is not None:
8016 lconf
["sessionId"] = self
.getSession().getId()
8017 lconf
["contribId"] = self
.getId()
8020 def _setConference( self
, conf
):
8023 def _setId( self
, id ):
8026 def includeInConference( self
, conf
, id ):
8027 """sets the conference of a contribution
8029 if self
.getConference() is not None:
8030 #raise MaKaCError("the contribution is already included in a conference")
8033 self
._setConference
( conf
)
8037 """deletes a contribution and all of its subitems
8040 oldParent
= self
.getConference()
8042 if oldParent
!= None:
8043 signals
.event
.contribution_deleted
.send(self
, parent
=oldParent
)
8046 for mat
in self
.getMaterialList():
8047 self
.removeMaterial(mat
)
8052 self
.removeMinutes()
8053 self
.removeReviewing()
8055 self
.notify_protection_to_owner(self
, delete
=True)
8057 self
.setSession(None)
8059 while len(self
.getSubContributionList()) > 0:
8061 sc
= self
.getSubContributionList()[0]
8063 self
.removeSubContribution(sc
)
8066 # delete it from parent session (if it exists)
8067 if self
.getOwner() != self
.getConference():
8069 self
.getOwner().removeContribution( self
)
8071 # (always) delete it from the parent conference
8072 self
.getConference().removeContribution( self
, callDelete
=False )
8074 self
._setConference
( None )
8076 self
.setStatus(ContribStatusNone(self
))
8078 TrashCanManager().add(self
)
8081 TrashCanManager().remove(self
)
8083 def setId( self
, newId
):
8089 def getUniqueId( self
):
8090 """returns (string) the unique identifier of the item"""
8091 """used mainly in the web session access key table"""
8092 return "%st%s" % (self
.getConference().getUniqueId(),self
.id)
8094 def setTitle( self
, newTitle
, notify
= True ):
8095 oldTitle
= self
.title
8096 self
.title
= newTitle
.strip()
8099 if oldTitle
!= newTitle
:
8100 signals
.event
.contribution_title_changed
.send(self
, old
=oldTitle
, new
=newTitle
)
8101 self
.notifyModification()
8103 def getTitle( self
):
8104 if self
.title
.strip() == "":
8108 def getDescription(self
):
8109 return str(self
.getField("content"))
8111 def setDescription(self
, desc
):
8112 self
.setField("content", desc
)
8114 def setParent(self
,parent
):
8116 self
.notifyModification(cleanCache
= False)
8117 if self
.parent
==None:
8120 def getParent( self
):
8121 if self
.getSession() is not None:
8122 return self
.getSession()
8123 return self
.getConference()
8125 def getOwner( self
):
8126 return self
.getParent()
8128 def setOwner(self
, owner
):
8129 self
.setParent(owner
)
8131 def getConference( self
):
8134 def getSession( self
):
8138 except AttributeError:
8140 return self
._session
8142 def setSession(self
,session
):
8143 if self
.getSession()==session
:
8145 if self
.isScheduled():
8146 schEntry
=self
.getSchEntry()
8147 schEntry
.getSchedule().removeEntry(schEntry
)
8148 oldSession
=self
.getSession()
8149 if oldSession
is not None:
8150 oldSession
.removeContribution(self
)
8151 self
._session
=session
8152 if session
is not None:
8153 session
.addContribution(self
)
8155 def getContribution(self
):
8158 def _resetSchEntry(self
):
8159 self
.__schEntry
=ContribSchEntry(self
)
8161 def getSchEntry(self
):
8162 if self
.__schEntry
is None or \
8163 not isinstance(self
.__schEntry
,ContribSchEntry
):
8164 self
._resetSchEntry
()
8165 return self
.__schEntry
8167 def isScheduled(self
):
8168 #For the moment we do it like this
8169 return self
.getSchEntry().getSchedule() is not None
8171 def isWithdrawn(self
):
8172 return isinstance(self
.getCurrentStatus(), ContribStatusWithdrawn
)
8174 def getLocationParent(self
):
8176 Returns the object from which the room/location
8177 information should be inherited
8179 if not self
.getConference().getEnableSessionSlots() and self
.getSession():
8180 return self
.getSession()
8181 if self
.isScheduled():
8182 return self
.getSchEntry().getSchedule().getOwner()
8183 return self
.getOwner()
8185 def getOwnLocation(self
):
8188 def setLocation(self
, newLocation
):
8189 oldLocation
= self
.place
8190 self
.place
= newLocation
8191 self
.notifyModification()
8193 def getOwnRoom(self
):
8196 def setRoom(self
, newRoom
):
8199 self
.notifyModification()
8201 def setBoardNumber(self
, newBoardNum
):
8202 self
._boardNumber
=str(newBoardNum
).strip()
8204 def getBoardNumber(self
):
8206 if self
._boardNumber
:
8208 except AttributeError:
8209 self
._boardNumber
=""
8210 return self
._boardNumber
8212 def verifyStartDate(self
, sDate
, check
=2):
8215 1: check and raise error in case of problem
8216 2: check and adapt the owner dates"""
8218 tz
= timezone(self
.getConference().getTimezone())
8219 if self
.getSchEntry().getSchedule():
8220 owner
= self
.getSchEntry().getSchedule().getOwner()
8222 owner
= self
.getOwner()
8223 if sDate
< owner
.getStartDate():
8225 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start before (%s) its parent (%s)") %\
8226 (self
.getTitle(), sDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8227 owner
.getStartDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
8230 ContextManager
.get('autoOps').append((self
, "OWNER_START_DATE_EXTENDED",
8231 owner
, sDate
.astimezone(tz
)))
8232 owner
.setDates(sDate
,owner
.getEndDate(), check
)
8233 if sDate
> owner
.getEndDate():
8235 raise ParentTimingError(_("The contribution <i>\"%s\"</i> cannot start after (%s) its parent end date(%s)") %\
8236 (self
.getTitle(), sDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8237 owner
.getEndDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
8240 owner
.setEndDate(sDate
+self
.getDuration(),check
)
8241 # Check that after modifying the start date, the end date is still within the limits of the slot
8242 if self
.getDuration() and sDate
+ self
.getDuration() > owner
.getEndDate():
8244 raise ParentTimingError("The contribution cannot end after (%s) its parent ends (%s)"%\
8245 ((sDate
+ self
.getDuration()).astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8246 owner
.getAdjustedEndDate().strftime('%Y-%m-%d %H:%M')),\
8249 # update the schedule
8250 owner
.setEndDate(sDate
+ self
.getDuration(),check
)
8251 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
8252 owner
, owner
.getAdjustedEndDate()))
8254 def setStartDate(self
, newDate
, check
=2, moveEntries
=0):
8257 1: check and raise error in case of problem
8258 2: check and adapt the owner dates"""
8262 if not newDate
.tzname():
8263 raise MaKaCError("date should be timezone aware")
8265 if newDate
!= None and check
!= 0:
8266 self
.verifyStartDate(newDate
, check
)
8267 self
.startDate
=copy
.copy(newDate
)
8268 self
.getSchEntry().synchro()
8269 self
.notifyModification()
8271 def getStartDate(self
):
8272 return self
.startDate
8274 def getAdjustedStartDate(self
, tz
=None):
8275 if self
.getStartDate() is None:
8278 tz
= self
.getConference().getTimezone()
8279 if tz
not in all_timezones
:
8281 return self
.getStartDate().astimezone(timezone(tz
))
8283 def getEndDate(self
):
8284 if self
.getStartDate() is None:
8286 return self
.getStartDate()+self
.getDuration()
8288 def getAdjustedEndDate(self
, tz
=None):
8290 tz
= self
.getConference().getTimezone()
8291 if tz
not in all_timezones
:
8293 if self
.getEndDate():
8294 return self
.getEndDate().astimezone(timezone(tz
))
8297 def getDuration(self
):
8298 return self
.duration
8300 def verifyDuration(self
, check
=2):
8303 1: check and raise error in case of problem
8304 2: check and adapt the owner dates"""
8306 tz
= timezone(self
.getConference().getTimezone())
8308 endDate
= self
.getEndDate()
8310 if self
.getSchEntry().getSchedule() is not None:
8311 owner
= self
.getSchEntry().getSchedule().getOwner()
8312 if endDate
> owner
.getEndDate():
8314 raise ParentTimingError(_("The contribution \"%s\" ending date (%s) has to fit between its parent's dates (%s - %s)") %\
8315 (self
.getTitle(), endDate
.astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8316 owner
.getStartDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M'),\
8317 owner
.getEndDate().astimezone(tz
).strftime('%Y-%m-%d %H:%M')),\
8320 ContextManager
.get('autoOps').append((self
, "OWNER_END_DATE_EXTENDED",
8321 owner
, self
.getAdjustedEndDate()))
8322 owner
.setEndDate(endDate
, check
)
8324 def setDuration(self
, hours
=0, minutes
=15, check
=2, dur
=0):
8327 1: check and raise error in case of problem
8328 2: check and adapt the owner dates"""
8333 self
.duration
=timedelta(hours
=int(hours
),minutes
=int(minutes
))
8335 self
.verifyDuration(check
)
8336 self
.getSchEntry().synchro()
8337 self
.notifyModification()
8339 def _addAuthor(self
, part
):
8345 except AttributeError:
8346 self
._authors
= OOBTree()
8350 except AttributeError:
8351 self
._authorGen
=Counter()
8352 newId
= part
.getId()
8354 newId
= str( self
._authorGen
.newCount() )
8355 self
._authors
[newId
] = part
8356 part
.includeInContribution( self
, newId
)
8358 def _removeAuthor(self
, part
):
8364 except AttributeError:
8365 self
._authors
= OOBTree()
8366 if not self
._authors
.has_key( part
.getId() ):
8368 del self
._authors
[ part
.getId() ]
8369 if not self
.isSpeaker(part
):
8372 def addPrimaryAuthor(self
, part
, index
=None):
8376 if self
._primaryAuthors
:
8378 except AttributeError:
8379 self
._primaryAuthors
= []
8380 self
._addAuthor
( part
)
8381 if index
is not None:
8382 self
._primaryAuthors
.insert(index
, part
)
8384 self
._primaryAuthors
.append( part
)
8385 if self
.getConference() is not None:
8386 self
.getConference().indexAuthor(part
)
8387 self
.notifyModification(cleanCache
= False)
8389 def removePrimaryAuthor(self
, part
, removeSpeaker
=1, removePendingSubm
=True):
8393 if self
._primaryAuthors
:
8395 except AttributeError:
8396 self
._primaryAuthors
= []
8397 if part
not in self
._primaryAuthors
:
8399 if self
.getConference() is not None:
8400 self
.getConference().unindexAuthor(part
)
8401 self
._primaryAuthors
.remove( part
)
8403 self
.removeSpeaker( part
)
8404 self
._removeAuthor
( part
)
8405 if removePendingSubm
:
8406 #--Pending queue: remove pending participant waiting to became submitter if anything
8407 self
.getConference().getPendingQueuesMgr().removePendingSubmitter(part
)
8409 self
.notifyModification(cleanCache
= False)
8411 def recoverPrimaryAuthor(self
, pa
, isPendingSubmitter
):
8412 self
.addPrimaryAuthor(pa
)
8414 if isPendingSubmitter
:
8415 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(pa
, False)
8417 def isPrimaryAuthor(self
, part
):
8421 if self
._primaryAuthors
:
8423 except AttributeError:
8424 self
._primaryAuthors
= []
8425 return part
in self
._primaryAuthors
8427 def isCoAuthor(self
, part
):
8431 except AttributeError:
8432 self
._coAuthors
= []
8433 return part
in self
._coAuthors
8435 def isPrimaryAuthorByEmail(self
, email
):
8436 for prAuthor
in self
.getPrimaryAuthorList():
8437 if prAuthor
.getEmail() == email
:
8441 def isCoAuthorByEmail(self
, email
):
8442 for coAuthor
in self
.getCoAuthorList():
8443 if coAuthor
.getEmail() == email
:
8447 def isSpeakerByEmail(self
, email
):
8448 for speaker
in self
.getSpeakerList():
8449 if speaker
.getEmail() == email
:
8453 def changePosPrimaryAuthor(self
, part
, index
):
8457 if self
._primaryAuthors
:
8459 except AttributeError:
8460 self
._primaryAuthors
=[]
8461 if not part
in self
._primaryAuthors
:
8463 self
._primaryAuthors
.remove(part
)
8464 self
._primaryAuthors
.insert(index
,part
)
8465 self
.notifyModification(cleanCache
= False)
8467 def upPrimaryAuthor(self
, part
):
8471 if self
._primaryAuthors
:
8473 except AttributeError:
8474 self
._primaryAuthors
=[]
8476 idx
=self
._primaryAuthors
.index(part
)
8481 self
._primaryAuthors
.remove(part
)
8482 self
._primaryAuthors
.insert(idx
-1,part
)
8483 self
.notifyModification(cleanCache
=False)
8485 def downPrimaryAuthor(self
, part
):
8489 if self
._primaryAuthors
:
8491 except AttributeError:
8492 self
._primaryAuthors
=[]
8494 idx
=self
._primaryAuthors
.index(part
)
8497 if idx
>len(self
._primaryAuthors
):
8499 self
._primaryAuthors
.remove(part
)
8500 self
._primaryAuthors
.insert(idx
+1,part
)
8501 self
.notifyModification(cleanCache
= False)
8503 def newAuthorsList(self
, prAuthors
, coAuthors
):
8504 ''' calculate new lists of both kind of authors, because something has
8505 been changed the position by drag and drop '''
8506 newPrList
= self
.calculateNewAuthorList(prAuthors
, "prAuthor")
8507 newCoList
= self
.calculateNewAuthorList(coAuthors
, "coAuthor")
8508 self
.setPrimaryAuthorList(newPrList
)
8509 self
.setCoAuthorList(newCoList
)
8511 def calculateNewAuthorList(self
, list, kind
):
8513 if kind
== "prAuthor":
8515 author
= self
.getPrimaryAuthorById(auth
['id'])
8517 result
.append(author
)
8519 author
= self
.getCoAuthorById(auth
['id'])
8521 result
.append(author
)
8523 elif kind
== "coAuthor":
8525 author
= self
.getCoAuthorById(auth
['id'])
8527 result
.append(author
)
8529 author
= self
.getPrimaryAuthorById(auth
['id'])
8531 result
.append(author
)
8534 def getPrimaryAuthorById(self
, authorId
):
8535 for author
in self
.getPrimaryAuthorList():
8536 if authorId
== author
.getId():
8540 def getCoAuthorById(self
, authorId
):
8541 for author
in self
.getCoAuthorList():
8542 if authorId
== author
.getId():
8546 def setPrimaryAuthorList(self
, l
):
8547 self
._primaryAuthors
= l
8548 self
.notifyModification(cleanCache
= False)
8550 def setCoAuthorList(self
, l
):
8552 self
.notifyModification(cleanCache
= False)
8554 def changePosCoAuthor(self
, part
, index
):
8560 except AttributeError:
8562 if not part
in self
._coAuthors
:
8564 self
._coAuthors
.remove(part
)
8565 self
._coAuthors
.insert(index
,part
)
8566 self
.notifyModification(cleanCache
= False)
8568 def upCoAuthor(self
, part
):
8574 except AttributeError:
8577 idx
=self
._coAuthors
.index(part
)
8582 self
._coAuthors
.remove(part
)
8583 self
._coAuthors
.insert(idx
-1,part
)
8584 self
.notifyModification(cleanCache
= False)
8586 def downCoAuthor(self
, part
):
8592 except AttributeError:
8595 idx
=self
._coAuthors
.index(part
)
8598 if idx
>len(self
._coAuthors
):
8600 self
._coAuthors
.remove(part
)
8601 self
._coAuthors
.insert(idx
+1,part
)
8602 self
.notifyModification(cleanCache
= False)
8604 def getPrimaryAuthorList(self
):
8608 if self
._primaryAuthors
:
8610 except AttributeError:
8611 self
._primaryAuthors
= []
8612 return self
._primaryAuthors
8614 getPrimaryAuthorsList
= getPrimaryAuthorList
8616 def getAuthorList(self
):
8622 except AttributeError:
8623 self
._authors
= OOBTree()
8624 return self
._authors
.values()
8626 def getAllAuthors(self
):
8627 """ This method returns a list composed by the primary authors
8628 and co-authors. The different with getAuthorList() is the type
8631 return self
.getPrimaryAuthorList() + self
.getCoAuthorList()
8633 def addCoAuthor(self
, part
, index
=None):
8639 except AttributeError:
8640 self
._coAuthors
= []
8641 self
._addAuthor
( part
)
8642 if index
is not None:
8643 self
._coAuthors
.insert(index
, part
)
8645 self
._coAuthors
.append( part
)
8646 if self
.getConference() is not None:
8647 self
.getConference().indexAuthor(part
)
8648 self
.notifyModification(cleanCache
= False)
8650 def removeCoAuthor(self
, part
, removeSpeaker
=1, removePendingSubm
=True):
8656 except AttributeError:
8657 self
._coAuthors
= []
8658 if part
not in self
._coAuthors
:
8660 if self
.getConference() is not None:
8661 self
.getConference().unindexAuthor(part
)
8662 self
._coAuthors
.remove( part
)
8664 self
.removeSpeaker( part
)
8665 self
._removeAuthor
( part
)
8666 if removePendingSubm
:
8667 #--Pending queue: remove pending participant waiting to became submitter if anything
8668 self
.getConference().getPendingQueuesMgr().removePendingSubmitter(part
)
8670 self
.notifyModification(cleanCache
= False)
8672 def recoverCoAuthor(self
, ca
, isPendingSubmitter
):
8673 self
.addCoAuthor(ca
)
8675 if isPendingSubmitter
:
8676 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(ca
, False)
8678 def getCoAuthorList(self
):
8684 except AttributeError:
8685 self
._coAuthors
= []
8686 return self
._coAuthors
8688 def getAuthorById(self
, authorId
):
8694 except AttributeError:
8695 self
._authors
= OOBTree()
8696 return self
._authors
.get( authorId
.strip(), None )
8698 def isAuthor(self
, part
):
8704 except AttributeError:
8705 self
._authors
= OOBTree()
8706 return self
._authors
.has_key( part
.getId() )
8708 def getSpeakerById(self
, authorId
):
8714 except AttributeError:
8716 for spk
in self
._speakers
:
8717 if spk
.getId() == authorId
:
8721 def changePosSpeaker(self
, part
, index
):
8727 except AttributeError:
8729 if not part
in self
._speakers
:
8731 self
._speakers
.remove(part
)
8732 self
._speakers
.insert(index
,part
)
8733 self
.notifyModification()
8735 def addSpeaker(self
, part
, index
=None):
8737 Adds a speaker (ContributionParticipation object) to the contribution
8738 forcing it to be one of the authors of the contribution
8743 except AttributeError:
8745 if not self
.isAuthor( part
):
8746 raise MaKaCError( _("The Specified speaker is not the Author"), _("Contribution"))
8747 if index
is not None:
8748 self
._speakers
.insert(index
, part
)
8750 self
._speakers
.append( part
)
8751 if self
.getConference() is not None:
8752 self
.getConference().indexSpeaker(part
)
8753 self
.notifyModification()
8755 def newSpeaker(self
, part
):
8757 Adds a new speaker (ContributionParticipation object) to the contribution
8758 setting the speakers ID and the fact it belongs to that contribution
8763 except AttributeError:
8768 except AttributeError:
8769 self
._authorGen
=Counter()
8770 self
._speakers
.append( part
)
8771 newId
= part
.getId()
8773 newId
= str( self
._authorGen
.newCount() )
8774 part
.includeInContribution(self
, newId
)
8775 if self
.getConference() is not None:
8776 self
.getConference().indexSpeaker(part
)
8777 self
.notifyModification()
8779 def removeSpeaker(self
, part
):
8785 except AttributeError:
8787 if part
not in self
._speakers
:
8789 self
._speakers
.remove( part
)
8790 if self
.getConference() is not None:
8791 self
.getConference().unindexSpeaker(part
)
8792 if part
not in self
.getAuthorList():
8794 #--Pending queue: remove pending participant waiting to became submitter if anything
8795 self
.getConference().getPendingQueuesMgr().removePendingSubmitter(part
)
8797 self
.notifyModification()
8799 def recoverSpeaker(self
, spk
, isPendingSubmitter
):
8800 self
.newSpeaker(spk
)
8802 if isPendingSubmitter
:
8803 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(spk
, False)
8805 def isSpeaker(self
, part
):
8811 except AttributeError:
8813 return part
in self
._speakers
8815 def getSpeakerList(self
):
8821 except AttributeError:
8823 return self
._speakers
8825 def getSpeakerText(self
):
8828 if self
.speakerText
:
8830 except AttributeError, e
:
8831 self
.speakerText
= ""
8832 return self
.speakerText
8834 def setSpeakerText(self
, newText
):
8835 self
.speakerText
= newText
.strip()
8837 def appendSpeakerText(self
, newText
):
8838 self
.setSpeakerText("%s, %s" % (self
.getSpeakerText(), newText
.strip()))
8840 def isProtected(self
):
8841 # tells if a contribution is protected or not
8842 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
8844 def getAccessProtectionLevel(self
):
8845 return self
.__ac
.getAccessProtectionLevel()
8847 def isItselfProtected(self
):
8848 return self
.__ac
.isItselfProtected()
8850 def hasAnyProtection(self
):
8851 """Tells whether a contribution has any kind of protection over it:
8852 access or domain protection.
8854 if self
.__ac
.isProtected():
8856 if self
.getDomainList():
8858 if self
.getAccessProtectionLevel() == -1:
8861 return self
.getOwner().hasAnyProtection()
8865 def hasProtectedOwner(self
):
8866 if self
.getOwner() != None:
8867 return self
.getOwner().isProtected()
8870 def setProtection(self
, private
):
8872 oldValue
= 1 if self
.isProtected() else -1
8874 self
.__ac
.setProtection( private
)
8875 self
.notify_protection_to_owner(self
)
8877 if oldValue
!= private
:
8879 signals
.event
.contribution_protection_changed
.send(self
, old
=oldValue
, new
=private
)
8881 def grantAccess(self
, prin
):
8882 self
.__ac
.grantAccess( prin
)
8883 if isinstance(prin
, AvatarUserWrapper
):
8884 prin
.linkTo(self
, "access")
8885 self
.notifyModification(raiseEvent
= False)
8887 def revokeAccess( self
, prin
):
8888 self
.__ac
.revokeAccess( prin
)
8889 if isinstance(prin
, AvatarUserWrapper
):
8890 prin
.unlinkTo(self
, "access")
8891 self
.notifyModification(raiseEvent
= False)
8893 def canView( self
, aw
):
8894 """tells whether the specified user has access to the current object
8895 or any of its sub-objects
8897 if self
.canAccess( aw
):
8899 ################################################################################################
8900 for sc
in self
.getSubContributionList():
8901 if sc
.canView( aw
):
8905 def isAllowedToAccess( self
, user
):
8908 return (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess( user
)) or\
8909 self
.__ac
.canUserAccess( user
) or\
8910 self
.canUserModify( user
) or \
8911 self
.canUserSubmit(user
)
8913 def canAccess( self
, aw
):
8914 # Allow harvesters (Invenio, offline cache) to access
8916 if has_request_context() and self
.__ac
.isHarvesterIP(request
.remote_addr
):
8918 #####################################################
8920 if self
.canModify(aw
):
8923 if not self
.canIPAccess(request
.remote_addr
) and not self
.isAllowedToAccess(aw
.getUser()):
8925 if not self
.isProtected():
8927 flag
= self
.isAllowedToAccess( aw
.getUser() )
8928 return flag
or self
.getConference().canKeyAccess(aw
)
8930 def grantModification( self
, prin
):
8931 self
.__ac
.grantModification( prin
)
8932 if isinstance(prin
, AvatarUserWrapper
):
8933 prin
.linkTo(self
, "manager")
8934 self
.notifyModification(raiseEvent
= False)
8936 def revokeModification( self
, prin
):
8937 self
.__ac
.revokeModification( prin
)
8938 if isinstance(prin
, AvatarUserWrapper
):
8939 prin
.unlinkTo(self
, "manager")
8940 self
.notifyModification(raiseEvent
= False)
8942 def canModify(self
, aw_or_user
):
8943 if hasattr(aw_or_user
, 'getUser'):
8944 aw_or_user
= aw_or_user
.getUser()
8945 return self
.canUserModify(aw_or_user
) or self
.getConference().canKeyModify()
8947 def canUserModify( self
, av
):
8948 """Tells whether a user is allowed to modify the current contribution:
8949 only if the user is granted to modify the contribution or the user
8950 can modify any of its upper objects (i.e. conference or session).
8952 return self
.getParent().canUserModify( av
) or self
.__ac
.canModify( av
)
8954 def getManagerList( self
):
8955 return self
.__ac
.getModifierList()
8957 def getAllowedToAccessList( self
):
8958 return self
.__ac
.getAccessList()
8960 def addMaterial( self
, newMat
):
8961 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
8962 newMat
.setOwner( self
)
8963 self
.materials
[ newMat
.getId() ] = newMat
8964 self
.notifyModification()
8966 def removeMaterial(self
, mat
):
8967 if mat
.getId() in self
.materials
.keys():
8969 self
.materials
[mat
.getId()].setOwner(None)
8970 del self
.materials
[ mat
.getId() ]
8971 self
.notifyModification()
8972 elif mat
.getId().lower() == 'paper':
8974 elif mat
.getId().lower() == 'slides':
8976 elif mat
.getId().lower() == 'minutes':
8977 self
.removeMinutes()
8978 elif mat
.getId().lower() == 'video':
8980 elif mat
.getId().lower() == 'poster':
8982 elif mat
.getId().lower() == 'reviewing':
8983 self
.removeReviewing()
8985 def recoverMaterial(self
, recMat
):
8986 # Id must already be set in recMat.
8987 recMat
.setOwner( self
)
8988 self
.materials
[ recMat
.getId() ] = recMat
8990 self
.notifyModification()
8992 def getMaterialRegistry(self
):
8994 Return the correct material registry for this type
8996 from MaKaC
.webinterface
.materialFactories
import ContribMFRegistry
8997 return ContribMFRegistry
8999 def getMaterialById( self
, matId
):
9000 if matId
.lower() == 'paper':
9001 return self
.getPaper()
9002 elif matId
.lower() == 'slides':
9003 return self
.getSlides()
9004 elif matId
.lower() == 'video':
9005 return self
.getVideo()
9006 elif matId
.lower() == 'poster':
9007 return self
.getPoster()
9008 elif matId
.lower() == 'minutes':
9009 return self
.getMinutes()
9010 elif self
.materials
.has_key(matId
):
9011 return self
.materials
[ matId
]
9014 def getMaterialList( self
):
9015 return self
.materials
.values()
9017 def getAllMaterialList(self
, sort
=True):
9018 l
= self
.getMaterialList()
9020 l
.append( self
.getPaper() )
9021 if self
.getSlides():
9022 l
.append( self
.getSlides() )
9024 l
.append( self
.getVideo() )
9025 if self
.getPoster():
9026 l
.append( self
.getPoster() )
9027 if self
.getMinutes():
9028 l
.append( self
.getMinutes() )
9030 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
9033 def getAllViewableMaterialList( self
, aw
=None ):
9035 aw
= ContextManager
.get("currentAW", ContextManager
.get("currentRH").getAW())
9036 return [mat
for mat
in self
.getAllMaterialList() if mat
.canView(aw
)]
9039 def newSubContribution(self
):
9040 newSub
= SubContribution()
9041 self
.addSubContribution(newSub
)
9042 signals
.event
.subcontribution_created
.send(newSub
, parent
=self
)
9045 def addSubContribution( self
, newSubCont
):
9046 newSubCont
.setId(str( self
.__subContGenerator
.newCount()) )
9047 newSubCont
.setOwner( self
)
9048 self
._subConts
.append( newSubCont
)
9049 self
.notifyModification(cleanCache
= False)
9051 def removeSubContribution( self
, subCont
):
9052 if subCont
in self
._subConts
:
9054 subCont
.setOwner(None)
9055 self
._subConts
.remove(subCont
)
9056 self
.notifyModification(cleanCache
= False)
9058 def recoverSubContribution( self
, recSubCont
):
9059 # Id must already be set in recSubCont.
9060 recSubCont
.setOwner( self
)
9061 self
._subConts
.append( recSubCont
)
9062 recSubCont
.recover()
9063 self
.notifyModification(cleanCache
= False)
9065 def getSubContributionById(self
, SCId
):
9066 for sb
in self
._subConts
:
9067 if sb
.getId() == SCId
:
9070 def getSubContributionList(self
):
9071 return self
._subConts
9073 def iterSubContributions(self
):
9074 return iter(self
._subConts
)
9076 def getNumberOfSubcontributions(self
):
9077 return len(self
._subConts
)
9079 def upSubContribution(self
, subcont
):
9080 if subcont
in self
._subConts
:
9081 if self
._subConts
.index(subcont
) != 0:
9082 index
= self
._subConts
.index(subcont
)
9083 sb
= self
._subConts
.pop(index
)
9084 self
._subConts
.insert(index
-1, sb
)
9085 self
.notifyModification(cleanCache
= False)
9087 def downSubContribution(self
, subCont
):
9088 if subCont
in self
._subConts
:
9089 if self
._subConts
.index(subCont
) < len(self
._subConts
)-1:
9090 index
= self
._subConts
.index(subCont
)
9091 sb
= self
._subConts
.pop(index
)
9092 self
._subConts
.insert(index
+1, sb
)
9093 self
.notifyModification(cleanCache
= False)
9095 def setPaper( self
, newPaper
):
9096 if self
.getPaper() != None:
9097 raise MaKaCError( _("The paper for this contribution has already been set"), _("Contribution"))
9099 self
.paper
.setOwner( self
)
9100 self
.notifyModification()
9102 def removePaper( self
):
9103 if self
.paper
is None:
9106 self
.paper
.setOwner(None)
9108 self
.notifyModification()
9110 def recoverPaper(self
, p
):
9114 def getPaper( self
):
9117 def setSlides( self
, newSlides
):
9118 if self
.getSlides() != None:
9119 raise MaKaCError( _("The slides for this contribution have already been set"), _("contribution"))
9120 self
.slides
=newSlides
9121 self
.slides
.setOwner( self
)
9122 self
.notifyModification()
9124 def removeSlides( self
):
9125 if self
.slides
is None:
9127 self
.slides
.delete()
9128 self
.slides
.setOwner( None )
9130 self
.notifyModification()
9132 def recoverSlides(self
, s
):
9136 def getSlides( self
):
9139 def setVideo( self
, newVideo
):
9140 if self
.getVideo() != None:
9141 raise MaKaCError( _("the video for this contribution has already been set"))
9143 self
.video
.setOwner( self
)
9144 self
.notifyModification()
9146 def removeVideo( self
):
9147 if self
.getVideo() is None:
9150 self
.video
.setOwner(None)
9152 self
.notifyModification()
9154 def recoverVideo(self
, v
):
9158 def getVideo( self
):
9162 except AttributeError:
9166 def setPoster( self
, newPoster
):
9167 if self
.getPoster() != None:
9168 raise MaKaCError( _("the poster for this contribution has already been set"))
9169 self
.poster
=newPoster
9170 self
.poster
.setOwner( self
)
9171 self
.notifyModification()
9173 def removePoster( self
):
9174 if self
.getPoster() is None:
9176 self
.poster
.delete()
9177 self
.poster
.setOwner(None)
9179 self
.notifyModification()
9181 def recoverPoster(self
, p
):
9185 def getPoster( self
):
9189 except AttributeError:
9193 def setMinutes( self
, newMinutes
):
9194 if self
.getMinutes() != None:
9195 raise MaKaCError( _("the Minutes for this contribution has already been set"))
9196 self
.minutes
=newMinutes
9197 self
.minutes
.setOwner( self
)
9198 self
.notifyModification()
9200 def createMinutes( self
):
9201 if self
.getMinutes() != None:
9202 raise MaKaCError( _("The minutes for this contribution have already been created"), _("Contribution"))
9203 self
.minutes
= Minutes()
9204 self
.minutes
.setOwner( self
)
9205 self
.notifyModification()
9208 def removeMinutes( self
):
9209 if self
.getMinutes() is None:
9211 self
.minutes
.delete()
9212 self
.minutes
.setOwner( None )
9214 self
.notifyModification()
9216 def recoverMinutes(self
, min):
9217 self
.removeMinutes() # To ensure that the current minutes are put in
9220 self
.minutes
.setOwner( self
)
9222 self
.notifyModification()
9225 def getMinutes( self
):
9230 except AttributeError, e
:
9234 def setReviewing( self
, newReviewing
):
9235 if self
.getReviewing() != None:
9236 raise MaKaCError( _("The reviewing maretial for this contribution has already been set"), _("Contribution"))
9237 self
.reviewing
=newReviewing
9238 self
.reviewing
.setOwner( self
)
9239 self
.notifyModification()
9241 def removeReviewing( self
):
9242 if self
.getReviewing() is None:
9244 self
.reviewing
.delete()
9245 self
.reviewing
.setOwner(None)
9246 self
.reviewing
= None
9247 self
.notifyModification()
9249 def recoverReviewing(self
, p
):
9250 self
.setReviewing(p
)
9253 def getReviewing( self
):
9257 except AttributeError, e
:
9258 self
.reviewing
= None
9259 return self
.reviewing
9261 def getMasterSchedule( self
):
9262 return self
.getOwner().getSchedule()
9264 def requireDomain( self
, dom
):
9265 self
.__ac
.requireDomain( dom
)
9267 def freeDomain( self
, dom
):
9268 self
.__ac
.freeDomain( dom
)
9270 def getDomainList( self
):
9271 return self
.__ac
.getRequiredDomainList()
9273 def getTrack( self
):
9277 except AttributeError:
9281 def setTrack( self
, newTrack
):
9282 currentTrack
= self
.getTrack()
9283 if newTrack
== currentTrack
:
9286 currentTrack
.removeContribution( self
)
9287 self
._track
= newTrack
9289 self
._track
.addContribution( self
)
9291 def removeTrack(self
, track
):
9292 if track
== self
._track
:
9295 def setType( self
, newType
):
9296 self
._type
= newType
9298 def getType( self
):
9302 except AttributeError:
9306 def getModificationDate( self
):
9307 """Returns the date in which the contribution was last modified"""
9309 return self
._modificationDS
9311 if self
.getConference():
9312 self
._modificationDS
= self
.getConference().getModificationDate()
9314 self
._modificationDS
= nowutc()
9315 return self
._modificationDS
9317 def getCurrentStatus(self
):
9321 except AttributeError:
9322 self
._status
=ContribStatusNotSch(self
)
9324 getStatus
= getCurrentStatus
9326 def setStatus(self
,newStatus
):
9329 self
._status
=newStatus
9331 def withdraw(self
,resp
,comment
):
9332 """ Remove or put a contribution in a conference
9335 if self
.isWithdrawn():
9336 #put back the authors in the author index
9337 for auth
in self
.getAuthorList():
9338 self
.getConference().getAuthorIndex().index(auth
)
9339 for spk
in self
.getSpeakerList():
9340 self
.getConference().getSpeakerIndex().index(spk
)
9341 #change the status of the contribution
9342 self
._status
=ContribStatusNotSch(self
)
9345 #remove the authors from the author index
9346 if self
.getConference() is not None:
9347 for auth
in self
.getAuthorList():
9348 self
.getConference().getAuthorIndex().unindex(auth
)
9349 for spk
in self
.getSpeakerList():
9350 self
.getConference().unindexSpeaker(spk
)
9351 #remove the contribution from any schedule it is included
9352 if self
.isScheduled():
9353 self
.getSchEntry().getSchedule().removeEntry(self
.getSchEntry())
9354 self
.getCurrentStatus().withdraw(resp
,comment
)
9357 def getSubmitterList(self
, no_groups
=False):
9359 if self
._submitters
:
9361 except AttributeError:
9362 self
._submitters
=[] #create the attribute
9363 self
.notifyModification(raiseEvent
= False)
9365 return [s
for s
in self
._submitters
if not isinstance(s
, GroupWrapper
)]
9367 return self
._submitters
9369 def _grantSubmission(self
,av
):
9370 if av
not in self
.getSubmitterList():
9371 self
.getSubmitterList().append(av
)
9372 if self
.getConference() is not None:
9373 self
.getConference().addContribSubmitter(self
,av
)
9374 if isinstance(av
, AvatarUserWrapper
):
9375 av
.linkTo(self
, "submission")
9376 self
.notifyModification(raiseEvent
= False)
9378 def _grantSubmissionEmail(self
, email
):
9379 """Returns True if submission email was granted. False if email was already in the list.
9381 if not email
.lower() in map(lambda x
: x
.lower(), self
.getSubmitterEmailList()):
9382 self
.getSubmitterEmailList().append(email
.lower().strip())
9386 def revokeSubmissionEmail(self
, email
):
9387 if email
in self
.getSubmitterEmailList():
9388 self
.getSubmitterEmailList().remove(email
)
9391 def grantSubmission(self
, sb
, sendEmail
=True):
9392 """Grants a user with submission privileges for the contribution
9393 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9395 if isinstance(sb
, ContributionParticipation
) or isinstance(sb
, SubContribParticipation
):
9397 results
=ah
.match({"email":sb
.getEmail()}, exact
=1, searchInAuthenticators
=False)
9399 results
=ah
.match({"email":sb
.getEmail()}, exact
=1)
9402 if i
.hasEmail(sb
.getEmail()):
9405 if r
and r
.isActivated():
9406 self
._grantSubmission
(r
)
9408 self
.getConference().getPendingQueuesMgr().addPendingSubmitter(sb
, False)
9409 submissionEmailGranted
= self
._grantSubmissionEmail
(sb
.getEmail())
9410 if submissionEmailGranted
and sendEmail
:
9411 notif
= pendingQueues
._PendingSubmitterNotification
( [sb
] )
9412 mail
.GenericMailer
.sendAndLog( notif
, self
.getConference() )
9413 if self
.getConference():
9414 self
.getConference().addContribSubmitter(self
,sb
)
9416 self
._grantSubmission
(sb
)
9418 def _revokeSubmission(self
, av
):
9419 if av
in self
.getSubmitterList():
9420 self
.getSubmitterList().remove(av
)
9421 if self
.getConference():
9422 self
.getConference().removeContribSubmitter(self
, av
)
9423 if isinstance(av
, AvatarUserWrapper
):
9424 av
.unlinkTo(self
, "submission")
9425 self
.notifyModification(raiseEvent
= False)
9427 def revokeSubmission(self
, sb
):
9428 """Removes submission privileges for the specified user
9429 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9431 if isinstance(sb
, ContributionParticipation
) or isinstance(sb
, SubContribParticipation
):
9433 results
= ah
.match({"email": sb
.getEmail()}, exact
=1, searchInAuthenticators
=False)
9436 if i
.hasEmail(sb
.getEmail()):
9440 self
._revokeSubmission
(r
)
9442 self
.revokeSubmissionEmail(sb
.getEmail())
9444 self
._revokeSubmission
(sb
)
9446 def revokeAllSubmitters(self
):
9447 self
._submitters
= []
9448 self
.notifyModification(raiseEvent
= False)
9450 def getSubmitterEmailList(self
):
9452 return self
._submittersEmail
9454 self
._submittersEmail
= []
9455 return self
._submittersEmail
9457 def canUserSubmit(self
, sb
):
9458 """Tells whether a user can submit material for the current contribution
9459 - sb: can be an Avatar or an Author (primary author, co-author, speaker)
9464 if isinstance(sb
, ContributionParticipation
) or isinstance(sb
, SubContribParticipation
):
9465 sbEmail
= sb
.getEmail()
9467 # Normally, we shouldn't get here unless we're adding someone as a Speaker or similar.
9468 # `no_groups` is used so that we do not consider group membership, as to not confuse the
9469 # user (since there will be speakers with "implicit" privileges) and avoid that hasEmail breaks
9470 return any(submitter
.hasEmail(sbEmail
) for submitter
in self
.getSubmitterList(no_groups
=True)) or \
9471 any(submitterEmail
== sbEmail
for submitterEmail
in self
.getSubmitterEmailList())
9473 for principal
in self
.getSubmitterList():
9474 if principal
!= None and principal
.containsUser(sb
):
9479 def getAccessController(self
):
9482 def getReportNumberHolder(self
):
9484 if self
._reportNumberHolder
:
9486 except AttributeError, e
:
9487 self
._reportNumberHolder
=ReportNumberHolder(self
)
9488 return self
._reportNumberHolder
9490 def setReportNumberHolder(self
, rnh
):
9491 self
._reportNumberHolder
=rnh
9494 def contributionStartDateForSort(cls
, contribution
):
9495 """ Function that can be used as "key" argument to sort a list of contributions by start date
9496 The contributions with no start date will be at the end with this sort
9498 if contribution
.getStartDate():
9499 return contribution
.getStartDate()
9501 return maxDatetime()
9505 if self
.getSession() is not None:
9506 res
=self
.getSession().getColor()
9509 def getTextColor(self
):
9511 if self
.getSession() is not None:
9512 res
=self
.getSession().getTextColor()
9516 class AcceptedContribution(Contribution
):
9517 """This class represents a contribution which has been created from an
9521 def __init__(self
, abstract
):
9522 Contribution
.__init
__(self
)
9523 abstract
.getConference().addContribution(self
, abstract
.getId())
9524 self
._abstract
= abstract
9525 self
.setTitle(abstract
.getTitle())
9526 self
._setFieldsFromAbstract
()
9527 if isinstance(abstract
.getCurrentStatus(), review
.AbstractStatusAccepted
):
9528 self
.setTrack(abstract
.getCurrentStatus().getTrack())
9529 self
.setType(abstract
.getCurrentStatus().getType())
9530 for auth
in abstract
.getAuthorList():
9531 c_auth
= ContributionParticipation()
9532 self
._setAuthorValuesFromAbstract
(c_auth
, auth
)
9533 if abstract
.isPrimaryAuthor(auth
):
9534 self
.addPrimaryAuthor(c_auth
)
9536 self
.addCoAuthor(c_auth
)
9537 if abstract
.isSpeaker(auth
):
9538 self
.addSpeaker(c_auth
)
9539 self
._grantSubmission
(self
.getAbstract().getSubmitter().getUser())
9541 def _setAuthorValuesFromAbstract(self
, cAuth
, aAuth
):
9542 cAuth
.setTitle(aAuth
.getTitle())
9543 cAuth
.setFirstName(aAuth
.getFirstName())
9544 cAuth
.setFamilyName(aAuth
.getSurName())
9545 cAuth
.setEmail(aAuth
.getEmail())
9546 cAuth
.setAffiliation(aAuth
.getAffiliation())
9547 cAuth
.setAddress(aAuth
.getAddress())
9548 cAuth
.setPhone(aAuth
.getTelephone())
9550 def _setFieldsFromAbstract(self
):
9551 for k
, v
in self
._abstract
.getFields().iteritems():
9554 def getAbstract(self
):
9555 return self
._abstract
9557 def setAbstract(self
, abs):
9558 self
._abstract
= abs
9560 def getSubmitterList(self
, no_groups
=False):
9562 if self
._submitters
:
9564 except AttributeError:
9565 self
._submitters
= [] # create the attribute
9566 self
._grantSubmission
(self
.getAbstract().getSubmitter().getUser())
9568 return [s
for s
in self
._submitters
if not isinstance(s
, GroupWrapper
)]
9570 return self
._submitters
9573 """deletes a contribution and all of their subitems
9575 abs = self
.getAbstract()
9577 cs
= abs.getCurrentStatus()
9578 if isinstance(cs
, review
.AbstractStatusAccepted
):
9579 if cs
.getTrack() is not None:
9580 abs.addTrack(cs
.getTrack())
9581 abs.setCurrentStatus(review
.AbstractStatusSubmitted(abs))
9582 abs._setContribution
(None)
9583 self
.setAbstract(None)
9584 Contribution
.delete(self
)
9587 class ContribStatus(Persistent
):
9591 def __init__(self
,contribution
,responsible
):
9592 self
._setContrib
(contribution
)
9593 self
._setResponsible
(responsible
)
9596 def clone(self
, contribution
, responsible
):
9597 cs
= ContribStatus(contribution
, responsible
)
9598 cs
.setDate(self
.getDate())
9601 def _setContrib(self
,newContrib
):
9602 self
._contrib
=newContrib
9604 def getContrib(self
):
9605 return self
._contrib
9607 def _setResponsible(self
,newResp
):
9608 self
._responsible
=newResp
9610 def getResponsible(self
):
9611 return self
._responsible
9616 def setDate(self
, date
):
9622 def withdraw(self
,resp
,comments
=""):
9623 self
._contrib
.setStatus(ContribStatusWithdrawn(self
.getContrib(),resp
,comments
))
9625 class ContribStatusNotSch(ContribStatus
):
9628 def __init__(self
,contrib
):
9629 ContribStatus
.__init
__(self
,contrib
,None)
9631 def clone(self
, contribution
):
9632 csns
= ContribStatusNotSch(contribution
)
9633 csns
.setDate(self
.getDate())
9636 ContribStatusSubmitted
=ContribStatusNotSch
9638 class ContribStatusSch(ContribStatus
):
9641 def __init__(self
,contrib
):
9642 ContribStatus
.__init
__(self
,contrib
,None)
9644 def clone(self
, contribution
):
9645 css
= ContribStatusSch(contribution
)
9646 css
.setDate(self
.getDate())
9649 class ContribStatusWithdrawn(ContribStatus
):
9652 def __init__(self
,contrib
,resp
,comments
):
9653 ContribStatus
.__init
__(self
,contrib
,resp
)
9654 self
._setComment
(comments
)
9656 def clone(self
, contribution
):
9657 csw
= ContribStatusWithdrawn(contribution
)
9658 csw
.setDate(self
.getDate())
9659 csw
.setComment(self
.getComment())
9662 def _setComment(self
,text
):
9663 self
._comment
=text
.strip()
9665 def getComment(self
):
9666 return self
._comment
9668 class ContribStatusNone(ContribStatus
):
9669 # This is a special status we assign to contributions that are put in the trash can.
9671 def __init__(self
,contrib
):
9672 ContribStatus
.__init
__(self
,contrib
,None)
9674 def clone(self
, contribution
):
9675 csn
= ContribStatusNone(contribution
)
9676 csn
.setDate(self
.getDate())
9679 class SubContribParticipation(Persistent
, Fossilizable
):
9681 fossilizes(ISubContribParticipationFossil
, ISubContribParticipationFullFossil
)
9683 def __init__( self
):
9684 self
._subContrib
= None
9686 self
._firstName
= ""
9689 self
._affiliation
= ""
9695 def getConference(self
):
9696 if self
._subContrib
is not None:
9697 return self
._subContrib
.getConference()
9700 def _notifyModification( self
):
9701 if self
._subContrib
!= None:
9702 self
._subContrib
.notifyModification()
9704 def setValues(self
, data
):
9705 self
.setFirstName(data
.get("firstName", ""))
9706 self
.setFamilyName(data
.get("familyName",""))
9707 self
.setAffiliation(data
.get("affilation",""))
9708 self
.setAddress(data
.get("address",""))
9709 self
.setEmail(data
.get("email",""))
9710 self
.setFax(data
.get("fax",""))
9711 self
.setTitle(data
.get("title",""))
9712 self
.setPhone(data
.get("phone",""))
9713 self
._notifyModification
()
9715 def getValues(self
):
9717 data
["firstName"]=self
.getFirstName()
9718 data
["familyName"]=self
.getFamilyName()
9719 data
["affilation"]=self
.getAffiliation()
9720 data
["address"]=self
.getAddress()
9721 data
["email"]=self
.getEmail()
9722 data
["fax"]=self
.getFax()
9723 data
["title"]=self
.getTitle()
9724 data
["phone"]=self
.getPhone()
9728 part
= SubContribParticipation()
9729 part
.setValues(self
.getValues())
9732 def setDataFromAvatar(self
,av
):
9733 # av is an Avatar object.
9736 self
.setFirstName(av
.getName())
9737 self
.setFamilyName(av
.getSurName())
9738 self
.setEmail(av
.getEmail())
9739 self
.setAffiliation(av
.getOrganisation())
9740 self
.setAddress(av
.getAddress())
9741 self
.setPhone(av
.getTelephone())
9742 self
.setTitle(av
.getTitle())
9743 self
.setFax(av
.getFax())
9744 self
._notifyModification
()
9746 def setDataFromAuthor(self
,au
):
9747 # au is a ContributionParticipation object.
9750 self
.setFirstName(au
.getFirstName())
9751 self
.setFamilyName(au
.getFamilyName())
9752 self
.setEmail(au
.getEmail())
9753 self
.setAffiliation(au
.getAffiliation())
9754 self
.setAddress(au
.getAddress())
9755 self
.setPhone(au
.getPhone())
9756 self
.setTitle(au
.getTitle())
9757 self
.setFax(au
.getFax())
9758 self
._notifyModification
()
9760 def setDataFromSpeaker(self
,spk
):
9761 # spk is a SubContribParticipation object.
9764 self
.setFirstName(spk
.getFirstName())
9765 self
.setFamilyName(spk
.getFamilyName())
9766 self
.setEmail(spk
.getEmail())
9767 self
.setAffiliation(spk
.getAffiliation())
9768 self
.setAddress(spk
.getAddress())
9769 self
.setPhone(spk
.getPhone())
9770 self
.setTitle(spk
.getTitle())
9771 self
.setFax(spk
.getFax())
9772 self
._notifyModification
()
9774 def includeInSubContrib( self
, subcontrib
, id ):
9775 if self
.getSubContrib() == subcontrib
and self
.getId()==id.strip():
9777 self
._subContrib
= subcontrib
9781 self
._subContrib
= None
9782 TrashCanManager().add(self
)
9785 TrashCanManager().remove(self
)
9787 @Updates ('MaKaC.conference.SubContribParticipation', 'id')
9788 def setId(self
, newId
):
9794 def getSubContrib( self
):
9795 return self
._subContrib
9797 def getContribution( self
):
9798 if self
._subContrib
is not None:
9799 return self
._subContrib
.getContribution()
9803 contrib
=self
.getContribution()
9804 if contrib
is not None:
9805 conf
=contrib
.getConference()
9806 if conf
is not None:
9807 conf
.unindexAuthor(self
)
9808 conf
.unindexSpeaker(self
)
9811 contrib
=self
.getContribution()
9812 if contrib
is not None:
9813 conf
=contrib
.getConference()
9814 if conf
is not None:
9815 conf
.indexAuthor(self
)
9816 conf
.indexSpeaker(self
)
9818 @Updates ('MaKaC.conference.SubContribParticipation', 'firstName')
9819 def setFirstName( self
, newName
):
9821 if tmp
==self
._firstName
:
9826 self
._notifyModification
()
9828 def getFirstName( self
):
9829 return self
._firstName
9831 def getName( self
):
9832 return self
._firstName
9834 @Updates ('MaKaC.conference.SubContribParticipation', 'familyName')
9835 def setFamilyName( self
, newName
):
9837 if tmp
==self
._surName
:
9842 self
._notifyModification
()
9844 def getFamilyName( self
):
9845 return self
._surName
9847 def getSurName( self
):
9848 return self
._surName
9850 @Updates ('MaKaC.conference.SubContribParticipation', 'email')
9851 def setEmail( self
, newMail
):
9853 if tmp
==self
._email
:
9856 self
._email
=newMail
.strip()
9858 self
._notifyModification
()
9860 def getEmail( self
):
9863 @Updates ('MaKaC.conference.SubContribParticipation', 'affiliation')
9864 def setAffiliation( self
, newAffil
):
9865 self
._affiliation
= newAffil
.strip()
9866 self
._notifyModification
()
9868 def getAffiliation( self
):
9869 return self
._affiliation
9871 @Updates ('MaKaC.conference.SubContribParticipation', 'address')
9872 def setAddress( self
, newAddr
):
9873 self
._address
= newAddr
.strip()
9874 self
._notifyModification
()
9876 def getAddress( self
):
9877 return self
._address
9879 @Updates ('MaKaC.conference.SubContribParticipation', 'phone')
9880 def setPhone( self
, newPhone
):
9881 self
._phone
= newPhone
.strip()
9882 self
._notifyModification
()
9884 def getPhone( self
):
9887 @Updates ('MaKaC.conference.SubContribParticipation', 'title')
9888 def setTitle( self
, newTitle
):
9889 self
._title
= newTitle
.strip()
9890 self
._notifyModification
()
9892 def getTitle( self
):
9895 def setFax( self
, newFax
):
9896 self
._fax
= newFax
.strip()
9897 self
._notifyModification
()
9903 except AttributeError:
9907 def getFullName( self
):
9908 res
= self
.getFullNameNoTitle()
9909 if self
.getTitle() != "":
9910 res
= "%s %s"%( self
.getTitle(), res
)
9913 def getFullNameNoTitle(self
):
9914 res
= safe_upper(self
.getFamilyName())
9915 if self
.getFirstName():
9917 res
= "%s, %s" % (res
, self
.getFirstName())
9919 res
= self
.getFirstName()
9922 def getAbrName(self
):
9923 res
= self
.getFamilyName()
9924 if self
.getFirstName():
9927 res
= "%s%s." % (res
, safe_upper(self
.getFirstName()[0]))
9930 def getDirectFullName(self
):
9931 res
= self
.getDirectFullNameNoTitle()
9933 res
= "%s %s" % (self
.getTitle(), res
)
9936 def getDirectFullNameNoTitle(self
, upper
=True):
9937 surName
= safe_upper(self
.getFamilyName()) if upper
else self
.getFamilyName()
9938 return "{0} {1}".format(self
.getFirstName(), surName
).strip()
9941 class SubContribution(CommonObjectBase
, Locatable
):
9945 fossilizes(ISubContributionFossil
, ISubContributionWithSpeakersFossil
)
9947 def __init__( self
, **subContData
):
9951 self
.description
= ""
9952 self
.__schEntry
= None
9953 self
.duration
= timedelta( minutes
=15 )
9955 self
.speakerText
= ""
9958 self
.__materialGenerator
= Counter() # Provides material unique
9959 # identifiers whithin the current
9960 self
.poster
= None # contribution
9966 self
._authorGen
= Counter()
9972 parent_id
= self
.parent
.getId()
9973 event_id
= self
.getConference().getId() if self
.getConference() else None
9977 return '<SubContribution({}, {}, {}.{})>'.format(self
.getId(), self
.getTitle(), event_id
, parent_id
)
9979 def updateNonInheritingChildren(self
, elem
, delete
=False):
9980 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
9982 def getAccessController(self
):
9983 return self
.getOwner().getAccessController()
9985 def getKeywords(self
):
9987 return self
._keywords
9992 def setKeywords(self
, keywords
):
9993 self
._keywords
= keywords
9995 def getLogInfo(self
):
9998 data
["subject"] = self
.getTitle()
9999 data
["id"] = self
.id
10000 data
["title"] = self
.title
10001 data
["parent title"] = self
.getParent().getTitle()
10002 data
["description"] = self
.description
10003 data
["duration"] = "%s"%self
.duration
10004 data
["minutes"] = self
.minutes
10006 for sp
in self
.speakers
:
10007 data
["speaker %s"%sp
.getId()] = sp
.getFullName()
10012 def clone(self
, deltaTime
, parent
, options
):
10013 sCont
= SubContribution()
10014 sCont
.setParent(parent
)
10015 sCont
.setTitle(self
.getTitle())
10016 sCont
.setDescription(self
.getDescription())
10017 sCont
.setKeywords(self
.getKeywords())
10018 dur
= self
.getDuration()
10019 hours
= dur
.seconds
/ 3600
10020 minutes
= (dur
.seconds
% 3600) / 60
10021 sCont
.setDuration(hours
, minutes
)
10022 sCont
.setReportNumberHolder(self
.getReportNumberHolder().clone(self
))
10024 # There is no _order attribute in this class
10026 if options
.get("authors", False) :
10027 for s
in self
.getSpeakerList() :
10028 sCont
.newSpeaker(s
.clone())
10029 sCont
.setSpeakerText(self
.getSpeakerText())
10031 if options
.get("materials", False) :
10032 for m
in self
.getMaterialList() :
10033 sCont
.addMaterial(m
.clone(sCont
))
10034 if self
.getPaper() is not None:
10035 sCont
.setPaper(self
.getPaper().clone(sCont
))
10036 if self
.getSlides() is not None:
10037 sCont
.setSlides(self
.getSlides().clone(sCont
))
10038 if self
.getVideo() is not None:
10039 sCont
.setVideo(self
.getVideo().clone(sCont
))
10040 if self
.getPoster() is not None:
10041 sCont
.setPoster(self
.getPoster().clone(sCont
))
10042 if self
.getMinutes() is not None:
10043 sCont
.setMinutes(self
.getMinutes().clone(sCont
))
10046 sCont
.notifyModification()
10049 def notifyModification(self
, raiseEvent
= True):
10050 parent
= self
.getParent()
10052 parent
.setModificationDate()
10054 signals
.event
.subcontribution_data_changed
.send(self
)
10055 self
._p
_changed
= 1
10057 def getCategoriesPath(self
):
10058 return self
.getConference().getCategoriesPath()
10060 def getLocator( self
):
10061 """Gives back a globaly unique identification encapsulated in a Locator
10062 object for the contribution instance
10065 lconf
= self
.getOwner().getLocator()
10066 lconf
["subContId"] = self
.getId()
10070 def setId( self
, newId
):
10076 def getUniqueId( self
):
10077 """returns (string) the unique identifier of the item"""
10078 """used mainly in the web session access key table"""
10079 return "%ssc%s" % (self
.getParent().getUniqueId(),self
.id)
10081 def setTitle( self
, newTitle
):
10082 old_title
= self
.title
10083 self
.title
= newTitle
.strip()
10084 if old_title
!= self
.title
:
10085 signals
.event
.subcontribution_title_changed
.send(self
, old
=old_title
, new
=self
.title
)
10086 self
.notifyModification()
10088 def getTitle( self
):
10089 if self
.title
.strip() == "":
10090 return "(no title)"
10093 def setDescription( self
, newDesc
):
10094 self
.description
= newDesc
.strip()
10095 self
.notifyModification()
10097 def getDescription( self
):
10098 return self
.description
10100 def setParent(self
,parent
):
10101 self
.parent
= parent
10102 if self
.parent
== None:
10105 def getParent( self
):
10108 def setOwner(self
, owner
):
10109 self
.setParent(owner
)
10111 def getOwner( self
):
10112 return self
.getParent()
10114 def getConference( self
):
10115 return self
.parent
.getConference()
10117 def getSession( self
):
10118 return self
.parent
.getSession()
10120 def getContribution(self
):
10123 def getDuration( self
):
10124 return self
.duration
10126 def setDuration( self
, hours
, minutes
=0, dur
=0 ):
10130 hours
= int( hours
)
10131 minutes
= int( minutes
)
10132 self
.duration
= timedelta(hours
=hours
,minutes
=minutes
)
10133 self
.notifyModification()
10135 def getLocation( self
):
10136 return self
.getOwner().getLocation()
10138 def getRoom( self
):
10139 return self
.getOwner().getRoom()
10141 def getSpeakerById( self
, id ):
10144 for spk
in self
.speakers
:
10145 if spk
.getId() == id:
10149 def newSpeaker( self
, spk
):
10152 self
.speakers
.append( spk
)
10154 if self
._authorGen
:
10156 except AttributeError:
10157 self
._authorGen
=Counter()
10158 newId
= spk
.getId()
10160 newId
= str( self
._authorGen
.newCount() )
10161 spk
.includeInSubContrib(self
, newId
)
10162 if self
.getConference() is not None:
10163 self
.getConference().indexSpeaker(spk
)
10164 self
.notifyModification()
10166 def removeSpeaker( self
, spk
):
10169 if spk
not in self
.speakers
:
10171 self
.speakers
.remove( spk
)
10172 if self
.getConference() is not None:
10173 self
.getConference().unindexSpeaker(spk
)
10175 self
.notifyModification()
10177 def recoverSpeaker(self
, spk
):
10178 self
.newSpeaker(spk
)
10181 def isSpeaker( self
, spk
):
10184 return spk
in self
._speakers
10186 def getSpeakerList ( self
):
10189 return self
.speakers
10191 def getSpeakerText( self
):
10194 if self
.speakerText
:
10196 except AttributeError, e
:
10197 self
.speakerText
= ""
10198 return self
.speakerText
10200 def setSpeakerText( self
, newText
):
10201 self
.speakerText
= newText
.strip()
10203 def appendSpeakerText( self
, newText
):
10204 self
.setSpeakerText( "%s, %s"%(self
.getSpeakerText(), newText
.strip()) )
10207 # There is no _order attribute in this class -
10208 # the methods below are either obsolate or the feature has not been implemented
10210 # def setOrder( self, order ):
10211 # self._order = order
10212 # self.notifyModification()
10214 # def getOrder(self):
10215 # return self._order
10217 def canIPAccess( self
, ip
):
10218 return self
.getOwner().canIPAccess(ip
)
10220 def isProtected( self
):
10221 return self
.hasProtectedOwner()
10223 def getAccessProtectionLevel( self
):
10224 return self
.getOwner().getAccessProtectionLevel()
10226 def hasAnyProtection( self
):
10227 """Tells whether a subContribution has any kind of protection over it:
10228 access or domain protection.
10230 return self
.getOwner().hasAnyProtection()
10232 def getManagerList( self
):
10233 return self
.parent
.getManagerList()
10235 def hasProtectedOwner( self
):
10236 if self
.getOwner() != None:
10237 return self
.getOwner().isProtected()
10240 def getAccessKey( self
):
10241 return self
.getOwner().getAccessKey()
10243 def getModifKey( self
):
10244 return self
.getConference().getModifKey()
10246 def canView( self
, aw
):
10247 """tells whether the specified user has access to the current object
10248 or any of its sub-objects
10250 if self
.canAccess( aw
):
10254 def isAllowedToAccess( self
, user
):
10255 return self
.parent
.isAllowedToAccess( user
)
10257 def canAccess( self
, aw
):
10258 return self
.getOwner().canAccess(aw
)
10260 def canModify(self
, aw_or_user
):
10261 if hasattr(aw_or_user
, 'getUser'):
10262 aw_or_user
= aw_or_user
.getUser()
10263 return self
.canUserModify(aw_or_user
) or self
.getConference().canKeyModify()
10265 def canUserModify( self
, av
):
10266 """Tells whether a user is allowed to modify the current contribution:
10267 only if the user is granted to modify the contribution or the user
10268 can modify any of its upper objects (i.e. conference or session).
10270 return self
.getParent().canUserModify( av
)
10272 def canUserSubmit( self
, av
):
10273 return self
.getOwner().canUserSubmit( av
)
10275 def getAllowedToAccessList( self
):
10276 """Currently the SubContribution class has no access list.
10277 But instead of returning the owner Contribution's access list,
10278 I am returning an empty list. Methods such as getRecursiveAllowedToAccess()
10279 will call the owner Contribution anyway.
10283 def addMaterial( self
, newMat
):
10284 newMat
.setId( str(self
.__materialGenerator
.newCount()) )
10285 newMat
.setOwner( self
)
10286 self
.materials
[ newMat
.getId() ] = newMat
10287 self
.notifyModification()
10289 def removeMaterial( self
, mat
):
10290 if mat
.getId() in self
.materials
.keys():
10292 self
.materials
[mat
.getId()].setOwner(None)
10293 del self
.materials
[ mat
.getId() ]
10294 self
.notifyModification()
10295 elif mat
.getId().lower() == 'paper':
10297 self
.notifyModification()
10298 elif mat
.getId().lower() == 'slides':
10299 self
.removeSlides()
10300 self
.notifyModification()
10301 elif mat
.getId().lower() == 'minutes':
10302 self
.removeMinutes()
10303 self
.notifyModification()
10304 elif mat
.getId().lower() == 'video':
10306 self
.notifyModification()
10307 elif mat
.getId().lower() == 'poster':
10308 self
.removePoster()
10309 self
.notifyModification()
10311 def recoverMaterial(self
, recMat
):
10312 # Id must already be set in recMat.
10313 recMat
.setOwner( self
)
10314 self
.materials
[ recMat
.getId() ] = recMat
10316 self
.notifyModification()
10318 def getMaterialRegistry(self
):
10320 Return the correct material registry for this type
10322 from MaKaC
.webinterface
.materialFactories
import SubContributionMFRegistry
10323 return SubContributionMFRegistry
10325 def getMaterialById( self
, matId
):
10326 if matId
.lower() == 'paper':
10327 return self
.getPaper()
10328 elif matId
.lower() == 'slides':
10329 return self
.getSlides()
10330 elif matId
.lower() == 'video':
10331 return self
.getVideo()
10332 elif matId
.lower() == 'poster':
10333 return self
.getPoster()
10334 elif matId
.lower() == 'minutes':
10335 return self
.getMinutes()
10336 elif self
.materials
.has_key(matId
):
10337 return self
.materials
[ matId
]
10340 def getMaterialList( self
):
10341 return self
.materials
.values()
10343 def getAllMaterialList(self
, sort
=True):
10344 l
= self
.getMaterialList()
10345 if self
.getPaper():
10346 l
.append( self
.getPaper() )
10347 if self
.getSlides():
10348 l
.append( self
.getSlides() )
10349 if self
.getVideo():
10350 l
.append( self
.getVideo() )
10351 if self
.getMinutes():
10352 l
.append( self
.getMinutes() )
10353 if self
.getPoster():
10354 l
.append( self
.getPoster() )
10356 l
.sort(lambda x
,y
: cmp(x
.getTitle(),y
.getTitle()))
10359 def setPaper( self
, newPaper
):
10360 if self
.getPaper() != None:
10361 raise MaKaCError( _("The paper for this subcontribution has already been set"), _("Contribution"))
10362 self
.paper
=newPaper
10363 self
.paper
.setOwner( self
)
10364 self
.notifyModification()
10366 def removePaper( self
):
10367 if self
.getPaper() is None:
10369 self
.paper
.delete()
10370 self
.paper
.setOwner(None)
10372 self
.notifyModification()
10374 def recoverPaper(self
, p
):
10378 def getPaper( self
):
10381 def setSlides( self
, newSlides
):
10382 if self
.getSlides() != None:
10383 raise MaKaCError( _("The slides for this subcontribution have already been set"), _("Contribution"))
10384 self
.slides
=newSlides
10385 self
.slides
.setOwner( self
)
10386 self
.notifyModification()
10388 def removeSlides( self
):
10389 if self
.getSlides() is None:
10391 self
.slides
.delete()
10392 self
.slides
.setOwner( None )
10394 self
.notifyModification()
10396 def recoverSlides(self
, s
):
10400 def getSlides( self
):
10403 def setVideo( self
, newVideo
):
10404 if self
.getVideo() != None:
10405 raise MaKaCError( _("the video for this subcontribution has already been set"))
10406 self
.video
=newVideo
10407 self
.video
.setOwner( self
)
10408 self
.notifyModification()
10410 def removeVideo( self
):
10411 if self
.getVideo() is None:
10413 self
.video
.delete()
10414 self
.video
.setOwner(None)
10416 self
.notifyModification()
10418 def recoverVideo(self
, v
):
10422 def getVideo( self
):
10426 except AttributeError:
10430 def setPoster( self
, newPoster
):
10431 if self
.getPoster() != None:
10432 raise MaKaCError( _("the poster for this subcontribution has already been set"))
10433 self
.poster
=newPoster
10434 self
.poster
.setOwner( self
)
10435 self
.notifyModification()
10437 def removePoster( self
):
10438 if self
.getPoster() is None:
10440 self
.poster
.delete()
10441 self
.poster
.setOwner(None)
10443 self
.notifyModification()
10445 def recoverPoster(self
, p
):
10449 def getPoster( self
):
10453 except AttributeError:
10457 def setMinutes( self
, newMinutes
):
10458 if self
.getMinutes() != None:
10459 raise MaKaCError( _("the Minutes for this subcontribution has already been set"))
10460 self
.minutes
=newMinutes
10461 self
.minutes
.setOwner( self
)
10462 self
.notifyModification()
10464 def createMinutes( self
):
10465 if self
.getMinutes() != None:
10466 raise MaKaCError( _("The minutes for this subcontribution have already been created"), _("Sub Contribution"))
10467 self
.minutes
= Minutes()
10468 self
.minutes
.setOwner( self
)
10469 self
.notifyModification()
10470 return self
.minutes
10472 def removeMinutes( self
):
10473 if self
.getMinutes() is None:
10475 self
.minutes
.delete()
10476 self
.minutes
.setOwner( None )
10477 self
.minutes
= None
10478 self
.notifyModification()
10480 def recoverMinutes(self
, min):
10481 self
.removeMinutes() # To ensure that the current minutes are put in
10484 self
.minutes
.setOwner( self
)
10486 self
.notifyModification()
10487 return self
.minutes
10489 def getMinutes( self
):
10494 except AttributeError, e
:
10495 self
.minutes
= None
10496 return self
.minutes
10498 def getMasterSchedule( self
):
10499 return self
.getOwner().getSchedule()
10502 signals
.event
.subcontribution_deleted
.send(self
, parent
=self
.getOwner())
10504 while len(self
.getSpeakerList()) > 0:
10505 self
.removeSpeaker(self
.getSpeakerList()[0])
10506 for mat
in self
.getMaterialList():
10507 self
.removeMaterial(mat
)
10509 self
.removeSlides()
10511 self
.removePoster()
10512 self
.removeMinutes()
10513 TrashCanManager().add(self
)
10518 TrashCanManager().remove(self
)
10520 def getReportNumberHolder(self
):
10522 if self
._reportNumberHolder
:
10524 except AttributeError, e
:
10525 self
._reportNumberHolder
=ReportNumberHolder(self
)
10526 return self
._reportNumberHolder
10528 def setReportNumberHolder(self
, rnh
):
10529 self
._reportNumberHolder
=rnh
10531 class Material(CommonObjectBase
):
10532 """This class represents a set of electronic documents (resources) which can
10533 be attached to a conference, a session or a contribution.
10534 A material can be of several types (achieved by specialising this class)
10535 and is like a container of files which have some relation among them.
10536 It contains the minimal set of attributes to store basic meta data and
10537 provides useful operations to access and manage it.
10539 owner -- (Conference, Session or Contribution) Object to which the
10540 material is attached to
10541 id -- (string) Material unique identifier. Normally used to uniquely
10542 identify a material within a conference, session or contribution
10543 title -- (string) Material denomination
10544 description -- (string) Longer text describing in more detail material
10546 type -- (string) String identifying the material classification
10547 resources -- (PMapping) Collection of resouces grouped within the
10548 material. Dictionary of references to Resource objects indexed
10549 by their unique relative id.
10552 fossilizes(IMaterialMinimalFossil
, IMaterialFossil
)
10554 def __init__( self
, materialData
=None ):
10555 self
.id = "not assigned"
10556 self
.__resources
= {}
10557 self
.__resourcesIdGen
= Counter()
10559 self
.description
= ""
10562 self
.__ac
= AccessController(self
)
10563 self
._mainResource
= None
10565 def __cmp__(self
, other
):
10566 if type(self
) is not type(other
):
10567 # This is actually dangerous and the ZODB manual says not to do this
10568 # because it relies on memory order. However, this branch should never
10569 # be taken anyway since we do not store different types in the same set
10570 # or use them as keys.
10571 return cmp(hash(self
), hash(other
))
10572 if self
.getConference() == other
.getConference():
10573 if self
.getId().isdigit() and other
.getId().isdigit():
10574 return cmp(int(self
.getId()), int(other
.getId()))
10576 return cmp(self
.getId(), other
.getId())
10577 return cmp(self
.getConference(), other
.getConference())
10579 def updateNonInheritingChildren(self
, elem
, delete
=False):
10580 # We do not want to store the inherited children in a Category because the funcionallity is not used
10581 if not isinstance(self
.getOwner(), Category
):
10582 self
.getAccessController().updateNonInheritingChildren(elem
, delete
)
10583 self
.notify_protection_to_owner(elem
, delete
)
10585 def notify_protection_to_owner(self
, elem
, delete
=False):
10586 self
.getOwner().updateNonInheritingChildren(elem
, delete
)
10588 def setValues( self
, params
):
10589 """Sets all the values of the current material object from a diccionary
10590 containing the following key-value pairs:
10593 Please, note that this method sets ALL values which means that if
10594 the given dictionary doesn't contain any of the keys the value
10595 will set to a default value.
10597 self
.setTitle(params
.get("title", "NO TITLE ASSIGNED"))
10598 self
.setDescription( params
.get( "description", "" ) )
10599 self
.notifyModification()
10601 def clone ( self
, owner
):
10603 mat
.setTitle(self
.getTitle())
10604 mat
.setDescription(self
.getDescription())
10605 mat
.notifyModification()
10607 mat
.setId(self
.getId())
10608 mat
.setOwner(owner
)
10609 mat
.setType(self
.getType())
10611 mat
.setProtection(self
.getAccessController()._getAccessProtection
())
10612 mat
.setAccessKey(self
.getAccessKey())
10613 rlist
= self
.getResourceList()
10615 newres
= r
.clone(mat
)
10616 mat
.addResource(newres
)
10618 mat
.setMainResource(self
.getMainResource())
10622 def notifyModification( self
):
10623 parent
= self
.getOwner()
10625 parent
.notifyModification(raiseEvent
= False)
10626 self
._p
_changed
= 1
10628 def getLocator( self
):
10629 if self
.owner
== None:
10631 lconf
= self
.owner
.getLocator()
10632 lconf
["materialId"] = self
.getId()
10635 def setId( self
, newId
):
10636 self
.id = str(newId
).strip()
10641 def getUniqueId( self
):
10642 """returns (string) the unique identifier of the item"""
10643 """used mainly in the web session access key table"""
10644 return "%sm%s" % (self
.getOwner().getUniqueId(),self
.id)
10646 def setOwner(self
, newOwner
):
10647 self
.owner
= newOwner
10649 def getOwner( self
):
10652 def getCategory( self
):
10653 if isinstance(self
.getOwner(), Category
):
10654 return self
.getOwner()
10657 def getConference( self
):
10658 owner
= self
.getOwner()
10659 if owner
is None or isinstance(owner
, Category
):
10661 elif isinstance(owner
, Conference
):
10664 return owner
.getConference()
10666 def getSession( self
):
10667 if self
.getContribution():
10668 return self
.getContribution().getSession()
10669 if isinstance(self
.getOwner(), Session
):
10670 return self
.getOwner()
10671 if isinstance(self
.getOwner(), SubContribution
):
10672 return self
.getOwner().getSession()
10675 def getContribution( self
):
10676 if self
.getSubContribution():
10677 return self
.getSubContribution().getContribution()
10678 if isinstance(self
.getOwner(), Contribution
):
10679 return self
.getOwner()
10682 def getSubContribution( self
):
10683 if isinstance(self
.getOwner(), SubContribution
):
10684 return self
.getOwner()
10687 @Updates (['MaKaC.conference.Material',
10688 'MaKaC.conference.Minutes',
10689 'MaKaC.conference.Paper',
10690 'MaKaC.conference.Slides',
10691 'MaKaC.conference.Video',
10692 'MaKaC.conference.Poster',
10693 'MaKaC.conference.Reviewing'],'title')
10694 def setTitle( self
, newTitle
):
10695 self
.title
= newTitle
.strip()
10696 self
.notifyModification()
10698 def getTitle( self
):
10701 @Updates (['MaKaC.conference.Material',
10702 'MaKaC.conference.Minutes',
10703 'MaKaC.conference.Paper',
10704 'MaKaC.conference.Slides',
10705 'MaKaC.conference.Video',
10706 'MaKaC.conference.Poster',
10707 'MaKaC.conference.Reviewing'], 'description')
10708 def setDescription( self
, newDescription
):
10709 self
.description
= newDescription
.strip()
10710 self
.notifyModification()
10712 def getDescription( self
):
10713 return self
.description
10715 def setType( self
, newType
):
10716 self
.type = newType
.strip()
10717 self
.notifyModification()
10719 def getType( self
):
10722 def getReviewingState(self
):
10723 """ Returns the reviewing state of a material.
10724 The state is represented by an integer:
10725 0 : there's no reviewing state because the material does not belong to a contribution, or the conference
10726 has not reviewing module enabled, or the module is enabled but the mode is "no reviewing"
10727 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
10728 2 : the material is subject to reviewing, but has not been submitted yet by the author
10729 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
10730 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
10731 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
10733 if isinstance(self
.owner
, Contribution
):
10734 conference
= self
.owner
.getConference()
10735 if conference
.getConfPaperReview().getChoice() == ConferencePaperReview
.NO_REVIEWING
: #conference has no reviewing process
10737 else: #conference has reviewing
10738 #if self.id in reviewableMaterials: #material is reviewable
10739 if isinstance(self
, Reviewing
): #material is reviewable
10740 lastReview
= self
.owner
.getReviewManager().getLastReview()
10741 if lastReview
.isAuthorSubmitted(): #author has submitted
10742 refereeJudgement
= lastReview
.getRefereeJudgement()
10743 if refereeJudgement
.isSubmitted(): #referee has submitted judgement
10744 if refereeJudgement
.getJudgement() == "Accept":
10746 elif refereeJudgement
.getJudgement() == "Reject":
10749 #we should never arrive here because referee judgements that are 'To be corrected'
10750 #or a custom state should imply a new review being created, so the state is back to 2
10751 raise MaKaCError("RefereeJudgement should be 'Accept' or 'Reject' in this method")
10752 else: #referee has not submitted judgement
10754 else: #author has not submitted
10756 else: #material is not reviewable
10758 else: #material does not belong to a contribution
10761 def _getRepository( self
):
10762 dbRoot
= DBMgr
.getInstance().getDBConnection().root()
10764 fr
= dbRoot
["local_repositories"]["main"]
10765 except KeyError, e
:
10766 fr
= fileRepository
.MaterialLocalRepository()
10767 dbRoot
["local_repositories"] = OOBTree()
10768 dbRoot
["local_repositories"]["main"] = fr
10771 def hasFile( self
, name
):
10772 for f
in self
.getResourceList():
10773 if f
.getName() == name
:
10777 def addResource( self
, newRes
, forcedFileId
= None ):
10778 newRes
.setOwner( self
)
10779 newRes
.setId( str( self
.__resourcesIdGen
.newCount() ) )
10780 newRes
.archive( self
._getRepository
(), forcedFileId
= forcedFileId
)
10781 self
.__resources
[newRes
.getId()] = newRes
10782 self
.notifyModification()
10783 Logger
.get('storage').debug("Finished storing resource %s for material %s" % (newRes
.getId(), self
.getLocator()))
10785 def getResourceList(self
, sort
=True):
10786 list = self
.__resources
.values()
10788 list.sort(utils
.sortFilesByName
)
10791 def getNbResources(self
):
10792 return len(self
.__resources
)
10794 def getResourceById( self
, id ):
10795 return self
.__resources
[id]
10797 def removeResource( self
, res
):
10798 if res
.getId() in self
.__resources
.keys():
10799 del self
.__resources
[ res
.getId() ]
10801 self
.notifyModification()
10802 if self
.getMainResource() is not None and \
10803 self
._mainResource
.getId() == res
.getId():
10804 self
._mainResource
= None
10806 def recoverResource(self
, recRes
):
10807 recRes
.setOwner(self
)
10808 self
.__resources
[recRes
.getId()] = recRes
10810 self
.notifyModification()
10812 def getMainResource(self
):
10814 if self
._mainResource
:
10816 except AttributeError:
10817 self
._mainResource
= None
10818 return self
._mainResource
10820 def setMainResource(self
, mr
):
10821 self
._mainResource
= mr
10824 self
.__ac
.unlinkAvatars('access')
10825 for res
in self
.getResourceList():
10826 self
.removeResource( res
)
10827 if self
.getReviewingState():
10828 self
.owner
._reviewManager
= ReviewManager(self
.owner
)
10829 self
.notify_protection_to_owner(self
, delete
=True)
10830 TrashCanManager().add(self
)
10833 TrashCanManager().remove(self
)
10835 def isProtected(self
):
10836 # tells if a material is protected or not
10837 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
10839 def getAccessProtectionLevel( self
):
10840 return self
.__ac
.getAccessProtectionLevel()
10842 def isItselfProtected( self
):
10843 return self
.__ac
.isItselfProtected()
10846 def hasProtectedOwner( self
):
10847 if self
.getOwner() != None:
10848 return self
.getOwner().isProtected()
10852 @Updates (['MaKaC.conference.Material',
10853 'MaKaC.conference.Minutes',
10854 'MaKaC.conference.Paper',
10855 'MaKaC.conference.Slides',
10856 'MaKaC.conference.Video',
10857 'MaKaC.conference.Poster',
10858 'MaKaC.conference.Reviewing'], 'protection', lambda(x
): int(x
))
10860 def setProtection( self
, private
):
10861 self
.__ac
.setProtection( private
)
10862 self
.notify_protection_to_owner(self
)
10863 self
._p
_changed
= 1
10865 def isHidden( self
):
10866 return self
.__ac
.isHidden()
10868 @Updates (['MaKaC.conference.Material',
10869 'MaKaC.conference.Minutes',
10870 'MaKaC.conference.Paper',
10871 'MaKaC.conference.Slides',
10872 'MaKaC.conference.Video',
10873 'MaKaC.conference.Poster',
10874 'MaKaC.conference.Reviewing'], 'hidden')
10875 def setHidden( self
, hidden
):
10876 self
.__ac
.setHidden( hidden
)
10877 self
._p
_changed
= 1
10880 @Updates (['MaKaC.conference.Material',
10881 'MaKaC.conference.Minutes',
10882 'MaKaC.conference.Paper',
10883 'MaKaC.conference.Slides',
10884 'MaKaC.conference.Video',
10885 'MaKaC.conference.Poster',
10886 'MaKaC.conference.Reviewing'], 'accessKey')
10888 def setAccessKey( self
, pwd
="" ):
10889 self
.__ac
.setAccessKey(pwd
)
10890 self
._p
_changed
= 1
10892 def getAccessKey( self
):
10893 return self
.__ac
.getAccessKey()
10895 def grantAccess( self
, prin
):
10896 self
.__ac
.grantAccess( prin
)
10897 if isinstance(prin
, AvatarUserWrapper
):
10898 prin
.linkTo(self
, "access")
10899 self
._p
_changed
= 1
10901 def revokeAccess( self
, prin
):
10902 self
.__ac
.revokeAccess( prin
)
10903 if isinstance(prin
, AvatarUserWrapper
):
10904 prin
.unlinkTo(self
, "access")
10905 self
._p
_changed
= 1
10907 def canView( self
, aw
):
10908 """tells whether the specified user has access to the current object
10909 or any of its sub-objects
10911 if self
.isHidden() and not self
.canAccess( aw
):
10916 def isAllowedToAccess( self
, user
):
10917 return (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess( user
)) or self
.__ac
.canUserAccess( user
) or self
.canUserModify(user
)
10919 def canAccess( self
, aw
):
10921 # Allow harvesters (Invenio, offline cache) to access
10923 if has_request_context() and self
.__ac
.isHarvesterIP(request
.remote_addr
):
10925 #####################################################
10927 # Managers have always access
10928 if self
.canModify(aw
):
10931 canUserAccess
= self
.isAllowedToAccess(aw
.getUser())
10932 canIPAccess
= self
.canIPAccess(request
.remote_addr
)
10933 if not self
.isProtected():
10934 return canUserAccess
or canIPAccess
10936 canKeyAccess
= self
.canKeyAccess(aw
)
10937 return canUserAccess
or canKeyAccess
10939 def canKeyAccess(self
, aw
):
10940 key
= session
.get('accessKeys', {}).get(self
.getUniqueId())
10941 if self
.getAccessKey():
10942 # Material has an access key => require this key
10945 return self
.__ac
.canKeyAccess(key
)
10946 elif self
.getConference():
10947 # If it has no key we check the conference's key
10948 conf_key
= session
.get('accessKeys', {}).get(self
.getConference().getUniqueId())
10949 return self
.getConference().canKeyAccess(aw
, conf_key
)
10952 def grantModification( self
, prin
):
10953 self
.__ac
.grantModification( prin
)
10954 if isinstance(prin
, AvatarUserWrapper
):
10955 prin
.linkTo(self
, "manager")
10956 self
._p
_changed
= 1
10958 def revokeModification( self
, prin
):
10959 self
.__ac
.revokeModification( prin
)
10960 if isinstance(prin
, AvatarUserWrapper
):
10961 prin
.unlinkTo(self
, "manager")
10962 self
._p
_changed
= 1
10964 def canModify(self
, aw_or_user
):
10965 if hasattr(aw_or_user
, 'getUser'):
10966 aw_or_user
= aw_or_user
.getUser()
10967 return self
.canUserModify(aw_or_user
) or (self
.getConference() and self
.getConference().canKeyModify())
10969 def canUserModify( self
, user
):
10970 """Tells whether a user is allowed to modify the current contribution:
10971 only if the user is granted to modify the contribution or the user
10972 can modify any of its upper objects (i.e. conference or session).
10974 return self
.getOwner().canUserModify( user
)
10976 def getModifKey( self
):
10977 return self
.getConference().getModifKey()
10979 def getManagerList( self
):
10980 return self
.__ac
.getModifierList()
10982 def getAllowedToAccessList( self
):
10983 return self
.__ac
.getAccessList()
10985 def requireDomain( self
, dom
):
10986 self
.__ac
.requireDomain( dom
)
10987 self
._p
_changed
= 1
10989 def freeDomain( self
, dom
):
10990 self
.__ac
.freeDomain( dom
)
10991 self
._p
_changed
= 1
10993 def getDomainList( self
):
10994 return self
.__ac
.getRequiredDomainList()
10996 def getAccessController(self
):
10999 def isBuiltin(self
):
11002 class BuiltinMaterial(Material
):
11004 Non-customizable material types
11006 def isBuiltin(self
):
11010 class Reviewing(BuiltinMaterial
):
11012 def __init__( self
, materialData
= None ):
11013 Material
.__init
__( self
, materialData
)
11014 self
.id = "reviewing"
11016 def setId( self
, newId
):
11019 def getContribution(self
):
11020 if isinstance(self
.getOwner(), Review
):
11021 return self
.getOwner().getContribution()
11022 return Material
.getContribution(self
)
11024 class Paper(BuiltinMaterial
):
11026 def __init__( self
, materialData
= None ):
11027 Material
.__init
__( self
, materialData
)
11030 def setId( self
, newId
):
11035 class Slides(BuiltinMaterial
):
11037 def __init__( self
, materialData
= None ):
11038 Material
.__init
__( self
, materialData
)
11041 def setId( self
, newId
):
11046 class Video(BuiltinMaterial
):
11048 def __init__( self
, materialData
= None ):
11049 Material
.__init
__( self
, materialData
)
11052 def setId( self
, newId
):
11055 class Poster(BuiltinMaterial
):
11057 def __init__( self
, materialData
= None ):
11058 Material
.__init
__( self
, materialData
)
11061 def setId( self
, newId
):
11064 class Minutes(BuiltinMaterial
):
11066 def __init__( self
, materialData
= None ):
11067 Material
.__init
__( self
, materialData
)
11068 self
.id = "minutes"
11069 self
.title
= "Minutes"
11072 def clone ( self
, owner
):
11074 mat
.setTitle(self
.getTitle())
11075 mat
.setDescription(self
.getDescription())
11076 mat
.notifyModification()
11078 mat
.setId(self
.getId())
11079 mat
.setOwner(owner
)
11080 mat
.setType(self
.getType())
11082 mat
.setProtection(self
.getAccessController()._getAccessProtection
())
11083 mat
.setAccessKey(self
.getAccessKey())
11084 lrep
= self
._getRepository
()
11085 flist
= lrep
.getFiles()
11086 rlist
= self
.getResourceList()
11088 if r
.getId()=="minutes":
11089 mat
.setText(self
.getText())
11090 elif isinstance(r
,Link
):
11092 newlink
.setOwner(mat
)
11093 newlink
.setName(r
.getName())
11094 newlink
.setDescription(r
.getDescription())
11095 newlink
.setURL(r
.getURL())
11096 mat
.addResource(newlink
)
11097 elif isinstance(r
,LocalFile
):
11098 newfile
= LocalFile()
11099 newfile
.setOwner(mat
)
11100 newfile
.setName(r
.getName())
11101 newfile
.setDescription(r
.getDescription())
11102 newfile
.setFilePath(r
.getFilePath())
11103 newfile
.setFileName(r
.getFileName())
11104 mat
.addResource(newfile
)
11106 raise Exception( _("Unexpected object type in Resource List : ")+str(type(r
)))
11108 mat
.setMainResource(self
.getMainResource())
11112 def setId( self
, newId
):
11115 def setTitle( self
, newTitle
):
11116 self
.title
= newTitle
.strip()
11117 self
.notifyModification()
11119 def _setFile( self
, forcedFileId
= None ):
11120 #XXX: unsafe; it must be changed by mkstemp when migrating to python 2.3
11121 tmpFileName
= tempfile
.mktemp()
11122 fh
= open(tmpFileName
, "w")
11125 self
.file = LocalFile()
11126 self
.file.setId("minutes")
11127 self
.file.setName("minutes")
11128 self
.file.setFilePath(tmpFileName
)
11129 self
.file.setFileName("minutes.txt")
11130 self
.file.setOwner(self
)
11131 self
.file.archive(self
._getRepository
(), forcedFileId
= forcedFileId
)
11133 def setText( self
, text
, forcedFileId
= None ):
11136 self
._setFile
(forcedFileId
= forcedFileId
)
11137 self
.file.replaceContent( text
)
11138 self
.getOwner().notifyModification()
11140 def getText( self
):
11143 return self
.file.readBin()
11145 def getResourceList(self
, sort
=True):
11146 res
= Material
.getResourceList(self
, sort
=sort
)
11148 res
.insert(0, self
.file)
11151 def getResourceById( self
, id ):
11152 if id.strip() == "minutes":
11154 return Material
.getResourceById( self
, id )
11156 def removeResource(self
, res
):
11157 Material
.removeResource(self
, res
)
11158 if self
.file is not None and res
.getId().strip() == "minutes":
11161 self
.notifyModification()
11163 def recoverResource(self
, recRes
):
11164 if recRes
.getId() == "minutes":
11165 recRes
.setOwner(self
)
11168 self
.notifyModification()
11170 Material
.recoverResource(self
, recRes
)
11173 class Resource(CommonObjectBase
):
11174 """This is the base class for representing individual resources which can
11175 be included in material containers for lately being attached to
11176 conference objects (i.e. conferences, sessions or contributions). This
11177 class provides basic data and operations to handle this resources.
11178 Resources can be of serveral types (files, links, ...) which means
11179 different specialisations of this class.
11181 id -- (string) Allows to assign the resource a unique identifier. It
11182 is normally used to uniquely identify the resource among other
11183 resources included in a certain material.
11184 name -- (string) Short description about the purpose or the contents
11186 description - (string) detailed and varied information about the
11188 __owner - (Material) reference to the material object in which the
11189 current resource is included.
11192 fossilizes(IResourceMinimalFossil
, IResourceFossil
)
11194 def __init__( self
, resData
= None ):
11195 self
.id = "not assigned"
11197 self
.description
= ""
11199 self
.__ac
= AccessController(self
)
11200 self
.pdfConversionRequestDate
= None
11202 def __cmp__(self
, other
):
11203 if type(self
) is not type(other
):
11204 # This is actually dangerous and the ZODB manual says not to do this
11205 # because it relies on memory order. However, this branch should never
11206 # be taken anyway since we do not store different types in the same set
11207 # or use them as keys.
11208 return cmp(hash(self
), hash(other
))
11209 if self
.getConference() == other
.getConference():
11210 return cmp(self
.getId(), other
.getId())
11211 return cmp(self
.getConference(), other
.getConference())
11213 def clone( self
, conf
, protection
=True ):
11214 res
= self
.__class
__()
11215 res
.setName(self
.getName())
11216 res
.setDescription(self
.getDescription())
11218 res
.notifyModification()
11219 res
.setId(self
.getId())
11222 res
.setProtection(self
.getAccessController()._getAccessProtection
())
11223 #res.__ac = self.getAccessController()
11227 def notifyModification( self
):
11228 parent
= self
.getOwner()
11230 parent
.setModificationDate()
11231 self
._p
_changed
= 1
11233 def getLocator( self
):
11234 if self
._owner
== None:
11236 lconf
= self
._owner
.getLocator()
11237 lconf
["resId"] = self
.getId()
11240 def setId( self
, newId
):
11241 self
.id = newId
.strip()
11246 def getUniqueId( self
):
11247 """returns (string) the unique identifier of the item
11248 used mainly in the web session access key table
11249 for resources, it is the same as the father material since
11250 only the material can be protected with an access key"""
11251 return self
.getOwner().getUniqueId()
11253 def setOwner(self
, newOwner
):
11254 self
._owner
= newOwner
11256 def getOwner( self
):
11259 def getCategory( self
):
11260 #raise "%s:%s:%s"%(self.getOwner(), Material, isinstance(self.getOwner, Material))
11262 if isinstance(self
.getOwner(), Category
):
11263 return self
.getOwner()
11264 if isinstance(self
.getOwner(), Material
):
11265 return self
.getOwner().getCategory()
11268 def getConference( self
):
11269 # this check owes itself to the fact that some
11270 # protection checking functions call getConference()
11271 # directly on resources, without caring whether they
11272 # are owned by Conferences or Categories
11273 if self
._owner
is None or isinstance(self
._owner
, Category
):
11276 return self
._owner
.getConference()
11278 def getSession( self
):
11279 return self
._owner
.getSession()
11281 def getContribution( self
):
11282 return self
._owner
.getContribution()
11284 def getSubContribution( self
):
11285 return self
._owner
.getSubContribution()
11287 @Updates (['MaKaC.conference.Link',
11288 'MaKaC.conference.LocalFile'], 'name')
11289 def setName( self
, newName
):
11290 self
.name
= newName
.strip()
11291 self
.notifyModification()
11293 def getName( self
):
11296 @Updates (['MaKaC.conference.Link',
11297 'MaKaC.conference.LocalFile'], 'description')
11298 def setDescription( self
, newDesc
):
11299 self
.description
= newDesc
.strip()
11300 self
.notifyModification()
11302 def getDescription( self
):
11303 return self
.description
11305 def archive( self
, repository
= None, forcedFileId
= None ):
11306 """performs necessary operations to ensure the archiving of the
11307 resource. By default is doing nothing as the persistence of the
11308 system already ensures the archiving of the basic resource data"""
11312 if self
._owner
is not None:
11313 self
.notify_protection_to_owner(delete
=True)
11314 self
._owner
.removeResource(self
)
11315 self
.__ac
.unlinkAvatars('access')
11317 TrashCanManager().add(self
)
11320 TrashCanManager().remove(self
)
11322 def isProtected(self
):
11323 # tells if a resource is protected or not
11324 return (self
.hasProtectedOwner() + self
.getAccessProtectionLevel()) > 0
11326 def getAccessProtectionLevel( self
):
11327 return self
.__ac
.getAccessProtectionLevel()
11329 def isItselfProtected( self
):
11330 return self
.__ac
.isItselfProtected()
11332 def hasProtectedOwner( self
):
11333 if self
.getOwner() != None:
11334 return self
.getOwner().isProtected()
11337 def notify_protection_to_owner(self
, delete
=False):
11338 # Resources can be attached to other objects (e.g. Registrant),
11339 # but we wish to trigger the notification only when attached to materials (except paper reviewing)
11340 if isinstance(self
.getOwner(), Material
) and not isinstance(self
.getOwner(), Reviewing
):
11341 self
.getOwner().updateNonInheritingChildren(self
, delete
)
11343 @Updates (['MaKaC.conference.Link',
11344 'MaKaC.conference.LocalFile'],'protection', lambda(x
): int(x
))
11346 def setProtection( self
, private
):
11347 self
.__ac
.setProtection( private
)
11348 self
.notify_protection_to_owner()
11350 def grantAccess( self
, prin
):
11351 self
.__ac
.grantAccess( prin
)
11352 if isinstance(prin
, AvatarUserWrapper
):
11353 prin
.linkTo(self
, "access")
11355 def revokeAccess( self
, prin
):
11356 self
.__ac
.revokeAccess( prin
)
11357 if isinstance(prin
, AvatarUserWrapper
):
11358 prin
.unlinkTo(self
, "access")
11360 def canView( self
, aw
):
11361 """tells whether the specified user has access to the current object
11362 or any of its sub-objects
11364 return self
.canAccess( aw
)
11366 def isAllowedToAccess( self
, user
):
11367 return self
.__ac
.canUserAccess( user
) or self
.canUserModify( user
) or (not self
.isItselfProtected() and self
.getOwner().isAllowedToAccess( user
))
11369 def canAccess( self
, aw
):
11370 # Allow harvesters (Invenio, offline cache) to access
11372 if has_request_context() and self
.__ac
.isHarvesterIP(request
.remote_addr
):
11374 #####################################################
11376 # Managers have always access
11377 if self
.canModify(aw
):
11380 if not self
.canIPAccess(request
.remote_addr
) and not self
.canUserModify(aw
.getUser()) and \
11381 not self
.isAllowedToAccess(aw
.getUser()):
11383 if not self
.isProtected():
11385 flag
= self
.isAllowedToAccess( aw
.getUser() )
11386 return flag
or self
.canKeyAccess(aw
) or self
.getOwner().canKeyAccess(aw
) or \
11387 (self
.getConference() != None and self
.getConference().canKeyAccess(aw
) and self
.getAccessKey() == "") or \
11388 (self
.getConference() != None and self
.getConference().canKeyAccess(aw
) and self
.getAccessKey() == self
.getConference().getAccessKey())
11390 def grantModification( self
, prin
):
11391 self
.__ac
.grantModification( prin
)
11393 def revokeModification( self
, prin
):
11394 self
.__ac
.revokeModification( prin
)
11396 def canModify(self
, aw_or_user
):
11397 if hasattr(aw_or_user
, 'getUser'):
11398 aw_or_user
= aw_or_user
.getUser()
11399 return self
.canUserModify(aw_or_user
) or (self
.getConference() and self
.getConference().canKeyModify())
11401 def canUserModify( self
, user
):
11402 """Tells whether a user is allowed to modify the current contribution:
11403 only if the user is granted to modify the contribution or the user
11404 can modify any of its upper objects (i.e. conference or session).
11406 return self
.getOwner().canUserModify( user
)
11408 def getModifKey( self
):
11409 return self
.getConference().getModifKey()
11411 def getManagerList( self
):
11412 return self
.__ac
.getModifierList()
11414 def getAllowedToAccessList( self
):
11415 return self
.__ac
.getAccessList()
11417 def getURL( self
):
11420 def requireDomain( self
, dom
):
11421 self
.__ac
.requireDomain( dom
)
11423 def freeDomain( self
, dom
):
11424 self
.__ac
.freeDomain( dom
)
11426 def getDomainList( self
):
11427 return self
.__ac
.getRequiredDomainList()
11429 def getAccessController(self
):
11432 def getAccessKey(self
):
11433 if self
.getOwner() is not None:
11434 return self
.getOwner().getAccessKey()
11437 def canKeyAccess(self
, aw
):
11438 accessKey
= self
.getAccessKey()
11439 key
= session
.get('accessKeys', {}).get(self
.getUniqueId())
11442 elif accessKey
and key
== accessKey
:
11444 elif not accessKey
and key
== self
.getConference().getAccessKey():
11448 def getReviewingState(self
):
11449 """ Returns the reviewing state of a resource, which is the reviewing state of the material to which it belongs.
11450 The state is represented by an integer:
11451 0 : there's no reviewing state because the resource doesn't belong to a material,
11452 the material does not belong to a contribution, or the conference does not have reviewing.
11453 1 : the material is not subject to reviewing, because this kind of material is not reviewable in the conference
11454 2 : the material is subject to reviewing, but has not been submitted yet by the author
11455 3 : the material is subject to reviewing, has been submitted by the author, but has not been judged yet
11456 4 : the material is subject to reviewing, has been submitted by the author, and has been judged as Accepted
11457 5 : the material is subject to reviewing, has been submitted by the author, and has been judged as Rejected
11459 if isinstance(self
.getOwner(), Material
):
11460 return self
.getOwner().getReviewingState()
11461 else: #ressource does not belong to a material
11464 def setPDFConversionRequestDate( self
, newPdfConversionRequestDate
):
11465 self
.pdfConversionRequestDate
= newPdfConversionRequestDate
11467 def getPDFConversionStatus(self
):
11469 if not hasattr(self
, "pdfConversionRequestDate"):
11470 self
.pdfConversionRequestDate
= None
11472 if self
.pdfConversionRequestDate
is not None and self
.pdfConversionRequestDate
+ timedelta(seconds
=50) > nowutc() :
11473 return 'converting'
11476 class Link(Resource
):
11477 """Specialises Resource class in order to represent web links. Objects of
11478 this class will contain necessary information to include in a conference
11479 object links to internet resources through a URL.
11481 url -- (string) Contains the URL to the internet target resource.
11484 fossilizes(ILinkMinimalFossil
, ILinkFossil
)
11486 def __init__( self
, resData
= None ):
11487 Resource
.__init
__( self
, resData
)
11490 def clone( self
, conf
):
11491 link
= Resource
.clone(self
, conf
)
11492 link
.setURL(self
.getURL())
11495 @Updates ('MaKaC.conference.Link', 'url')
11496 def setURL( self
, newURL
):
11497 self
.url
= newURL
.strip()
11498 self
.notifyModification()
11500 def getURL( self
):
11503 def getLocator(self
):
11504 locator
= Resource
.getLocator(self
)
11505 locator
['fileExt'] = 'link'
11508 class LocalFile(Resource
):
11509 """Specialises Resource class in order to represent files which can be
11510 stored in the system. The user can choose to use the system as an
11511 archive of electronic files so he may want to attach a file which is
11512 in his computer to a conference so it remains there and must be kept
11513 in the system. This object contains the file basic metadata and provides
11514 the necessary operations to ensure the corresponding file is archived
11515 (it uses one of the file repositories of the system to do so) and keeps
11516 the reference for being able to access it afterwards.
11518 fileName -- (string) Name of the file. Normally the original name of
11519 the user submitted file is kept.
11520 filePath -- (string) If it is set, it contains a local path to the
11521 file submitted by the user and uploaded in the system. This
11522 attribute is only temporary used so it keeps a pointer to a
11523 temporary uploaded file.
11524 __repository -- (FileRep) Once a file is archived, it is kept in a
11525 FileRepository for long term. This attribute contains a pointer
11526 to the file repository where the file is kept.
11527 __archivedId -- (string) It contains a unique identifier for the file
11528 inside the repository where it is archived.
11531 fossilizes(ILocalFileMinimalFossil
, ILocalFileFossil
, ILocalFileExtendedFossil
, ILocalFileAbstractMaterialFossil
)
11533 def __init__( self
, resData
= None ):
11534 Resource
.__init
__( self
, resData
)
11538 self
.__repository
= None
11539 self
.__archivedId
= ""
11541 def clone( self
, conf
, protection
=True ):
11542 localfile
= Resource
.clone(self
, conf
, protection
)
11543 localfile
.setFilePath(self
.getFilePath())
11544 localfile
.setFileName(self
.getFileName())
11547 def getLocator(self
):
11548 locator
= Resource
.getLocator(self
)
11549 if self
.fileName
== 'minutes.txt' and isinstance(self
._owner
, Minutes
):
11550 # Hack to get a html extension when viewing minutes
11551 locator
['fileExt'] = 'html'
11554 locator
['fileExt'] = (self
.fileType
.lower() or
11555 os
.path
.splitext(self
.fileName
)[1].lower().lstrip('.') or None)
11557 locator
['fileExt'] = 'bin' # no extension => use a dummy
11560 def setFileName( self
, newFileName
, checkArchive
=True ):
11561 """While the file is not archived sets the file name of the current
11562 object to the one specified (if a full path is specified the
11563 base name is extracted) replacing on it blanks by underscores.
11565 if checkArchive
and self
.isArchived():
11566 raise MaKaCError( _("The file name of an archived file cannot be changed"), _("File Archiving"))
11567 #Using os.path.basename is not enough as it only extract filenames
11568 # correclty depending on the server platform. So we need to convert
11569 # to the server platform and apply the basename extraction. As I
11570 # couldn't find a python function for this this is done manually
11571 # although it can contain errors
11572 #On windows basename function seems to work properly with unix file
11574 if newFileName
.count("/"):
11576 newFileName
= newFileName
.split("/")[-1]
11578 #windows file path: there "/" is not allowed on windows paths
11579 newFileName
= newFileName
.split("\\")[-1]
11580 self
.fileName
= newFileName
.strip().replace(" ", "_")
11582 def getFileName( self
):
11583 return self
.fileName
11585 def getFileType( self
):
11586 fileExtension
= os
.path
.splitext( self
.getFileName() )[1]
11587 if fileExtension
!= "":
11588 fileExtension
= fileExtension
[1:]
11589 cfg
= Config
.getInstance()
11590 if cfg
.getFileType( fileExtension
) != "":
11591 return cfg
.getFileType( fileExtension
)
11593 return fileExtension
11595 def setFilePath( self
, filePath
):
11596 if self
.isArchived():
11597 raise MaKaCError( _("The path of an archived file cannot be changed"), _("File Archiving"))
11598 if not os
.access( filePath
.strip(), os
.F_OK
):
11599 raise Exception( _("File does not exist : %s")%filePath
.strip())
11600 self
.filePath
= filePath
.strip()
11602 def getCreationDate( self
):
11603 return self
.__repository
.getCreationDate(self
.__archivedId
)
11605 def getFilePath( self
):
11606 if not self
.isArchived():
11607 return self
.filePath
11608 return self
.__repository
.getFilePath(self
.__archivedId
)
11610 def getSize( self
):
11611 if not self
.isArchived():
11612 return int(os
.stat(self
.getFilePath())[stat
.ST_SIZE
])
11613 return self
.__repository
.getFileSize( self
.__archivedId
)
11615 def setArchivedId( self
, rep
, id ):
11616 self
.__repository
= rep
11617 self
.__archivedId
= id
11619 def getRepositoryId( self
):
11620 return self
.__archivedId
11622 def setRepositoryId(self
, id):
11623 self
.__archivedId
= id
11625 def isArchived( self
):
11626 return self
.__repository
!= None and self
.__archivedId
!= ""
11628 def readBin( self
):
11629 if not self
.isArchived():
11630 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11631 return self
.__repository
.readFile( self
.__archivedId
)
11633 def replaceContent( self
, newContent
):
11634 if not self
.isArchived():
11635 raise MaKaCError( _("File not available until it has been archived") , _("File Archiving"))
11636 self
.__repository
.replaceContent( self
.__archivedId
, newContent
)
11638 def archive( self
, repository
=None, forcedFileId
= None ):
11639 if self
.isArchived():
11640 raise Exception( _("File is already archived"))
11642 raise Exception( _("Destination repository not set"))
11643 if self
.filePath
== "":
11644 return _("Nothing to archive")
11645 repository
.storeFile( self
, forcedFileId
= forcedFileId
)
11647 self
.notifyModification()
11649 def unArchive(self
):
11651 self
.__repository
= None
11652 self
.__archivedId
= ""
11655 if not self
.isArchived():
11656 raise Exception( _("File is not archived, so it cannot be recovered."))
11657 if not self
.__repository
:
11658 raise Exception( _("Destination repository not set."))
11659 self
.__repository
.recoverFile(self
)
11660 Resource
.recover(self
)
11661 self
.notifyModification()
11663 def delete( self
):
11664 if not self
.isArchived():
11665 os
.remove( self
.getFilePath() )
11667 self
.__repository
.retireFile( self
)
11668 except AttributeError, e
:
11670 Resource
.delete( self
)
11672 def getRepository(self
):
11673 return self
.__repository
11675 def __str__( self
):
11676 return self
.getFileName()
11679 class TCIndex( Persistent
):
11680 """Index for conference track coordinators.
11682 This class allows to index conference track coordinators so the owner
11683 can answer optimally to the query if a user is coordinating
11684 any conference track.
11685 It is implemented by simply using a BTree where the Avatar id is used
11686 as key (because it is unique and non variable) and a list of
11687 coordinated tracks is kept as keys. It is the responsability of the
11688 index owner (conference) to keep it up-to-date i.e. notify track
11689 coordinator additions and removals.
11692 def __init__( self
):
11693 self
._idx
= OOBTree()
11696 def getTracks( self
, av
):
11697 """Gives a list with the tracks a user is coordinating.
11701 return self
._idx
.get( av
.getId(), [] )
11703 def indexCoordinator( self
, av
, track
):
11704 """Registers in the index a coordinator of a track.
11706 if av
== None or track
== None:
11708 if not self
._idx
.has_key( av
.getId() ):
11711 l
= self
._idx
[av
.getId()]
11714 # necessary, otherwise ZODB won't know it needs to update the BTree
11715 self
._idx
[av
.getId()] = l
11716 self
.notifyModification()
11718 def unindexCoordinator( self
, av
, track
):
11719 if av
== None or track
== None:
11721 l
= self
._idx
.get( av
.getId(), [] )
11724 self
._idx
[av
.getId()] = l
11725 self
.notifyModification()
11727 def notifyModification(self
):
11728 self
._p
_changed
= 1
11731 class Track(CoreObject
):
11733 def __init__( self
):
11734 self
.conference
= None
11735 self
.id = "not assigned"
11737 self
.description
= ""
11738 self
.subTracks
= {}
11739 self
.__SubTrackGenerator
= Counter()
11740 self
._abstracts
= OOBTree()
11741 self
._coordinators
= []
11742 self
._contributions
= OOBTree()
11745 def __cmp__(self
, other
):
11746 if type(self
) is not type(other
):
11747 # This is actually dangerous and the ZODB manual says not to do this
11748 # because it relies on memory order. However, this branch should never
11749 # be taken anyway since we do not store different types in the same set
11750 # or use them as keys.
11751 return cmp(hash(self
), hash(other
))
11752 if self
.getConference() == other
.getConference():
11753 return cmp(self
.getId(), other
.getId())
11754 return cmp(self
.getConference(), other
.getConference())
11756 def clone(self
, conference
):
11758 tr
.setConference(conference
)
11759 tr
.setTitle(self
.getTitle())
11760 tr
.setCode(self
.getCode())
11761 tr
.setDescription(self
.getDescription())
11763 for co
in self
.getCoordinatorList() :
11764 tr
.addCoordinator(co
)
11766 for subtr
in self
.getSubTrackList() :
11767 tr
.addSubTrack(subtr
.clone())
11772 def delete( self
):
11773 """Deletes a track from the system. All the associated abstracts will
11774 also be notified so the track is no longer associated to them.
11776 #XXX: Should we allow to delete a track when there are some abstracts
11777 # or contributions submitted for it?!?!?!?!
11779 # we must notify each abstract in the track about the deletion of the
11781 while len(self
._abstracts
)>0:
11782 k
= self
._abstracts
.keys()[0]
11783 abstract
= self
._abstracts
[k
]
11784 del self
._abstracts
[k
]
11785 abstract
.removeTrack( self
)
11787 # we must notify each contribution in the track about the deletion of the
11789 while len(self
._contributions
)>0:
11790 k
= self
._contributions
.keys()[0]
11791 contrib
= self
._contributions
[k
]
11792 del self
._contributions
[k
]
11793 contrib
.removeTrack( self
)
11795 # we must delete and unindex all the possible track coordinators
11796 while len(self
._coordinators
)>0:
11797 self
.removeCoordinator(self
._coordinators
[0])
11799 # we must notify the conference about the track deletion
11800 if self
.conference
:
11801 conf
= self
.conference
11802 self
.conference
= None
11803 conf
.removeTrack( self
)
11805 TrashCanManager().add(self
)
11808 TrashCanManager().remove(self
)
11810 def canModify(self
, aw_or_user
):
11811 return self
.conference
.canModify(aw_or_user
)
11813 def canUserModify( self
, av
):
11814 return self
.conference
.canUserModify( av
)
11816 def canView( self
, aw
):
11817 return self
.conference
.canView( aw
)
11819 def notifyModification( self
):
11820 parent
= self
.getConference()
11822 parent
.setModificationDate()
11823 self
._p
_changed
= 1
11825 def getLocator( self
):
11826 """Gives back a globaly unique identification encapsulated in a Locator
11827 object for the track instance
11829 if self
.conference
== None:
11831 lconf
= self
.conference
.getLocator()
11832 lconf
["trackId"] = self
.getId()
11835 def setConference(self
, conference
):
11836 self
.conference
= conference
11838 def getConference( self
):
11839 return self
.conference
11841 def getOwner( self
):
11842 return self
.getConference()
11844 def setId( self
, newId
):
11845 self
.id = str(newId
)
11850 def setTitle( self
, newTitle
):
11851 self
.title
= newTitle
11852 self
.notifyModification()
11854 def getTitle( self
):
11857 def setDescription(self
, newDescription
):
11858 self
.description
= newDescription
11859 self
.notifyModification()
11861 def getDescription(self
):
11862 return self
.description
11868 except AttributeError:
11872 def setCode(self
,newCode
):
11873 self
._code
=str(newCode
).strip()
11875 def __generateNewSubTrackId( self
):
11876 return str(self
.__SubTrackGenerator
.newCount())
11878 def addSubTrack( self
, newSubTrack
):
11879 """Registers the contribution passed as parameter within the session
11880 assigning it a unique id.
11882 if newSubTrack
in self
.subTracks
.values():
11884 subTrackId
= newSubTrack
.getId()
11885 if subTrackId
== "not assigned":
11886 subTrackId
= self
.__generateNewSubTrackId
()
11887 self
.subTracks
[subTrackId
] = newSubTrack
11888 newSubTrack
.setTrack( self
)
11889 newSubTrack
.setId( subTrackId
)
11890 self
.notifyModification()
11892 def removeSubTrack( self
, subTrack
):
11893 """Removes the indicated contribution from the session
11895 if subTrack
in self
.subTracks
.values():
11896 del self
.subTracks
[ subTrack
.getId() ]
11897 subTrack
.setTrack( None )
11899 self
.notifyModification()
11901 def recoverSubTrack(self
, subTrack
):
11902 self
.addSubTrack(subTrack
)
11905 def newSubTrack( self
):
11907 self
.addSubTrack( st
)
11910 def getSubTrackById( self
, id ):
11911 if self
.subTracks
.has_key( id ):
11912 return self
.subTracks
[ id ]
11915 def getSubTrackList( self
):
11916 return self
.subTracks
.values()
11918 def getAbstractList( self
):
11922 if self
._abstracts
:
11924 except AttributeError:
11925 self
._abstracts
= OOBTree()
11926 return self
._abstracts
.values()
11928 def getAbstractById( self
, id ):
11930 if self
._abstracts
:
11932 except AttributeError:
11933 self
._abstracts
= OOBTree()
11934 return self
._abstracts
.get(str(id).strip())
11936 def hasAbstract( self
, abstract
):
11940 if self
._abstracts
:
11942 except AttributeError:
11943 self
._abstracts
= OOBTree()
11944 return self
._abstracts
.has_key( abstract
.getId() )
11946 def addAbstract( self
, abstract
):
11947 """Adds an abstract to the track abstract list.
11949 Notice that this method doesn't notify the abstract about the track
11952 if not self
.hasAbstract( abstract
):
11953 self
._abstracts
[ abstract
.getId() ] = abstract
11954 #abstract.addTrack( self )
11956 def removeAbstract( self
, abstract
):
11957 """Removes an abstract from the track abstract list.
11959 Notice that this method doesn't notify the abstract about the track
11962 if self
.hasAbstract( abstract
):
11963 del self
._abstracts
[ abstract
.getId() ]
11964 #abstract.removeTrack( self )
11966 def addCoordinator( self
, av
):
11967 """Grants coordination privileges to user.
11970 av -- (AvatarUserWrapper) the user to which
11971 coordination privileges must be granted.
11975 if self
._coordinators
:
11977 except AttributeError, e
:
11978 self
._coordinators
= []
11979 self
.notifyModification()
11981 if not (av
in self
._coordinators
):
11982 self
._coordinators
.append( av
)
11983 self
.getConference().addTrackCoordinator( self
, av
)
11984 av
.linkTo(self
, "coordinator")
11985 self
.notifyModification()
11987 def removeCoordinator( self
, av
):
11988 """Revokes coordination privileges to user.
11991 av -- (AvatarUserWrapper) user for which coordination privileges
11995 if self
._coordinators
:
11997 except AttributeError, e
:
11998 self
._coordinators
= []
11999 self
.notifyModification()
12001 if av
in self
._coordinators
:
12002 self
._coordinators
.remove( av
)
12003 self
.getConference().removeTrackCoordinator( self
, av
)
12004 av
.unlinkTo(self
, "coordinator")
12005 self
.notifyModification()
12007 def isCoordinator( self
, av
):
12008 """Tells whether the specified user is a coordinator of the track.
12011 av -- (AvatarUserWrapper) user to be checke
12013 Return value: (boolean)
12016 if self
._coordinators
:
12018 except AttributeError, e
:
12019 self
._coordinators
= []
12021 return av
in self
._coordinators
12023 def getCoordinatorList( self
):
12024 """Return all users which have privileges to coordinate the track.
12026 Return value: (list)
12029 if self
._coordinators
:
12031 except AttributeError, e
:
12032 self
._coordinators
= []
12034 return self
._coordinators
12036 def canCoordinate( self
, aw
):
12037 """Tells if a user has coordination privileges.
12039 Only track coordinators have coordination privileges over a track.
12042 aw -- (MaKaC.accessControl.AccessWrapper) User access
12043 information for which the coordination privileges must be
12046 Return value: (boolean)
12048 return self
.isCoordinator( aw
.getUser() ) or self
.canModify( aw
)
12050 def addContribution( self
, newContrib
):
12054 if self
._contributions
:
12056 except AttributeError:
12057 self
._contributions
= OOBTree()
12058 if self
._contributions
.has_key( newContrib
.getId() ):
12060 self
._contributions
[ newContrib
.getId() ] = newContrib
12061 newContrib
.setTrack( self
)
12063 def getModifKey( self
):
12064 return self
.getConference().getModifKey()
12066 def removeContribution( self
, contrib
):
12070 if self
._contributions
:
12072 except AttributeError:
12073 self
._contributions
= OOBTree()
12074 if not self
._contributions
.has_key( contrib
.getId() ):
12076 del self
._contributions
[ contrib
.getId() ]
12077 contrib
.setTrack( None )
12079 def hasContribution( self
, contrib
):
12081 if self
._contributions
:
12083 except AttributeError:
12084 self
._contributions
= OOBTree()
12085 return self
._contributions
.has_key( contrib
.getId() )
12087 def getContributionList(self
):
12089 if self
._contributions
:
12091 except AttributeError:
12092 self
._contributions
= OOBTree()
12093 return self
._contributions
.values()
12095 def canUserCoordinate( self
, av
):
12096 return self
.isCoordinator( av
) or self
.canUserModify( av
)
12099 class SubTrack(CoreObject
):
12101 def __init__( self
):
12103 self
.id = "not assigned"
12105 self
.description
= ""
12109 sub
.setDescription(self
.getDescription())
12110 sub
.setTitle(self
.getTitle())
12116 TrashCanManager().add(self
)
12119 TrashCanManager().remove(self
)
12121 def canModify(self
, aw_or_user
):
12122 return self
.track
.canModify(aw_or_user
)
12124 def canView( self
, aw
):
12125 return self
.track
.canView( aw
)
12127 def notifyModification( self
):
12128 parent
= self
.getTrack()
12130 parent
.setModificationDate()
12131 self
._p
_changed
= 1
12133 def getLocator( self
):
12134 """Gives back a globaly unique identification encapsulated in a Locator
12135 object for the session instance
12137 if self
.track
== None:
12139 lconf
= self
.track
.getLocator()
12140 lconf
["subTrackId"] = self
.getId()
12143 def setTrack(self
, track
):
12148 def getTrack( self
):
12151 def getOwner( self
):
12152 return self
.getTrack()
12154 def setId( self
, newId
):
12155 self
.id = str(newId
)
12160 def setTitle( self
, newTitle
):
12161 self
.title
= newTitle
12162 self
.notifyModification()
12164 def getTitle( self
):
12167 def setDescription(self
, newDescription
):
12168 self
.description
= newDescription
12169 self
.notifyModification()
12171 def getDescription(self
):
12172 return self
.description
12175 class ContributionType(Persistent
):
12177 def __init__(self
, name
, description
, conference
):
12180 self
._description
= description
12181 self
._conference
= conference
12186 def setId(self
, id):
12192 def setName(self
, name
):
12195 def getDescription(self
):
12196 return self
._description
12198 def setDescription(self
, desc
):
12199 self
._description
= desc
12201 def getConference(self
):
12202 return self
._conference
12204 def setConference(self
, conf
):
12205 self
._conference
= conf
12207 def getLocator( self
):
12208 if self
._conference
== None:
12210 lconf
= self
._conference
.getLocator()
12211 lconf
["contribTypeId"] = self
.getId()
12214 def canModify(self
, aw_or_user
):
12215 return self
._conference
.canModify(aw_or_user
)
12218 self
.setConference(None)
12219 TrashCanManager().add(self
)
12222 TrashCanManager().remove(self
)
12224 def clone(self
, conference
):
12225 type = ContributionType(self
.getName(), self
.getDescription(),conference
)
12229 class BOAConfig(Persistent
):
12230 """Contains the configuration of the Book of Abstracts of a conference
12232 sortByTypes
= {"number": L_("ID"),
12233 "name": L_("Title"),
12234 "sessionTitle": L_("Session title"),
12235 "speaker": L_("Presenter"),
12236 "schedule": L_("Schedule")}
12238 correspondingAuthorTypes
= {"none": L_("Nobody"),
12239 "submitter": L_("Submitter"),
12240 "speakers": L_("Speakers")}
12242 def __init__(self
,conf
):
12245 self
._showIds
= False
12246 self
._sortBy
= "number"
12247 self
._correspondingAuthor
= "submitter"
12248 self
._modificationDS
= nowutc()
12249 self
._cache
= False
12254 def setText(self
,newText
):
12255 self
._text
=newText
.strip()
12256 self
._notifyModification
()
12258 def getShowIds(self
):
12259 if not hasattr(self
, "_showIds"):
12260 self
._showIds
=False
12261 return self
._showIds
12263 def setShowIds(self
,showIds
):
12264 self
._showIds
=showIds
12265 self
._notifyModification
()
12267 def getSortBy(self
):
12268 if not hasattr(self
, "_sortBy"):
12269 self
._sortBy
="number"
12270 return self
._sortBy
12272 def setSortBy(self
,sortBy
):
12273 self
._sortBy
=sortBy
12274 self
._notifyModification
()
12277 def getSortByTypes():
12278 return BOAConfig
.sortByTypes
12280 def getCorrespondingAuthor(self
):
12281 if not hasattr(self
, "_correspondingAuthor"):
12282 self
._correspondingAuthor
= "submitter"
12283 return self
._correspondingAuthor
12285 def setCorrespondingAuthor(self
, correspondingAuthor
):
12286 self
._correspondingAuthor
= correspondingAuthor
12287 self
._notifyModification
()
12290 def getCorrespondingAuthorTypes():
12291 return BOAConfig
.correspondingAuthorTypes
12293 def isCacheEnabled(self
):
12294 if not hasattr(self
, '_cache'):
12295 self
._cache
= False
12298 def setCache(self
, value
):
12299 self
._cache
= value
;
12301 def _notifyModification(self
):
12302 self
._modificationDS
= nowutc()
12305 def lastChanged(self
):
12306 if not hasattr(self
, '_modificationDS'):
12307 self
._modificationDS
= nowutc()
12308 return self
._modificationDS
12311 class EventCloner(object):
12312 """Base class to let plugins/modules plug into the event cloning mechanism"""
12315 def get_plugin_items(event
):
12316 """Returns the items/checkboxes for the clone options provided by EventCloner"""
12317 plugin_options
= []
12318 for plugin_cloner
in values_from_signal(signals
.event_management
.clone
.send(event
), single_value
=True):
12319 with
plugin_context(plugin_cloner
.plugin
):
12320 for name
, (title
, enabled
, checked
) in plugin_cloner
.get_options().iteritems():
12321 full_name
= plugin_cloner
.full_option_name(name
)
12322 plugin_options
.append((
12324 """<li><input type="checkbox" name="cloners" id="cloner-{0}" value="{0}" {2} {3}>{1}</li>"""
12325 .format(full_name
, title
,
12326 'disabled' if not enabled
else '',
12327 'checked' if checked
and enabled
else '')
12329 return '\n'.join(x
[1] for x
in sorted(plugin_options
))
12332 def clone_event(old_event
, new_event
):
12333 """Calls the various cloning methods"""
12334 selected
= set(request
.values
.getlist('cloners'))
12335 for plugin_cloner
in values_from_signal(signals
.event_management
.clone
.send(old_event
), single_value
=True):
12336 with
plugin_context(plugin_cloner
.plugin
):
12337 selected_options
= {name
for name
, (_
, enabled
, _
) in plugin_cloner
.get_options().iteritems()
12338 if enabled
and plugin_cloner
.full_option_name(name
) in selected
}
12339 plugin_cloner
.clone(new_event
, selected_options
)
12341 def __init__(self
, event
, plugin
=None):
12343 self
.plugin
= plugin
12345 def full_option_name(self
, option
):
12346 return '{}-{}'.format(self
.__module
__, option
)
12348 def get_options(self
):
12349 """Returns a dict containing the clone options.
12351 :return: dict mapping option names to ``title, enabled, checked`` tuples
12353 raise NotImplementedError
12355 def clone(self
, new_event
, options
):
12356 """Performs the actual cloning.
12358 This method is always called, even if no options are selected!
12360 :param new_event: The new event created during the clone
12361 :param options: A set containing the options provided by
12362 this class which the user has selected
12364 raise NotImplementedError