| 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 | |
|---|
| 21 | import pkg_resources, sys |
|---|
| 22 | from MaKaC.plugins import PluginsHolder, Plugin |
|---|
| 23 | from MaKaC.webinterface import urlHandlers |
|---|
| 24 | from MaKaC.common.utils import formatDateTime, formatTwoDates, formatTime, \ |
|---|
| 25 | formatDuration |
|---|
| 26 | from MaKaC.common.timezoneUtils import getAdjustedDate, isSameDay |
|---|
| 27 | from MaKaC.common.Configuration import Config |
|---|
| 28 | from MaKaC.conference import Contribution, Conference |
|---|
| 29 | from MaKaC.plugins.Collaboration.fossils import ICSBookingBaseIndexingFossil, \ |
|---|
| 30 | IQueryResultFossil |
|---|
| 31 | from MaKaC.fossils.conference import IConferenceFossil |
|---|
| 32 | from MaKaC.common.contextManager import ContextManager |
|---|
| 33 | |
|---|
| 34 | class 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 | |
|---|
| 390 | class 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 """ |
|---|
| 462 | Event 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]) |
|---|