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/>.
19 from BTrees
import OOBTree
20 from persistent
import Persistent
21 from MaKaC
.common
.url
import EndpointURL
23 import MaKaC
.webinterface
.internalPagesMgr
as internalPagesMgr
24 from indico
.core
import signals
25 from indico
.core
.db
import DBMgr
26 from indico
.util
.contextManager
import ContextManager
27 from indico
.util
.i18n
import _
, N_
28 from MaKaC
.common
.Counter
import Counter
29 from MaKaC
.common
.Locators
import Locator
30 from MaKaC
.webinterface
import urlHandlers
31 from MaKaC
.trashCan
import TrashCanManager
32 from MaKaC
.errors
import MaKaCError
33 from MaKaC
.conference
import LocalFile
34 from indico
.util
.signals
import values_from_signal
37 class ConfDisplayMgrRegistery
:
39 Class to get the DisplayMgr for a conference
43 self
._displayMgrRegistery
= None
45 def _getDisplayMgrRegistery( self
):
46 #DBMgr.getInstance().commit()
47 if not self
._displayMgrRegistery
:
48 db_root
= DBMgr
.getInstance().getDBConnection().root()
49 if db_root
.has_key( "displayRegistery" ):
50 self
._displayMgrRegistery
= db_root
["displayRegistery"]
52 self
._displayMgrRegistery
= OOBTree
.OOBTree()
53 db_root
["displayRegistery"] = self
._displayMgrRegistery
54 return self
._displayMgrRegistery
57 def registerDisplayMgr( self
, conference
, dispMgr
):
58 """Associates a given conference with a confDispplayMgr
60 self
._getDisplayMgrRegistery
()[ conference
.getId() ] = dispMgr
62 def getDisplayMgr( self
, conference
, update
=False ):
63 """Gives back the webfactory associated with a given conference or None
64 if no association exists
66 if self
._getDisplayMgrRegistery
().has_key( conference
.getId() ):
67 DM
= self
._getDisplayMgrRegistery
()[ conference
.getId() ]
68 # as the object can just coming out the database, we must update the system link of the menu
70 DM
.getMenu().updateSystemLink()
72 DM
= ConfDisplayMgr(conference
, Menu(conference
))
73 self
.registerDisplayMgr(conference
, DM
)
74 # as the object just coming out the database, we must update the system link of the menu
75 DM
.getMenu().updateSystemLink()
79 class DisplayMgr(Persistent
):
81 base class for the DisplayMgr object
87 class ConfDisplayMgr(DisplayMgr
):
89 DisplayMgr for a conference
92 def __init__(self
, conf
, menu
=None, format
=None, tickerTape
=None):
97 self
._menu
= Menu(self
._conf
, self
)
101 self
._format
= Format()
103 self
._tickerTape
= tickerTape
105 self
._tickerTape
= TickerTape()
106 self
._defaultstyle
= ""
107 #################################
108 # Fermi timezone awareness #
109 #################################
110 self
.defaulttimezone
= ""
111 #################################
112 # Fermi timezone awareness(end) #
113 #################################
115 # Search is enabled, by default
116 self
._searchEnabled
= True
118 #Manager for all the images stored in the conference
119 self
._imagesMngr
= ImagesManager(conf
)
121 #Manager for CSS file rendering the main display page for the conference
122 self
._styleMngr
= StyleManager(conf
)
124 # Displaying navigation bar
125 self
._displayNavigationBar
= True
127 self
._showSocialApps
= True
129 def clone(self
, conf
):
130 newCdm
= ConfDisplayMgrRegistery().getDisplayMgr(conf
, update
=False)
132 newCdm
.setDefaultStyle(self
.getDefaultStyle())
134 self
.getMenu().clone(newCdm
)
136 self
.getFormat().clone(newCdm
)
137 # clone the tickertape
138 self
.getTickerTape().clone(newCdm
)
139 # clone the imagesmanager
140 self
.getImagesManager().clone(newCdm
)
141 # clone the imagesmanager
142 self
.getStyleManager().clone(newCdm
)
145 def getDefaultStyle( self
):
146 """Returns the default view of the conference"""
148 return self
._defaultstyle
150 self
._defaultstyle
= ""
151 return self
._defaultstyle
153 def setDefaultStyle( self
, style
):
154 self
._defaultstyle
= style
156 #################################
157 # Fermi timezone awareness #
158 #################################
159 def getDefaultTimezone(self
):
161 return self
._defaulttimezone
163 self
._defaulttimezone
= ""
164 return self
._defaulttimezone
166 def setDefaultTimezone(self
, tz
):
167 self
._defaulttimezone
= tz
169 #################################
170 # Fermi timezone awareness(end) #
171 #################################
173 def getShowSocialApps(self
):
174 if not hasattr(self
, '_showSocialApps'):
175 self
._showSocialApps
= True
176 return self
._showSocialApps
178 def setShowSocialApps(self
, value
):
179 self
._showSocialApps
= value
181 def getDisplayNavigationBar(self
):
182 if not hasattr(self
, "_displayNavigationBar"):
183 self
._displayNavigationBar
= True
184 return self
._displayNavigationBar
186 def setDisplayNavigationBar(self
, value
):
187 self
._displayNavigationBar
= value
190 if self
._menu
.getParent() is None:
191 self
._menu
.setParent(self
)
192 extra_items
= frozenset(x
.name
for x
in values_from_signal(signals
.event
.sidemenu
.send()))
193 if getattr(self
, 'extra_items', frozenset()) != extra_items
:
194 self
._menu
.updateSystemLink()
195 self
.extra_items
= extra_items
198 def getConference(self
):
205 except AttributeError, e
:
206 self
._format
= Format()
209 def getSearchEnabled(self
):
210 if ContextManager
.get('offlineMode', False):
213 return self
._searchEnabled
214 except AttributeError:
215 self
._searchEnabled
= True
216 return self
._searchEnabled
218 def setSearchEnabled(self
, value
):
219 self
._searchEnabled
= value
221 def getTickerTape(self
):
225 except AttributeError, e
:
226 self
._tickerTape
= TickerTape()
227 return self
._tickerTape
229 def getImagesManager(self
):
233 except AttributeError, e
:
234 self
._imagesMngr
= ImagesManager(self
._conf
)
235 return self
._imagesMngr
237 def getStyleManager(self
):
241 except AttributeError, e
:
242 self
._styleMngr
= StyleManager(self
._conf
)
243 return self
._styleMngr
246 class EventMenuEntry(object):
247 """Defines an endpoint-based conference menu entry.
249 :param endpoint: Name of the endpoint for building the link's target URL
250 :param caption: Caption of the link
251 :param parent: Name of the parent link
252 :param name: Name of the link. Defaults to the endpoint.
253 :param plugin: True if the endpoint is in a plugin
254 :param visible: Callback to set the visibility of the link.
255 Invoked with the event as its only argument,
256 must return True or False.
258 def __init__(self
, endpoint
, caption
, parent
=None, name
=None, plugin
=False, visible
=None):
260 endpoint
= 'plugin_{}'.format(endpoint
)
261 self
.endpoint
= endpoint
262 self
.caption
= caption
263 self
.parent
= parent
or '' # the code actually expects '' and not None for top-level items m(
264 self
.name
= name
or endpoint
265 self
.visible
= visible
268 return hash((self
.endpoint
, self
.name
))
270 def __eq__(self
, other
):
271 return (self
.endpoint
, self
.name
) == (other
.endpoint
, other
.name
)
274 return '<EventMenuEntry({}, {}, {})>'.format(self
.name
, self
.endpoint
, self
.caption
)
277 class Menu(Persistent
):
279 class to configure a menu
282 def __init__(self
, conf
, parent
=None):
284 self
._parent
= parent
286 self
._indent
= " "
287 self
._linkGenerator
= Counter()
288 self
._timetable
_detailed
_view
= False
289 self
._timetable
_layout
= 'normal'
291 def clone(self
, cdm
):
292 newMenu
= cdm
.getMenu()
293 newMenu
.set_timetable_detailed_view(self
.is_timetable_detailed_view())
294 newMenu
.set_timetable_layout(self
.get_timetable_layout())
295 newMenu
._linkGenerator
= self
._linkGenerator
.clone()
297 for link
in self
.getLinkList():
298 newList
.append(link
.clone(newMenu
))
299 if len(newList
) != 0:
300 newMenu
._listLink
= newList
302 # change system links to new event id
303 newMenu
.updateSystemLink()
316 def getConference(self
):
319 def updateSystemLink(self
):
320 systemLinkData
= SystemLinkData(self
._conf
)
321 linksData
= systemLinkData
.getLinkData()
322 linksDataOrderedKeys
= systemLinkData
.getLinkDataOrderedKeys()
324 #remove system links (and sublinks) which are not define in linksData
325 for link
in self
.getAllLinks()[:]:
326 if isinstance(link
, SystemLink
):
327 if link
.getParent() is not None:
328 if not link
.getName() in linksData
:
329 link
.getParent().removeLink(link
)
330 elif link
.getParent().getName() != linksData
[link
.getName()]["parent"]:
331 link
.getParent().removeLink(link
)
332 elif link
.getName() not in linksData
:
333 # link was removed from the list
334 self
.removeLink(link
)
336 #Now, update the system links
337 for name
in linksDataOrderedKeys
:
338 data
= linksData
[name
]
339 link
= self
.getLinkByName(name
)
341 # only update the caption if it has been already customized
342 if not link
.wasChanged() or link
.getCaption() == '':
343 link
.setCaption(data
["caption"], silent
=True)
344 link
.setURLHandler(data
["URL"])
345 link
.setDisplayTarget(data
.get("displayTarget",""))
347 #we must create the link
348 self
._createSystemLink
(name
, linksData
)
350 def _createSystemLink(self
, name
, linksData
):
351 data
= linksData
.get(name
, None)
353 raise MaKaCError(_("error in the system link structure of the menu"))
354 if data
["parent"] == "":
355 #create the link at the fisrt level
356 link
= SystemLink(name
)
357 link
.setCaption(data
["caption"], silent
=True)
358 link
.setURLHandler(data
["URL"])
361 if data
.get("visibilityByDefault", True):
364 #We must check if the parent exist
365 parent
= self
.getLinkByName(data
["parent"])
367 self
._createSystemLink
(data
["parent"], linksData
)
368 parent
= self
.getLinkByName(data
["parent"])
369 #We can create the link under the parent
370 link
= SystemLink(name
)
371 link
.setCaption(data
["caption"], silent
=True)
372 link
.setURLHandler(data
["URL"])
375 if data
.get("visibilityByDefault", True):
378 def _generateNewLinkId( self
):
379 """Returns a new unique identifier for the current conference
382 return str(self
._linkGenerator
.newCount())
384 def linkHasToBeDisplayed(self
, link
):
385 if isinstance(link
, SystemLink
):
386 if link
.getName()=="CFA" or link
.getName()=="abstractsBook" or link
.getName()=="mytracks" or link
.getName()=="manageTrack":
387 return self
.getConference().hasEnabledSection("cfa")
388 elif link
.getName()=="registrationForm" or link
.getName()=="registrants":
389 return self
.getConference().hasEnabledSection("regForm")
395 def getLocator( self
):
396 """Gives back a globaly unique identification encapsulated in a Locator
397 object for the session instance
399 if self
._parent
== None:
401 lconf
= self
._parent
.getConference().getLocator()
404 def setParent(self
, parent
):
405 self
._parent
= parent
413 def setIndent(self
, indent
):
414 self
._indent
= indent
416 def addLink(self
, link
):
417 self
._listLink
.append(link
)
421 id = self
._generateNewLinkId
()
425 def removeLink(self
, link
):
426 if link
in self
._listLink
:
427 self
._listLink
.remove(link
)
431 def upLink(self
, link
):
432 if link
in self
._listLink
:
433 index
= self
._listLink
.index(link
)
435 while newindex
>= 0 and not self
.linkHasToBeDisplayed(self
._listLink
[newindex
]):
437 self
._listLink
.remove(link
)
439 self
._listLink
.insert(newindex
, link
)
441 self
._listLink
.append(link
)
445 def downLink(self
, link
):
446 if link
in self
._listLink
:
447 index
= self
._listLink
.index(link
)
449 while newindex
< len(self
._listLink
) and not self
.linkHasToBeDisplayed(self
._listLink
[newindex
]):
451 self
._listLink
.remove(link
)
452 if newindex
<= len(self
._listLink
):
453 self
._listLink
.insert(newindex
, link
)
455 self
._listLink
.insert(0, link
)
458 def getLinkById(self
, id):
459 for link
in self
._listLink
:
460 if link
.getId() == id:
462 ret
= link
.getLinkById(id)
467 def getLinkByName(self
, name
):
468 for link
in self
._listLink
:
469 if link
.getName() == name
:
471 ret
= link
.getLinkByName(name
)
476 def getAllLinks(self
):
478 for link
in self
._listLink
:
479 if isinstance(link
,Spacer
):
482 l
.extend(link
._listLink
)
485 def getLinkList(self
):
486 return self
._listLink
488 def getEnabledLinkList(self
):
490 for link
in self
._listLink
:
495 def isCurrentItem(self
, item
):
496 return self
.getCurrentItem() == item
498 def setCurrentItem(self
, value
):
499 self
._v
_currentItem
= value
501 def getCurrentItem(self
):
502 return getattr(self
, '_v_currentItem', None)
504 def set_timetable_layout(self
, layout
):
505 self
._timetable
_layout
= layout
507 def toggle_timetable_layout(self
):
508 if self
._timetable
_layout
== 'normal':
509 self
.set_timetable_layout('room')
511 self
.set_timetable_layout('normal')
513 def get_timetable_layout(self
):
515 return self
._timetable
_layout
516 except AttributeError:
517 self
._timetable
_layout
= 'normal'
518 return self
._timetable
_layout
520 def set_timetable_detailed_view(self
, view
):
521 self
._timetable
_detailed
_view
= view
523 def is_timetable_detailed_view(self
):
525 return self
._timetable
_detailed
_view
526 except AttributeError:
527 self
._timetable
_detailed
_view
= False
528 return self
._timetable
_detailed
_view
532 for link
in self
._listLink
:
538 class Spacer(Persistent
):
541 def __init__(self
, name
="", parent
=None):
544 self
._parent
= parent
548 def clone(self
, newMenu
):
549 newSpacer
= Spacer(name
=self
.getName(),parent
=newMenu
)
550 newSpacer
.setId(self
.getId())
551 newSpacer
.setEnabled(self
.isEnabled())
563 self
._name
= "spacer %s"%id
565 def getLocator( self
):
566 """Gives back a globaly unique identification encapsulated in a Locator
567 object for the session instance
569 if self
._parent
== None:
571 lparent
= self
._parent
.getLocator()
572 lparent
["linkId"] = self
.getId()
575 def getLinkById(self
, id):
578 def getLinkByName(self
, name
):
581 def setParent(self
, parent
):
582 self
._parent
= parent
593 def setEnabled(self
, value
):
602 def setName(self
, name
):
608 def __str__(self
, indent
=""):
609 str = """%s<br>\n"""%indent
616 except AttributeError:
618 return self
._v
_visible
620 def setVisible(self
,newValue
=True):
621 self
._v
_visible
=newValue
624 TrashCanManager().add(self
)
627 TrashCanManager().remove(self
)
630 class Link(Persistent
):
632 base class for the links of a menu
636 def __init__(self
, name
, parent
=None):
640 self
._parent
= parent
644 self
._displayTarget
= ""
655 def getLocator( self
):
656 """Gives back a globaly unique identification encapsulated in a Locator
657 object for the session instance
659 if self
._parent
== None:
661 lparent
= self
._parent
.getLocator()
662 lparent
["linkId"] = self
.getId()
665 def _generateNewLinkId( self
):
666 """Returns a new unique identifier for the current conference
670 return self
._parent
._generateNewLinkId
()
672 def setParent(self
, parent
):
673 self
._parent
= parent
678 def getDisplayTarget(self
):
680 if self
._displayTarget
:
682 except AttributeError, e
:
683 self
._displayTarget
= "_blank"
684 return self
._displayTarget
686 def setDisplayTarget(self
, t
):
687 self
._displayTarget
= t
690 previousState
= self
._active
692 if not previousState
:
693 for link
in self
._listLink
:
696 self
._parent
.enable()
700 for link
in self
._listLink
:
704 def setEnabled(self
, enable
):
713 def setName(self
, name
):
719 def setCaption(self
, caption
):
720 self
._caption
= caption
722 def getCaption(self
):
725 def addLink(self
, link
):
726 self
._listLink
.append(link
)
730 id = self
._generateNewLinkId
()
734 def removeLink(self
, link
):
735 if link
in self
._listLink
:
736 self
._listLink
.remove(link
)
740 def upLink(self
, link
):
741 if link
in self
._listLink
:
742 if self
._listLink
.index(link
) != 0:
743 index
= self
._listLink
.index(link
)
744 sb
= self
._listLink
.pop(index
)
745 self
._listLink
.insert(index
-1, sb
)
748 def downLink(self
, link
):
749 if link
in self
._listLink
:
750 if self
._listLink
.index(link
) < len(self
._listLink
)-1:
751 index
= self
._listLink
.index(link
)
752 sb
= self
._listLink
.pop(index
)
753 self
._listLink
.insert(index
+1, sb
)
756 def getLinkByName(self
, name
):
757 for link
in self
._listLink
:
758 if link
.getName() == name
:
760 ret
= link
.getLinkByName(name
)
765 def getLinkById(self
, id):
766 for link
in self
._listLink
:
767 if link
.getId() == id:
769 ret
= link
.getLinkById(id)
774 def getLinkList(self
):
775 return self
._listLink
777 def getEnabledLinkList(self
):
779 for link
in self
._listLink
:
787 def __str__(self
, indent
=""):
788 str = """%s<a href="%s">%s</a><br>\n"""%(indent
, self
.getURL(), self
.getName())
789 for link
in self
._listLink
:
791 str += "%s\n"%link
.__str
__(indent
+ " ")
798 except AttributeError:
800 return self
._v
_visible
802 def setVisible(self
,newValue
=True):
803 self
._v
_visible
=newValue
806 for l
in self
.getLinkList()[:]:
808 TrashCanManager().add(self
)
811 TrashCanManager().remove(self
)
815 Go up till the "parent menu" is found
817 if isinstance(self
._parent
, Menu
):
820 return self
._parent
.getMenu()
822 class SystemLink(Link
):
824 class for link which target a system part
825 The user cannot change the link data
826 The URL is dynamicly generated
830 def __init__(self
, name
, parent
=None, changed
=False):
831 Link
.__init
__(self
, name
, parent
)
833 # by default, this link will be updated when there are version
834 # changes that modify its default name
835 self
._changed
= changed
837 def clone(self
, newMenu
):
838 newLink
= SystemLink(self
.getName(), parent
=newMenu
, changed
=self
.wasChanged())
839 newLink
.setEnabled(self
.isEnabled())
840 newLink
.setVisible(self
.isVisible())
841 newLink
.setId(self
.getId())
842 newLink
.setDisplayTarget(self
.getDisplayTarget())
843 newLink
.setCaption(self
.getCaption(), silent
=True)
844 newLink
.setURLHandler(self
.getURLHandler())
847 for link
in self
.getLinkList():
848 listLink
.append(link
.clone(newLink
))
850 newLink
._listLink
= listLink
854 def wasChanged(self
):
855 # old conferences, before `_changed` was introduced
856 if hasattr(self
, '_changed'):
859 # for old conferences, just keeps things as people
863 def _getURLObject(self
):
864 # TOREMOVE: fix events with "absolute" URL
865 if not hasattr(self
, '_URLHandler'):
866 self
.getMenu().updateSystemLink()
867 if isinstance(self
._URLHandler
, basestring
):
868 if self
._URLHandler
.startswith("http"): # Fix for hardcoded URLs
869 self
.getMenu().updateSystemLink()
870 if '.' in self
._URLHandler
:
871 return EndpointURL(self
._URLHandler
,
872 urlHandlers
.URLHandler
._want
_secure
_url
(),
873 urlHandlers
.URLHandler
._getParams
(self
.getMenu().getConference(), {}))
875 handler
= getattr(urlHandlers
, self
._URLHandler
)
877 handler
= self
._URLHandler
878 return handler
.getURL(self
.getMenu().getConference())
881 url
= str(self
._getURLObject
())
882 if self
._name
== 'timetable':
883 menu
= self
.getMenu()
884 if menu
.get_timetable_layout() == 'room':
886 if menu
.is_timetable_detailed_view():
887 startDate
= menu
.getConference().getSchedule().getAdjustedStartDate()
888 url
+= startDate
.strftime('#%Y%m%d')
892 def getURLHandler(self
):
893 if not hasattr(self
, '_URLHandler'):
894 self
.getMenu().updateSystemLink()
895 return self
._URLHandler
897 def setURLHandler(self
, url
):
898 self
._URLHandler
= url
900 def getCaption(self
):
903 def setCaption(self
, caption
, silent
=False):
904 self
._caption
= caption
907 # if the caption was changed, do not update it when the default
908 # value get an update
912 return self
._getURLObject
().valid
and super(SystemLink
, self
).isVisible()
915 class SystemLinkData(object):
916 def __init__(self
, conf
=None):
917 plugin_entries
= None
918 if not hasattr(self
, '_linkData') or not hasattr(self
, '_linkDataOrderedKeys'):
919 plugin_entries
= values_from_signal(signals
.event
.sidemenu
.send())
920 #the following dict is used to update the system link of the menu. each new entry is added to the menu,
921 #and all entries in the menu whiche are not is this dict are removed.
922 if not hasattr(self
, "_linkData"):
925 "caption": N_("Overview"),
926 "URL": 'UHConferenceOverview',
929 "caption": N_("Scientific Programme"),
930 "URL": 'UHConferenceProgram',
933 "caption": N_("Call for Abstracts"),
934 "URL": 'UHConferenceCFA',
937 "caption": N_("View my Abstracts"),
938 "URL": 'UHUserAbstracts',
941 "caption": N_("Submit Abstract"),
942 "URL": 'UHAbstractSubmission',
945 "caption": N_("Manage my Tracks"),
946 "URL": 'UHConfMyStuffMyTracks',
947 "parent": "programme"},
949 "caption": N_("Timetable"),
950 "URL": 'UHConferenceTimeTable',
952 "contributionList": {
953 "caption": N_("Contribution List"),
954 "URL": 'UHContributionList',
957 "caption": N_("Author List"),
958 "URL": 'UHConfAuthorIndex',
961 "caption": N_("Speaker List"),
962 "URL": 'UHConfSpeakerIndex',
964 "visibilityByDefault": False},
966 "caption": N_("My Conference"),
967 "URL": 'UHConfMyStuff',
970 "caption": N_("My Tracks"),
971 "URL": 'UHConfMyStuffMyTracks',
972 "parent": "mystuff"},
974 "caption": N_("My Sessions"),
975 "URL": 'UHConfMyStuffMySessions',
976 "parent": "mystuff"},
978 "caption": N_("My Contributions"),
979 "URL": 'UHConfMyStuffMyContributions',
980 "parent": "mystuff"},
982 "caption": N_("Paper Reviewing"),
983 "URL": 'UHPaperReviewingDisplay',
985 "managepaperreviewing": {
986 "caption": N_("Manage Paper Reviewing"),
987 "URL": 'UHConfModifReviewingPaperSetup',
988 "parent": "paperreviewing"},
989 "assigncontributions": {
990 "caption": N_("Assign Papers"),
991 "URL": 'UHConfModifReviewingAssignContributionsList',
992 "parent": "paperreviewing"},
994 "caption": N_("Referee Area"),
995 "URL": 'UHConfModifListContribToJudge',
996 "parent": "paperreviewing"},
997 "judgelistreviewer": {
998 "caption": N_("Content Reviewer Area"),
999 "URL": 'UHConfModifListContribToJudgeAsReviewer',
1000 "parent": "paperreviewing"},
1001 "judgelisteditor": {
1002 "caption": N_("Layout Reviewer Area"),
1003 "URL": 'UHConfModifListContribToJudgeAsEditor',
1004 "parent": "paperreviewing"},
1006 "caption": N_("Upload Paper"),
1007 "URL": 'UHUploadPaper',
1008 "parent": "paperreviewing"},
1009 "downloadtemplate": {
1010 "caption": N_("Download Template"),
1011 "URL": 'UHDownloadPRTemplate',
1012 "parent": "paperreviewing"},
1014 "caption": N_("Book of Abstracts"),
1015 "URL": 'UHConfAbstractBook',
1017 "displayTarget": "_blank"},
1018 "registrationForm": {
1019 "caption": N_("Registration"),
1020 "URL": 'UHConfRegistrationForm',
1023 "caption": N_("Participant List"),
1024 "URL": 'UHConfRegistrantsList',
1026 "visibilityByDefault": False},
1028 "caption": N_("Evaluation"),
1029 "URL": 'UHConfEvaluationMainInformation',
1032 "caption": N_("Evaluation Form"),
1033 "URL": 'UHConfEvaluationDisplay',
1034 "parent": "evaluation"},
1035 "viewMyEvaluation": {
1036 "caption": N_("Modify my Evaluation"),
1037 "URL": 'UHConfEvaluationDisplayModif',
1038 "parent": "evaluation"}
1040 for entry
in plugin_entries
:
1041 assert entry
.name
not in self
._linkData
1042 self
._linkData
[entry
.name
] = {
1043 'caption': entry
.caption
,
1044 'URL': entry
.endpoint
,
1045 'parent': entry
.parent
1048 #this ordered list allow us to keep the order we want for the menu
1049 if not hasattr(self
, "_linkDataOrderedKeys"):
1050 self
._linkDataOrderedKeys
= ["overview",
1065 "managepaperreviewing",
1066 "assigncontributions",
1068 "judgelistreviewer",
1078 self
._linkDataOrderedKeys
+= [x
.name
for x
in plugin_entries
]
1080 def getLinkData(self
):
1081 return self
._linkData
1083 def getLinkDataOrderedKeys(self
):
1084 self
.__init
__() # init self._linkDataOrderedKeys if it isn't defined.
1085 return self
._linkDataOrderedKeys
1088 class ExternLink(Link
):
1090 class for link create by the user to a fixed link
1093 def __init__(self
, name
, URL
):
1094 Link
.__init
__(self
, name
)
1097 def clone(self
, newMenu
):
1098 newLink
= ExternLink(self
.getName(),self
.getURL())
1099 newLink
.setId(self
.getId())
1100 newLink
.setParent(newMenu
)
1101 newLink
.setEnabled(self
.isEnabled())
1102 newLink
.setCaption(self
.getCaption())
1103 newLink
.setDisplayTarget(self
.getDisplayTarget())
1109 def setURL(self
, URL
):
1112 class PageLink(Link
):
1114 class for link create by the user to a fixed link
1118 def __init__(self
, name
, page
):
1119 Link
.__init
__(self
, name
)
1122 def clone(self
, newMenu
):
1123 conf
= newMenu
.getConference()
1124 intPagesMgr
= internalPagesMgr
.InternalPagesMgrRegistery().getInternalPagesMgr(conf
)
1125 newPage
= self
.getPage().clone(conf
)
1126 intPagesMgr
.addPage(newPage
)
1127 newLink
= PageLink(self
.getName(),newPage
)
1128 newLink
.setId(self
.getId())
1129 newLink
.setParent(newMenu
)
1130 newLink
.setEnabled(self
.isEnabled())
1131 newLink
.setCaption(self
.getCaption())
1132 newLink
.setDisplayTarget(self
.getDisplayTarget())
1135 def setPage(self
, page
):
1142 return urlHandlers
.UHInternalPageDisplay
.getURL(self
._page
)
1145 class _FormatDefaultData
:
1149 "titleBgColor":{"code":"",\
1150 "url":urlHandlers
.UHConfModifFormatTitleBgColor
}, \
1151 "titleTextColor":{"code":"",\
1152 "url":urlHandlers
.UHConfModifFormatTitleTextColor
}
1155 def getColor(self
,key
):
1156 return self
._data
[key
]["code"]
1158 def getURL(self
,key
):
1159 return self
._data
[key
]["url"]
1162 class Format(Persistent
):
1166 self
._data
["titleBgColor"]=_FormatDefaultData().getColor("titleBgColor")
1167 self
._data
["titleTextColor"]=_FormatDefaultData().getColor("titleTextColor")
1170 def getFormatOption(self
,key
):
1171 if self
._data
.has_key(key
):
1172 code
=self
._data
[key
]
1173 url
=_FormatDefaultData().getURL(key
)
1174 return {"code":code
,"url":url
}
1177 def clone(self
, newCdm
):
1178 newFormat
= newCdm
.getFormat()
1179 newFormat
.setColorCode("titleBgColor", self
.getFormatOption("titleBgColor")["code"])
1180 newFormat
.setColorCode("titleTextColor", self
.getFormatOption("titleTextColor")["code"])
1183 def setColorCode(self
,key
,color
):
1184 if self
._data
.has_key(key
):
1185 color
=self
._getCorrectColor
(color
)
1189 self
._data
[key
]=color
1192 def _getCorrectColor(self
, color
):
1196 if not color
.startswith("#"):
1198 m
= re
.match("^#[0-9A-Fa-f]{6}$", color
)
1203 def clearColorCode(self
,key
):
1204 self
.setColorCode(key
, "")
1206 class TickerTape(Persistent
):
1209 # active will be set to true everytime the now
1210 # happening is enabled or the setText is called
1211 # this to avoid having an extra button in the interface
1212 # for activating the TickerTape
1213 self
._active
= False
1215 self
._enabledNowPlaying
= False
1216 self
._enabledSimpleText
= False
1218 def clone(self
, newCdm
):
1219 newTT
= newCdm
.getTickerTape()
1220 newTT
.setText(self
.getText())
1221 newTT
.setActive(self
.isActive())
1222 newTT
.setNowHappeningEnabled(self
.isNowHappeningEnabled())
1223 newTT
.setSimpleTextEnabled(self
.isSimpleTextEnabled())
1229 def setText(self
, text
):
1239 def deactivate(self
):
1242 def setActive(self
, v
):
1245 def isNowHappeningEnabled(self
):
1247 if self
._enabledNowPlaying
:
1249 except AttributeError, e
:
1250 self
._enabledNowPlaying
=False
1251 return self
._enabledNowPlaying
and self
._active
1253 def setNowHappeningEnabled(self
, v
):
1255 self
._enabledNowPlaying
= v
1257 def isSimpleTextEnabled(self
):
1259 if self
._enabledSimpleText
:
1261 except AttributeError, e
:
1262 self
._enabledSimpleText
= False
1263 return self
._enabledSimpleText
and self
._active
1265 def setSimpleTextEnabled(self
, v
):
1267 self
._enabledSimpleText
=v
1269 class ImageWrapper(Persistent
):
1271 It wraps a LocalFile class, just in case we need to add more info to this image
1275 def __init__(self
, localFile
):
1276 self
._localFile
= localFile
1279 return self
._localFile
.getId()
1282 self
._localFile
.delete()
1284 def getLocator(self
):
1285 loc
= self
._localFile
.getOwner().getLocator()
1286 loc
["picId"] = self
.getId()
1287 loc
["picExt"] = self
._localFile
.getFileType().lower()
1291 lf
= self
.getLocalFile().clone()
1292 iw
= ImageWrapper(lf
)
1295 def getLocalFile(self
):
1296 return self
._localFile
1298 class ImagesManager(Persistent
):
1300 This class manages all the images and pics used by a conference while displaying.
1301 We make difference between the "logo" of the conference and the rest of pictures.
1304 def __init__(self
, conf
):
1308 self
._picsCounter
= Counter()
1310 def clone(self
, newCdm
):
1311 newIM
= newCdm
.getImagesManager()
1312 newIM
._conf
= newCdm
.getConference()
1314 for pic
in self
.getPicList().values():
1315 lf
= pic
.getLocalFile()
1317 f
.setFileName( lf
.getFileName() )
1318 f
.setFilePath( lf
.getFilePath() )
1321 #Logo is not being cloned so far.
1325 def notifyModification(self
):
1328 def getPicList(self
):
1329 """ function for getting piclist """
1335 return self
._picList
1337 def _getPicsCounter(self
):
1339 if self
._picsCounter
:
1342 self
._picsCounter
= Counter()
1343 return self
._picsCounter
1345 def addPic( self
, picFile
):
1346 """ function for adding new picture item """
1347 picId
= self
._getPicsCounter
().newCount()
1348 if self
.getPicList().has_key(picId
) and self
.getPicList()[picId
] != None:
1349 raise MaKaCError("there is already a pic with the id %s"%picId
)
1350 picFile
.setOwner( self
._conf
)
1351 picFile
.setId( picId
)
1352 picFile
.archive( self
._conf
._getRepository
() )
1353 pic
= ImageWrapper(picFile
)
1354 self
.getPicList()[picId
] = pic
1355 self
.notifyModification()
1358 def getPic( self
,picId
):
1359 if self
.getPicList().has_key(picId
):
1360 return self
.getPicList()[picId
]
1363 def removePic(self
,picId
):
1364 """ function for removing pictures, used in picture uploader """
1365 pic
= self
.getPic(picId
)
1367 self
.getPicList()[picId
].delete()
1368 del self
.getPicList()[picId
]
1369 self
.notifyModification()
1371 # Logo should be migrated to this class in the near future.
1372 def setLogo( self
, logoFile
):
1373 logoFile
.setOwner( self
._conf
)
1374 logoFile
.setId( "logo" )
1375 logoFile
.archive( self
._conf
._getRepository
() )
1376 if self
._logo
!= None:
1378 self
._logo
= logoFile
1380 def getLogo( self
):
1383 def getLogoURL( self
):
1385 if self
._logo
== None:
1387 return self
._logo
.getURL()
1388 except AttributeError:
1392 def removeLogo(self
):
1393 if self
._logo
is None:
1398 def recoverLogo(self
, logo
):
1399 logo
.setOwner(self
._conf
)
1400 if self
._logo
!= None:
1405 class CSSWrapper(Persistent
):
1407 This class will handle the CSS file that is going to be applied
1408 to the conference display. CSS file can be an upload file or a
1409 template we already have. The upload file is an object of the class
1410 LocalFile and the template is just a string with the id (name) of the
1412 The class encapsulates the CSS so the user does not care about if it is
1413 a template or a local file.
1416 def __init__(self
, conf
, css
):
1418 self
._localFile
= css
1421 return self
._localFile
.getId()
1423 def getLocator(self
):
1424 loc
= self
._localFile
.getOwner().getLocator()
1425 loc
["cssId"] = self
.getId()
1428 def clone(self
, newSM
):
1432 f
.setFileName( self
._localFile
.getFileName() )
1433 f
.setFilePath( self
._localFile
.getFilePath() )
1434 f
.setOwner( newSM
._conf
)
1436 f
.archive( newSM
._conf
._getRepository
() )
1437 newCW
= CSSWrapper(self
._conf
, f
)
1441 from MaKaC
.webinterface
.urlHandlers
import UHConferenceCSS
1442 return UHConferenceCSS
.getURL(self
._conf
)
1444 def getFileName(self
, extension
=True):
1445 fn
=self
._localFile
.getFileName()
1447 fn
= fn
.lower().replace(".css","")
1450 def getFilePath(self
):
1451 return self
._localFile
.getFilePath()
1454 return self
._localFile
.getSize()
1457 return self
._localFile
.readBin()
1460 self
._localFile
.delete()
1461 self
._localFile
=None
1463 class StyleManager(Persistent
):
1465 This class manages the CSS customization for a conference.
1468 def __init__(self
, conf
):
1471 self
._usingTemplate
= None
1473 def clone(self
, newCdm
):
1474 newSM
= newCdm
.getStyleManager()
1475 newSM
._conf
= newCdm
.getConference()
1476 newSM
._usingTemplate
= self
._usingTemplate
1478 newSM
._css
= self
._css
.clone(newSM
)
1480 #Logo is not being cloned so far.
1484 def isUsingTemplate(self
):
1485 return self
._usingTemplate
is not None
1487 def useLocalCSS(self
):
1488 self
._usingTemplate
= None
1490 def setCSS( self
, cssFile
):
1491 if isinstance(cssFile
, str):
1492 # we will use a template but we keep the uploaded css file
1493 from indico
.modules
import ModuleHolder
1494 self
._cssTplsModule
= ModuleHolder().getById("cssTpls")
1495 self
._usingTemplate
= self
._cssTplsModule
.getCssTplById(cssFile
)
1498 cssFile
.setOwner( self
._conf
)
1499 cssFile
.setId( "css" )
1500 cssFile
.archive( self
._conf
._getRepository
() )
1501 if self
._css
!= None:
1503 self
._usingTemplate
= None
1504 self
._css
= CSSWrapper(self
._conf
, cssFile
)
1506 def getLocalCSS( self
):
1510 if self
._usingTemplate
:
1511 return self
._usingTemplate
1512 return self
.getLocalCSS()
1514 def getCSSURL( self
):
1516 return self
.getCSS().getURL()
1519 def removeCSS(self
):
1520 if self
._css
is not None: