source: indico/indico/MaKaC/plugins/Collaboration/collaborationTools.py @ 77384a

hello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.99v1.0v1.1
Last change on this file since 77384a was 77384a, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 16 months ago

[FIX] Fix previous commit

  • Moved the fossil to fossils.py.
  • Moved the utils methods in http_apy to collaborationTools.py
  • Fossilizing getTitle takes into account if linked to contribution or session in vidyo bookings.
  • Fossilizing status fixed.
  • Property mode set to 100644
File size: 26.9 KB
Line 
1# -*- coding: utf-8 -*-
2##
3##
4## This file is part of CDS Indico.
5## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
6##
7## CDS Indico is free software; you can redistribute it and/or
8## modify it under the terms of the GNU General Public License as
9## published by the Free Software Foundation; either version 2 of the
10## License, or (at your option) any later version.
11##
12## CDS Indico is distributed in the hope that it will be useful, but
13## WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15## General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21import pkg_resources, sys
22from MaKaC.plugins import PluginsHolder, Plugin
23from MaKaC.webinterface import urlHandlers
24from MaKaC.common.utils import formatDateTime, formatTwoDates, formatTime, \
25    formatDuration
26from MaKaC.common.timezoneUtils import getAdjustedDate, isSameDay
27from MaKaC.common.Configuration import Config
28from MaKaC.conference import Contribution, Conference
29from MaKaC.plugins.Collaboration.fossils import ICSBookingBaseIndexingFossil, \
30    IQueryResultFossil
31from MaKaC.fossils.conference import IConferenceFossil
32from MaKaC.common.contextManager import ContextManager
33
34class CollaborationTools(object):
35    """ Class with utility classmethods for the Collaboration plugins core and plugins
36    """
37
38    #This commented code tried to gain some performance by caching the collaboration
39    # PluginType object, but sometimes there would be problems by
40    # different requests sharing memory and trying to access the database
41    # after a connection was closed. This happened under Apache in Windows Vista with ZODB 3.8
42#    _cpt = None
43#    _plugins = {}
44
45    @classmethod
46    def getCollaborationPluginType(cls):
47        #This commented code tried to gain some performance by caching the collaboration
48        # PluginType object, but sometimes there would be problems by
49        # different requests sharing memory and trying to access the database
50        # after a connection was closed. This happened under Apache in Windows Vista with ZODB 3.8
51#        if not cls._cpt:
52#            cls._cpt = PluginsHolder().getPluginType("Collaboration")
53#        return cls._cpt
54        return PluginsHolder().getPluginType("Collaboration")
55
56    @classmethod
57    def getPlugin(cls, pluginId):
58        #This commented code tried to gain some performance by caching the collaboration
59        # PluginType object, but sometimes there would be problems by
60        # different requests sharing memory and trying to access the database
61        # after a connection was closed. This happened under Apache in Windows Vista with ZODB 3.8
62
63#        if not pluginName in cls._plugins:
64#            cls._plugins[pluginName] = cls.getCollaborationPluginType().getPlugin(pluginId)
65#        return cls._plugins[pluginId]
66        return cls.getCollaborationPluginType().getPlugin(pluginId)
67
68    @classmethod
69    def anyPluginsAreActive(cls):
70        return len(cls.getCollaborationPluginType().getPlugins(includeNonActive = False)) > 0
71
72    @classmethod
73    def getOptionValue(cls, pluginId, optionName):
74        """ Returns the value of an option of a plugin (plugins/Collaboration/XXXXX/options.py)
75            pluginName: a string with the name of the plugin
76            optionName: a string with the name of the option
77        """
78        ph = PluginsHolder()
79        return ph.getPluginType("Collaboration").getPlugin(pluginId).getOption(optionName).getValue()
80
81    @classmethod
82    def getOptionValueRooms(cls, pluginId, optionName):
83        """ Returns the room list of an option with type 'rooms' of a plugin (plugins/Collaboration/XXXXX/options.py)
84            pluginName: a string with the name of the plugin
85            optionName: a string with the name of the option
86        """
87        ph = PluginsHolder()
88        return ph.getPluginType("Collaboration").getPlugin(pluginId).getOption(optionName).getRooms()
89
90    @classmethod
91    def hasCollaborationOption(cls, optionName):
92        return cls.getCollaborationPluginType().hasOption(optionName)
93
94    @classmethod
95    def getCollaborationOptionValue(cls, optionName):
96        """ Returns the value of an option of the Collaboration plugin type (plugins/Collaboration/options.py)
97        """
98        return cls.getCollaborationPluginType().getOption(optionName).getValue()
99
100    @classmethod
101    def getModule(cls, pluginId):
102        """ Utility function that returns a module object given a plugin name.
103            pluginId: a string such as "evo", "DummyPlugin", etc.
104        """
105        pmodules = pkg_resources.get_entry_map('indico', group='indico.ext')
106        entry = pmodules.get('Collaboration.%s' % pluginId, None)
107        if entry:
108            __import__(entry.module_name, globals(), locals(),
109                       ['collaboration', 'pages', 'actions', 'fossils', 'services'])
110            return sys.modules[entry.module_name]
111        else:
112            return None
113
114    @classmethod
115    def getTemplateClass(cls, pluginId, templateName):
116        """ Utility function that returns a template class object given a plugin name and the class name.
117            Example: templateClass = CollaborationTools.getTemplateClass("EVO", "WNewBookingForm") will return the WNewBookingForm class in the EVO plugin.
118        """
119        return cls.getModule(pluginId).pages.__dict__.get(templateName, None)
120
121    @classmethod
122    def getServiceClass(cls, pluginName, serviceName):
123        """ Utility function that returns a service class object given a plugin name and the class name.
124            Example: serviceClass = CollaborationTools.getTemplateClass("WebcastRequest", "WebcastAbleTalksService") will return the WebcastAbleTalksService class in the WebcastRequest plugin.
125        """
126        return cls.getModule(pluginName).services.__dict__.get(serviceName + "Service", None)
127
128    @classmethod
129    def getGlobalData(cls, pluginName):
130        """ Returns the GlobalData object of a plugin
131        """
132        return cls.getPlugin(pluginName).getGlobalData()
133
134    @classmethod
135    def getExtraJS(cls, conf, plugin, user):
136        """ Utility function that returns a string with the extra JS declared by a plugin.
137        """
138        templateClass = cls.getTemplateClass(plugin.getId(), "WExtra")
139        if templateClass:
140            return templateClass(conf, plugin.getId(), user).getHTML()
141        else:
142            return None
143
144    @classmethod
145    def getCSBookingClass(cls, pluginName):
146        """ Utility function that returns a CSBooking class given a plugin name.
147            Example: templateClass = getCSBookingClass("EVO") will return the CSBooking class of the EVO plugin.
148        """
149        return cls.getModule(pluginName).collaboration.CSBooking
150
151    @classmethod
152    def getTabs(cls, conference, user):
153        """ Returns a list of tab names corresponding to the active plugins for an event.
154            If a user is specified, only tabs that a user can see are returned.
155            A user can see a tab if:
156            -The user is a Server Admin or a Video Services Admin
157            -The user is a Plugin Admin of a plugin in that tab.
158            -The user is an Event Manager or Video Services Manager and the plugin is not "admins only"
159            -The user is a Plugin Manager of a plugin in that tab and the plugin is not "admins only"
160        """
161        tabNamesSet = set()
162        csbm = conference.getCSBookingManager()
163
164        # we get the list of Plugin objects allowed for this kind of event
165        allowedForThisEvent = csbm.getAllowedPlugins()
166
167        for plugin in allowedForThisEvent:
168
169            if cls.canUserManagePlugin(conference, plugin, user):
170                tabNamesSet.add(cls.getPluginTab(plugin))
171                EATab = cls.getEATab(plugin)
172                if EATab is not None:
173                    tabNamesSet.add(EATab)
174
175        tabNames = list(tabNamesSet)
176        return tabNames
177
178    @classmethod
179    def getPluginTab(cls, pluginObject):
180        """ Utility function that returns the tab a Collaboration plugin belongs to.
181            If the option was not defined, "Collaboration" is the default.
182        """
183        if pluginObject.hasOption("tab"):
184            return pluginObject.getOption("tab").getValue()
185        else:
186            return "Collaboration"
187
188    @classmethod
189    def getEATab(cls, pluginObject):
190        """ Utility function that returns the Electronic Agreement Tab
191            (to be defined in options.py of each plugin that need it) a Collaboration plugin belongs to.
192            If the option was not defined, None is returned.
193        """
194        if pluginObject.hasOption("ElectronicAgreementTab"):
195            return pluginObject.getOption("ElectronicAgreementTab").getValue()
196        else:
197            return None
198
199    @classmethod
200    def getPluginsByTab(cls, tabName, conference, user):
201        """ Utility function that returns a list of plugin objects.
202            These Plugin objects will be of the "Collaboration" type, and only those who have declared a subtab equal
203            to the "tabName" argument will be returned.
204            If tabName is None, [] is returned.
205            The conference object is used to filter plugins that are not allowed in a conference,
206            because of the conference type or the equipment of the conference room
207            If a user is specified, only tabs with plugins that the user can see will be returned:
208            -
209        """
210
211        if tabName:
212
213            csbm = conference.getCSBookingManager()
214
215            if conference:
216                allowedPlugins = csbm.getAllowedPlugins()
217            else:
218                allowedPlugins = None
219
220            #we get the plugins of this tab
221            return cls.getCollaborationPluginType().getPluginList(
222                doSort = True,
223                filterFunction = lambda plugin: cls.getPluginTab(plugin) == tabName and
224                                                (allowedPlugins is None or plugin in allowedPlugins) and
225                                                cls.canUserManagePlugin(conference, plugin, user)
226            )
227        else:
228            return []
229
230    @classmethod
231    def canUserManagePlugin(cls, conference, plugin, user):
232        """ Utility function that returns if a user can interact with a plugin inside an event,
233            depending on the plugin, the user, and the event where the user tries to see a plugin page
234            or change a plugin object
235        """
236        csbm = conference.getCSBookingManager()
237
238        from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin
239        isAdminUser = RCCollaborationAdmin.hasRights(user = user)
240
241        isAdminOnlyPlugin = cls.isAdminOnlyPlugin(plugin)
242
243        canSee = (
244                isAdminUser or
245                user in plugin.getOption('admins').getValue() or
246                not isAdminOnlyPlugin and (conference.canUserModify(user) or
247                                           csbm.isVideoServicesManager(user) or
248                                           csbm.isPluginManager(plugin.getName(), user) ) )
249
250        return canSee
251
252
253
254    @classmethod
255    def splitPluginsByAllowMultiple(cls, pluginList):
256        """ Utility function that returns a tuple of 2 lists of Plugin objects.
257            The first list are the plugins who only allow 1 booking of their type.
258            The second list are the plugins who allow multiple bookings of their type.
259        """
260
261        #we split them into 2 lists
262        singleBookingPlugins = [p for p in pluginList if not cls.getCSBookingClass(p.getId())._allowMultiple]
263        multipleBookingPlugins = [p for p in pluginList if cls.getCSBookingClass(p.getId())._allowMultiple]
264
265        return singleBookingPlugins, multipleBookingPlugins
266
267    @classmethod
268    def getPluginAllowedOn(cls, pluginObject):
269        """ Utility function that returns a list of event types that this plugin is allowed on.
270            If the option was not defined, an empty list is returned
271        """
272        if pluginObject.hasOption("allowedOn"):
273            return pluginObject.getOption("allowedOn").getValue()
274        else:
275            return []
276
277    @classmethod
278    def isAdminOnlyPlugin(cls, plugin):
279        """ plugin can be a string with the name of the plugin
280            or a Plugin object
281        """
282        if isinstance(plugin, Plugin):
283            pluginId = plugin.getId()
284        else:
285            pluginId = plugin
286        return cls.getCSBookingClass(pluginId)._adminOnly
287
288    @classmethod
289    def pluginsWithEventDisplay(cls):
290        """ Utility function that returns a list of strings with the names of the
291            collaboration plugins that want to display something in event display pages
292        """
293        l = []
294        for pluginName in cls.getCollaborationPluginType().getPlugins():
295            if cls.getCSBookingClass(pluginName)._hasEventDisplay:
296                l.append(pluginName)
297        return l
298
299    @classmethod
300    def pluginsWithIndexing(cls):
301        """ Utility function that returns a list of strings with the names
302            of the collaboration plugins that want to be indexed
303        """
304        l = []
305        for plugin in cls.getCollaborationPluginType().getPlugins().values():
306            if plugin.getModule().collaboration.CSBooking._shouldBeIndexed:
307                l.append(plugin)
308        return l
309
310    @classmethod
311    def getIndexingFossil(cls, pluginName):
312        """ Utility function that returns the fossil that should be used for indexing for a given plugin
313        """
314        fossilsModule = cls.getModule(pluginName).fossils
315        if hasattr(fossilsModule, "ICSBookingIndexingFossil"):
316            return fossilsModule.ICSBookingIndexingFossil
317        else:
318            return ICSBookingBaseIndexingFossil
319
320    @classmethod
321    def updateIndexingFossilsDict(cls):
322        """ Utility function that updates IQueryResultFossil's getResults method
323            with the proper dict in order to fossilize bookings for the VS Overview page
324        """
325        fossilDict = {"%s.%s" % (Conference.__module__, Conference.__name__): IConferenceFossil}
326        for pluginName in cls.getCollaborationPluginType().getPlugins():
327            classObject = cls.getCSBookingClass(pluginName)
328            fossilClassObject = cls.getIndexingFossil(pluginName)
329            fossilDict["%s.%s" % (classObject.__module__, classObject.__name__)] = fossilClassObject
330
331        IQueryResultFossil.get('getResults').setTaggedValue('result', fossilDict)
332
333    @classmethod
334    def getXMLGenerator(cls, pluginName):
335        return cls.getModule(pluginName).pages.XMLGenerator
336
337    @classmethod
338    def getServiceInformation(cls, pluginName):
339        return cls.getModule(pluginName).pages.ServiceInformation
340
341    @classmethod
342    def getRequestTypeUserCanManage(cls, conf, user):
343        requestType = ""
344        if CollaborationTools.canUserManagePlugin(conf, CollaborationTools.getPlugin("RecordingRequest"), user):
345            if CollaborationTools.canUserManagePlugin(conf, CollaborationTools.getPlugin("WebcastRequest"), user):
346                requestType = "both"
347            else:
348                requestType = "recording"
349        else:
350            if CollaborationTools.canUserManagePlugin(conf, CollaborationTools.getPlugin("WebcastRequest"), user):
351                requestType = "webcast"
352
353        return requestType
354
355    """ The CSBooking object which can be passed through to the fossil
356        may be linked to a Contribution, in the case of WebcastRequest etc,
357        therefore the URL may be more specific than the event in this instance.
358    """
359
360    @classmethod
361    def getConferenceOrContributionURL(cls, event):
362        from MaKaC.webinterface.urlHandlers import UHConferenceDisplay, UHContributionDisplay
363        url = ""
364
365        # Webcast and Recording Request specific:
366        if hasattr(event, '_conf'):
367            event = event._conf
368
369        if isinstance(event, Conference):
370            url = UHConferenceDisplay.getURL(event)
371        elif isinstance(event, Contribution):
372            url = UHContributionDisplay(event)
373
374        return url
375
376    @classmethod
377    def getBookingTitle(cls, booking):
378        title = ""
379        if hasattr(booking, 'getFullTitle'):
380            title = booking.getFullTitle()
381        elif hasattr(booking, 'getTitle'):
382            title = booking.getTitle()
383        elif hasattr(booking, '_getTitle'):
384            title = booking._getTitle()
385        elif hasattr(booking, '_conf'):
386            title = booking._conf.getTitle()
387
388        return title if title is not None else 'No title defined.'
389
390class MailTools(object):
391
392    @classmethod
393    def getServerName(cls):
394        return str(Config.getInstance().getBaseURL())
395
396    @classmethod
397    def needToSendEmails(cls, pluginName = None):
398        """
399        Checks the plugin/global options in order to know if notification e-mails
400        need to be sent
401        """
402
403        # this is not cool... the object should be passed in the first place
404        if pluginName:
405            plugin = CollaborationTools.getCollaborationPluginType().getPlugin(pluginName)
406        else:
407            plugin = None
408
409        if plugin and plugin.hasOption('sendMailNotifications'):
410            admins = plugin.getOption('admins').getValue()
411            sendMail = plugin.getOption('sendMailNotifications').getValue()
412            addEmails = plugin.getOption('additionalEmails').getValue()
413
414        else:
415            # get definitions from the Collaboration plugin type
416            admins = CollaborationTools.getCollaborationOptionValue('collaborationAdmins')
417            sendMail = CollaborationTools.getCollaborationOptionValue('sendMailNotifications')
418            addEmails = CollaborationTools.getCollaborationOptionValue('additionalEmails')
419
420        return (sendMail and len(admins) > 0) or len(addEmails) > 0
421
422    @classmethod
423    def getAdminEmailList(cls, pluginName = None):
424        """ Returns a list of admin email addresses that a notification email should be sent to.
425            If pluginName is None, then the global Collaboration admin mails will be returned.
426            The emails in the list are not in any particular order and should be unique.
427        """
428
429        if pluginName:
430
431            adminEmails = CollaborationTools.getOptionValue(pluginName, 'additionalEmails')
432            if CollaborationTools.getOptionValue(pluginName, 'sendMailNotifications'):
433                adminEmails.extend([u.getEmail() for u in CollaborationTools.getOptionValue(pluginName, 'admins')])
434        else:
435            adminEmails = CollaborationTools.getCollaborationOptionValue('additionalEmails')
436            if CollaborationTools.getCollaborationOptionValue('sendMailNotifications'):
437                adminEmails.extend([u.getEmail() for u in CollaborationTools.getCollaborationOptionValue('collaborationAdmins')])
438        return list(set(adminEmails))
439
440    @classmethod
441    def getManagersEmailList(cls, conf, pluginName = None):
442        """ Returns a list of manager email addresses (for a given event) that a notification email should be sent to.
443            This list includes:
444                -The creator of an event
445                -The managers of an event
446                -Any Video Services Managers
447                -If pluginName is not None, any Video Services Managers for that given system
448            The emails in the list are not in any particular order and should be unique.
449        """
450        csbm = conf.getCSBookingManager()
451        managersEmails = []
452        managersEmails.append(conf.getCreator().getEmail())
453        managersEmails.extend([u.getEmail() for u in conf.getManagerList()])
454        managersEmails.extend([u.getEmail() for u in csbm.getVideoServicesManagers()])
455        if pluginName:
456            managersEmails.extend([u.getEmail() for u in csbm.getPluginManagers(pluginName)])
457        return list(set(managersEmails))
458
459    @classmethod
460    def eventDetails(cls, conf):
461        return """
462Event details:
463<table style="border-spacing: 10px 10px;">
464    <tr>
465        <td style="vertical-align: top; white-space : nowrap;">
466            <strong>Event name:</strong>
467        </td>
468        <td>
469            <a href="%s">%s</a>
470        </td
471    </tr>
472    <tr>
473        <td style="vertical-align: top; white-space : nowrap;">
474            <strong>Event dates:</strong>
475        </td>
476        <td>
477            %s
478        </td
479    </tr>
480    <tr>
481        <td style="vertical-align: top; white-space : nowrap;">
482            <strong>Event id</strong>
483        </td>
484        <td>
485            %s
486        </td
487    </tr>
488    %s
489</table>
490"""%(urlHandlers.UHConferenceDisplay.getURL(conf),
491     conf.getTitle(),
492     formatTwoDates(conf.getStartDate(), conf.getEndDate(), tz = conf.getTimezone(), showWeek = True),
493     conf.getId(),
494     MailTools.eventRoomDetails(conf)
495     )
496
497
498    @classmethod
499    def eventRoomDetails(cls, conf):
500        location = conf.getLocation()
501        room = conf.getRoom()
502        if location and location.getName() and location.getName().strip():
503            locationText = location.getName().strip()
504            if room and room.getName() and room.getName().strip():
505                locationText += ". Room: " + room.getName().strip()
506            else:
507                locationText += " (room not defined)"
508        else:
509            locationText = "location/room not defined"
510
511        return """
512    <tr>
513        <td style="vertical-align: top; white-space : nowrap;">
514            <strong>Event location & room:</strong>
515        </td>
516        <td>
517            %s
518        </td>
519    </tr>
520""" % locationText
521
522
523    @classmethod
524    def userDetails(cls, caption, user):
525        additionalEmailsText = ""
526        additionalEmails = user.getSecondaryEmails()
527        if additionalEmails:
528            additionalEmailsText="""
529    <tr>
530        <td style="vertical-align: top; white-space : nowrap;">
531            <strong>Additional emails:</strong>
532        </td>
533        <td>
534            %s
535        </td
536    </tr>
537""" % ", ".join(user.getEmails()[1:])
538
539        additionalTelephonesText = ""
540        additionalTelephones = user.getSecondaryTelephones()
541        if additionalTelephones:
542            additionalTelephonesText="""
543    <tr>
544        <td style="vertical-align: top; white-space : nowrap;">
545            <strong>Additional telephones:</strong>
546        </td>
547        <td>
548            %s
549        </td
550    </tr>
551""" % ", ".join(user.getTelephone()[1:])
552
553
554        return """
555%s details:
556<table style="border-spacing: 10px 10px;">
557    <tr>
558        <td style="vertical-align: top; white-space : nowrap;">
559            <strong>Full name:</strong>
560        </td>
561        <td>
562            %s
563        </td
564    </tr>
565    <tr>
566        <td style="vertical-align: top; white-space : nowrap;">
567            <strong>Main email address:</strong>
568        </td>
569        <td>
570            %s
571        </td
572    </tr>
573    %s
574    <tr>
575        <td style="vertical-align: top; white-space : nowrap;">
576            <strong>Main phone number:</strong>
577        </td>
578        <td>
579            %s
580        </td
581    </tr>
582    %s
583</table>
584""" % (caption,
585       user.getFullName(),
586       user.getEmail(),
587       additionalEmailsText,
588       user.getTelephone(),
589       additionalTelephonesText
590       )
591
592    @classmethod
593    def organizerDetails(cls, conf):
594        return cls.userDetails('Creator of the event', conf.getCreator())
595
596    @classmethod
597    def currentUserDetails(cls, caption):
598        if not 'currentUser' in ContextManager.get():
599            return ""
600        user = ContextManager.get('currentUser')
601        return cls.userDetails(caption, user)
602
603    @classmethod
604    def bookingCreationDate(cls, booking):
605        return formatDateTime(getAdjustedDate(booking.getCreationDate(), booking.getConference()))
606
607    @classmethod
608    def bookingModificationDate(cls, booking, typeOfMail):
609        if (typeOfMail == 'new'):
610            return ""
611        else:
612            return """
613    <tr>
614        <td style="vertical-align: top; white-space : nowrap;">
615            <strong>Modification date:</strong>
616        </td>
617        <td style="vertical-align: top;">
618            %s
619        </td>
620    </tr>
621""" % formatDateTime(getAdjustedDate(booking.getModificationDate(), booking.getConference()))
622
623    @classmethod
624    def talkListText(cls, conf, talkList):
625        text = []
626
627        #we sort by start date
628        talkList.sort(key = Contribution.contributionStartDateForSort)
629
630        #we check is event is single day
631        singleDayEvent = isSameDay(conf.getStartDate(), conf.getEndDate(), conf.getTimezone())
632
633        for contribution in talkList:
634
635            #1. speakers text
636            speakerList = contribution.getSpeakerList()
637            if speakerList:
638                speakers = ', by ' + ", ".join([person.getFullName() for person in speakerList])
639            else:
640                speakers = ''
641
642            #2. room and location text
643            locationStr = MailTools.locationOrRoomToStr(contribution.getLocation())
644            roomStr = MailTools.locationOrRoomToStr(contribution.getRoom())
645            confLocationStr = MailTools.locationOrRoomToStr(conf.getLocation())
646            confRoomStr = MailTools.locationOrRoomToStr(conf.getRoom())
647
648            if locationStr == confLocationStr and roomStr == confRoomStr:
649                locationText = ''
650            else:
651                if locationStr:
652                    locationText = "Location: " + locationStr
653                    if roomStr:
654                        locationText += ', Room: ' + roomStr
655                    else:
656                        locationText += ', Room: not defined'
657                else:
658                    locationText = "Location: not defined"
659
660                locationText = " (%s)" % locationText
661
662            #3. dates text
663            if not contribution.getStartDate():
664                datesText = '(Not scheduled)'
665            elif singleDayEvent and isSameDay(conf.getStartDate(), contribution.getStartDate(), conf.getTimezone()):
666                datesText = formatTime(contribution.getAdjustedStartDate().time()) + ' (' + formatDuration(contribution.getDuration(), "hours_minutes") + ')'
667            else:
668                datesText = formatDateTime(contribution.getAdjustedStartDate(), showWeek = True) + ' (' + formatDuration(contribution.getDuration(), "hours_minutes") + ')'
669
670            #4. returned result
671            contributionLine = """•%s : <a href="%s">%s</a>%s (id: %s)%s""" % (
672                datesText,
673                urlHandlers.UHContributionDisplay.getURL(contribution),
674                contribution.getTitle(),
675                speakers,
676                contribution.getId(),
677                locationText
678            )
679            text.append(contributionLine)
680
681        return text
682
683    @classmethod
684    def locationOrRoomToStr(cls, object):
685        """ Turns a CustomLocation or CustomRoom object into a string,
686            testing if the object is None, object.getName() is None.
687        """
688        if object is None:
689            return ''
690        elif object.getName() is None:
691            return ''
692        else:
693            return object.getName().strip()
694
695    @classmethod
696    def listToStr(cls, list):
697        return "<br />".join([("•" + item) for item in list])
Note: See TracBrowser for help on using the repository browser.