| [54fef7] | 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | ## |
|---|
| 3 | ## $Id: collaboration.py,v 1.21 2009/04/25 13:56:05 dmartinc Exp $ |
|---|
| 4 | ## |
|---|
| 5 | ## This file is part of CDS Indico. |
|---|
| 6 | ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN. |
|---|
| 7 | ## |
|---|
| 8 | ## CDS Indico is free software; you can redistribute it and/or |
|---|
| 9 | ## modify it under the terms of the GNU General Public License as |
|---|
| 10 | ## published by the Free Software Foundation; either version 2 of the |
|---|
| 11 | ## License, or (at your option) any later version. |
|---|
| 12 | ## |
|---|
| 13 | ## CDS Indico is distributed in the hope that it will be useful, but |
|---|
| 14 | ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 16 | ## General Public License for more details. |
|---|
| 17 | ## |
|---|
| 18 | ## You should have received a copy of the GNU General Public License |
|---|
| 19 | ## along with CDS Indico; if not, write to the Free Software Foundation, Inc., |
|---|
| 20 | ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 21 | import xml.dom.minidom |
|---|
| 22 | import re |
|---|
| 23 | import datetime |
|---|
| 24 | #from MaKaC.common.PickleJar import DictPickler |
|---|
| 25 | from datetime import timedelta, datetime |
|---|
| 26 | from time import strftime, strptime |
|---|
| 27 | from MaKaC.common.PickleJar import Retrieves |
|---|
| 28 | from MaKaC.common.utils import formatDateTime |
|---|
| 29 | from MaKaC.common.timezoneUtils import nowutc, utctimestamp2date, naive2local, datetimeToUnixTime, getAdjustedDate |
|---|
| 30 | from MaKaC.plugins.Collaboration.base import CSBookingBase |
|---|
| 31 | from MaKaC.plugins.Collaboration.WebEx.common import WebExControlledException, WebExException,\ |
|---|
| 32 | getMinStartDate, getMaxEndDate, ChangesFromWebExError,\ |
|---|
| 33 | WebExError, WebExWarning, getWebExOptionValueByName, sendXMLRequest, makeTime, findDuration, \ |
|---|
| 34 | Participant, makeParticipantXML |
|---|
| 35 | from MaKaC.plugins.Collaboration.WebEx.mail import NewWebExMeetingNotificationAdmin, \ |
|---|
| 36 | WebExMeetingModifiedNotificationAdmin, WebExMeetingRemovalNotificationAdmin, \ |
|---|
| 37 | NewWebExMeetingNotificationManager, WebExMeetingModifiedNotificationManager,\ |
|---|
| 38 | WebExMeetingRemovalNotificationManager, WebExParticipantNotification |
|---|
| 39 | from MaKaC.common.mail import GenericMailer |
|---|
| 40 | from MaKaC.webinterface.mail import personMail, Mailer |
|---|
| 41 | from MaKaC.common.logger import Logger |
|---|
| 42 | from MaKaC.i18n import _ |
|---|
| 43 | from MaKaC.plugins.Collaboration.collaborationTools import MailTools |
|---|
| 44 | from MaKaC.services.interface.rpc.common import ProcessError |
|---|
| 45 | from MaKaC.common.Counter import Counter |
|---|
| 46 | |
|---|
| 47 | from MaKaC.plugins.Collaboration.WebEx.fossils import ICSBookingIndexingFossil, ICSBookingConfModifFossil |
|---|
| 48 | from MaKaC.common.fossilize import fossilizes |
|---|
| 49 | from MaKaC.plugins.Collaboration.fossils import ICSBookingBaseConfModifFossil |
|---|
| 50 | |
|---|
| 51 | class CSBooking(CSBookingBase): |
|---|
| 52 | fossilizes(ICSBookingConfModifFossil, ICSBookingIndexingFossil) |
|---|
| 53 | |
|---|
| 54 | _hasTitle = True |
|---|
| 55 | _hasStart = True |
|---|
| 56 | _hasStop = False |
|---|
| 57 | _hasCheckStatus = True |
|---|
| 58 | |
|---|
| 59 | _requiresServerCallForStart = True |
|---|
| 60 | _requiresClientCallForStart = False |
|---|
| 61 | |
|---|
| 62 | _needsBookingParamsCheck = True |
|---|
| 63 | _needsToBeNotifiedOnView = True |
|---|
| 64 | _needsToBeNotifiedOfDateChanges = True |
|---|
| 65 | _canBeNotifiedOfEventDateChanges = True |
|---|
| 66 | _allowMultiple = True |
|---|
| 67 | |
|---|
| 68 | _hasEventDisplay = True |
|---|
| 69 | |
|---|
| 70 | _commonIndexes = ["All Videoconference"] |
|---|
| 71 | _changesFromWebEx = [] |
|---|
| 72 | |
|---|
| 73 | _simpleParameters = { |
|---|
| 74 | "meetingTitle": (str, ''), |
|---|
| 75 | "meetingDescription": (str, None), |
|---|
| 76 | "sendMailToManagers": (bool, False), |
|---|
| 77 | "webExUser":(str, None), |
|---|
| 78 | "webExPass":(str, None), |
|---|
| 79 | "webExKey":(str, None), #The meeting key / ID number in the WebEx system |
|---|
| 80 | "sendAttendeesEmail":(bool, True) |
|---|
| 81 | } |
|---|
| 82 | _complexParameters = ["accessPassword", "hasAccessPassword", "participants" ] |
|---|
| 83 | |
|---|
| 84 | def __init__(self, type, conf): |
|---|
| 85 | CSBookingBase.__init__(self, type, conf) |
|---|
| 86 | self._participants = {} |
|---|
| 87 | self._participantIdCounter = Counter(1) |
|---|
| 88 | self._accessPassword = None |
|---|
| 89 | self._url = None |
|---|
| 90 | self._webExKey = None |
|---|
| 91 | self._phoneNum = None |
|---|
| 92 | self._duration = None |
|---|
| 93 | self._iCalURL = None |
|---|
| 94 | |
|---|
| 95 | self._created = False |
|---|
| 96 | self._error = False |
|---|
| 97 | self._errorMessage = None |
|---|
| 98 | self._errorDetails = None |
|---|
| 99 | |
|---|
| 100 | self._lastCheck = nowutc() |
|---|
| 101 | self._checksDone = [] |
|---|
| 102 | |
|---|
| 103 | def getParticipantList(self, sorted = False): |
|---|
| 104 | Logger.get('WebEx').debug( "In getParticipantList" ) |
|---|
| 105 | if sorted: |
|---|
| 106 | keys = self._participants.keys() |
|---|
| 107 | keys.sort() |
|---|
| 108 | for k in keys: |
|---|
| 109 | Logger.get('WebEx').info( "Adding: " + self._participants[k]._email ) |
|---|
| 110 | return [self._participants[k] for k in keys] |
|---|
| 111 | else: |
|---|
| 112 | return self._participants.values() |
|---|
| 113 | |
|---|
| 114 | def getParticipants(self): |
|---|
| 115 | Logger.get('WebEx').debug( "In getParticipants" ) |
|---|
| 116 | return self.getParticipantList(sorted = True) |
|---|
| 117 | |
|---|
| 118 | def setParticipants(self, participants): |
|---|
| 119 | Logger.get('WebEx').debug( "In setParticipants" ) |
|---|
| 120 | participantsCopy = dict(self._participants) |
|---|
| 121 | self._participants = {} |
|---|
| 122 | for p in participants: |
|---|
| 123 | id = p.get("participantId", None) |
|---|
| 124 | Logger.get('WebEx').debug( "Adding a participant: %s" % str(id) ) |
|---|
| 125 | if id is None or not id in participantsCopy: |
|---|
| 126 | id = self._participantIdCounter.newCount() |
|---|
| 127 | |
|---|
| 128 | participantObject = Participant(self, id, p) |
|---|
| 129 | |
|---|
| 130 | self._participants[id] = participantObject |
|---|
| 131 | |
|---|
| 132 | self._p_changed = 1 |
|---|
| 133 | |
|---|
| 134 | def getAccessPassword(self): |
|---|
| 135 | """ This method returns the access password that will be displayed in the indico page |
|---|
| 136 | """ |
|---|
| 137 | if self._accessPassword is None: |
|---|
| 138 | return "" |
|---|
| 139 | else: |
|---|
| 140 | return self._accessPassword |
|---|
| 141 | def setHasAccessPassword(self, value = False): |
|---|
| 142 | return value |
|---|
| 143 | |
|---|
| 144 | def setAccessPassword(self, accessPassword): |
|---|
| 145 | if accessPassword.strip() == "": |
|---|
| 146 | self._accessPassword = None |
|---|
| 147 | else: |
|---|
| 148 | self._accessPassword = accessPassword |
|---|
| 149 | |
|---|
| 150 | def getHasAccessPassword(self): |
|---|
| 151 | return self._accessPassword is not None |
|---|
| 152 | |
|---|
| 153 | def getUrl(self): |
|---|
| 154 | return self._url |
|---|
| 155 | |
|---|
| 156 | def getErrorMessage(self): |
|---|
| 157 | return self._errorMessage |
|---|
| 158 | |
|---|
| 159 | def getWebExUser(self): |
|---|
| 160 | return self._bookingParams['webExUser'] |
|---|
| 161 | |
|---|
| 162 | def getWebExKey(self): |
|---|
| 163 | try: |
|---|
| 164 | return self._webExKey |
|---|
| 165 | except: |
|---|
| 166 | return "No key set" |
|---|
| 167 | |
|---|
| 168 | def getErrorDetails(self): |
|---|
| 169 | return self._errorDetails |
|---|
| 170 | |
|---|
| 171 | def getChangesFromWebEx(self): |
|---|
| 172 | return self._changesFromWebEx |
|---|
| 173 | |
|---|
| 174 | def getLastCheck(self): |
|---|
| 175 | if not hasattr(self, "_lastCheck"): #TODO: remove when safe |
|---|
| 176 | self._lastCheck = nowutc() |
|---|
| 177 | self._checksDone = [] |
|---|
| 178 | return self._lastCheck |
|---|
| 179 | |
|---|
| 180 | ## overriding methods |
|---|
| 181 | def _getTitle(self): |
|---|
| 182 | return self._bookingParams["meetingTitle"] |
|---|
| 183 | |
|---|
| 184 | def _getPluginDisplayName(self): |
|---|
| 185 | return "WebEx" |
|---|
| 186 | |
|---|
| 187 | def _checkBookingParams(self): |
|---|
| 188 | for p in self._participants.itervalues(): |
|---|
| 189 | if re.match("^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$", p._email) == None: |
|---|
| 190 | raise WebExException("Participant email address (" + p._email + ") for " + p._firstName + " " + p._lastName +" is invalid. ") |
|---|
| 191 | |
|---|
| 192 | if len(self._bookingParams["meetingTitle"].strip()) == 0: |
|---|
| 193 | raise WebExException("meetingTitle parameter (" + str(self._bookingParams["meetingTitle"]) +" ) is empty for booking with id: " + str(self._id)) |
|---|
| 194 | |
|---|
| 195 | if len(self._bookingParams["meetingDescription"].strip()) == 0: |
|---|
| 196 | raise WebExException("meetingDescription parameter (" + str(self._bookingParams["meetingDescription"]) +" ) is empty for booking with id: " + str(self._id)) |
|---|
| 197 | |
|---|
| 198 | if self._startDate > self._endDate: |
|---|
| 199 | raise WebExException("Start date of booking cannot be after end date. Booking id: " + str(self._id)) |
|---|
| 200 | |
|---|
| 201 | allowedStartMinutes = self._WebExOptions["allowedPastMinutes"].getValue() |
|---|
| 202 | if self.getAdjustedStartDate('UTC') < (nowutc() - timedelta(minutes = allowedStartMinutes )): |
|---|
| 203 | raise WebExException("Cannot create booking before the past %s minutes. Booking id: %s"% (allowedStartMinutes, str(self._id))) |
|---|
| 204 | |
|---|
| 205 | minStartDate = getMinStartDate(self.getConference()) |
|---|
| 206 | if self.getAdjustedStartDate() < minStartDate: |
|---|
| 207 | raise WebExException("Cannot create a booking %s minutes before the Indico event's start date. Please create it after %s"%(self._WebExOptions["allowedMinutes"].getValue(), formatDateTime(minStartDate))) |
|---|
| 208 | |
|---|
| 209 | maxEndDate = getMaxEndDate(self.getConference()) |
|---|
| 210 | if self.getAdjustedEndDate() > maxEndDate: |
|---|
| 211 | raise WebExException("Cannot create a booking %s minutes after before the Indico event's end date. Please create it before %s"%(self._WebExOptions["allowedMinutes"].getValue(), formatDateTime(maxEndDate))) |
|---|
| 212 | |
|---|
| 213 | if False: #for now, we don't detect overlapping |
|---|
| 214 | for booking in self.getBookingsOfSameType(): |
|---|
| 215 | if self._id != booking.getId(): |
|---|
| 216 | if not ((self._startDate < booking.getStartDate() and self._endDate <= booking.getStartDate()) or |
|---|
| 217 | (self._startDate >= booking.getEndDate() and self._endDate > booking.getEndDate())): |
|---|
| 218 | return OverlappedError(booking) |
|---|
| 219 | |
|---|
| 220 | return False |
|---|
| 221 | |
|---|
| 222 | def getWebExTimeZoneToUTC( self, tz_id, the_date ): |
|---|
| 223 | """ |
|---|
| 224 | The date is required because the WebEx server |
|---|
| 225 | responds with the offset of GMT time based |
|---|
| 226 | on that date, adjusted for daylight savings, etc |
|---|
| 227 | """ |
|---|
| 228 | params = self.getBookingParams() |
|---|
| 229 | request_xml = """<?xml version="1.0\" encoding="UTF-8"?> |
|---|
| 230 | <serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:serv=\"http://www.webex.com/schemas/2002/06/service" > |
|---|
| 231 | <header> |
|---|
| 232 | <securityContext> |
|---|
| 233 | <webExID>%(username)s</webExID> |
|---|
| 234 | <password>%(password)s</password> |
|---|
| 235 | <siteID>%(siteID)s</siteID> |
|---|
| 236 | <partnerID>%(partnerID)s</partnerID> |
|---|
| 237 | </securityContext> |
|---|
| 238 | </header> |
|---|
| 239 | <body> |
|---|
| 240 | <bodyContent xsi:type="site.LstTimeZone" > |
|---|
| 241 | <timeZoneID>%(tz_id)s</timeZoneID> |
|---|
| 242 | <date>%(date)s</date> |
|---|
| 243 | </bodyContent> |
|---|
| 244 | </body> |
|---|
| 245 | </serv:message> |
|---|
| 246 | """ % ( { "username" : params['webExUser'], "password" : params['webExPass'], "siteID" : getWebExOptionValueByName("WESiteID"), "partnerID" : getWebExOptionValueByName("WEPartnerID"), "tz_id":tz_id, "date":the_date } ) |
|---|
| 247 | response_xml = sendXMLRequest( request_xml ) |
|---|
| 248 | dom = xml.dom.minidom.parseString( response_xml ) |
|---|
| 249 | offset = dom.getElementsByTagName( "ns1:gmtOffset" )[0].firstChild.toxml('utf-8') |
|---|
| 250 | try: |
|---|
| 251 | return int(offset) |
|---|
| 252 | except: |
|---|
| 253 | Logger.get('WebEx').debug( "Eror requesting time zone offset from WebEx:\n\n%s" % ( response_xml ) ) |
|---|
| 254 | return None |
|---|
| 255 | |
|---|
| 256 | def bookingOK(self): |
|---|
| 257 | self._statusMessage = _("Booking created") |
|---|
| 258 | self._statusClass = "statusMessageOK" |
|---|
| 259 | self._created = True |
|---|
| 260 | |
|---|
| 261 | def checkCanStart(self, changeMessage = True): |
|---|
| 262 | if self._created: |
|---|
| 263 | ############### |
|---|
| 264 | self._canBeStarted = True |
|---|
| 265 | return True |
|---|
| 266 | ##########Remove above here; in for testing |
|---|
| 267 | now = nowutc() |
|---|
| 268 | self._canBeDeleted = True |
|---|
| 269 | self._canBeNotifiedOfEventDateChanges = CSBooking._canBeNotifiedOfEventDateChanges |
|---|
| 270 | if self.getStartDate() < now and self.getEndDate() > now: |
|---|
| 271 | self._canBeStarted = True |
|---|
| 272 | self._canBeDeleted = False |
|---|
| 273 | if changeMessage: |
|---|
| 274 | self._statusMessage = _("Ready to start!") |
|---|
| 275 | self._statusClass = "statusMessageOK" |
|---|
| 276 | else: |
|---|
| 277 | self._canBeStarted = False |
|---|
| 278 | if now > self.getEndDate() and changeMessage: |
|---|
| 279 | self._canBeDeleted = False |
|---|
| 280 | self._statusMessage = _("Already took place") |
|---|
| 281 | self._statusClass = "statusMessageOther" |
|---|
| 282 | self._needsToBeNotifiedOfDateChanges = False |
|---|
| 283 | self._canBeNotifiedOfEventDateChanges = False |
|---|
| 284 | elif changeMessage: |
|---|
| 285 | self.bookingOK() |
|---|
| 286 | |
|---|
| 287 | def _create(self): |
|---|
| 288 | """ Creates a booking in the EVO server if all conditions are met. |
|---|
| 289 | """ |
|---|
| 290 | try: |
|---|
| 291 | params = self.getBookingParams() |
|---|
| 292 | self.setAccessPassword( params['accessPassword'] ) |
|---|
| 293 | |
|---|
| 294 | participant_xml = makeParticipantXML(self._participants) |
|---|
| 295 | |
|---|
| 296 | t1 = makeTime( self.getAdjustedStartDate('UTC') ) |
|---|
| 297 | self._duration = findDuration( self.getAdjustedStartDate('UTC'), self.getAdjustedEndDate('UTC') ) |
|---|
| 298 | start_date = t1.strftime( "%m/%d/%Y %H:%M" ) |
|---|
| 299 | request_xml = """<?xml version="1.0\" encoding="UTF-8"?> |
|---|
| 300 | <serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:serv=\"http://www.webex.com/schemas/2002/06/service" > |
|---|
| 301 | <header> |
|---|
| 302 | <securityContext> |
|---|
| 303 | <webExID>%(username)s</webExID> |
|---|
| 304 | <password>%(password)s</password> |
|---|
| 305 | <siteID>%(siteID)s</siteID> |
|---|
| 306 | <partnerID>%(partnerID)s</partnerID> |
|---|
| 307 | </securityContext> |
|---|
| 308 | </header> |
|---|
| 309 | <body> |
|---|
| 310 | <bodyContent xsi:type="java:com.webex.service.binding.meeting.CreateMeeting" xmlns:meet="http://www.webex.com/schemas/2002/06/service/meeting" > |
|---|
| 311 | <accessControl> |
|---|
| 312 | <meetingPassword>%(meetingPassword)s</meetingPassword> |
|---|
| 313 | </accessControl> |
|---|
| 314 | <metaData> |
|---|
| 315 | <confName>%(meetingName)s</confName> |
|---|
| 316 | <agenda>%(description)s</agenda> |
|---|
| 317 | </metaData> |
|---|
| 318 | %(participants)s |
|---|
| 319 | <enableOptions> |
|---|
| 320 | <chat>true</chat> |
|---|
| 321 | <poll>true</poll> |
|---|
| 322 | <audioVideo>true</audioVideo> |
|---|
| 323 | </enableOptions> |
|---|
| 324 | <schedule> |
|---|
| 325 | <startDate>%(startDate)s:00</startDate> |
|---|
| 326 | <joinTeleconfBeforeHost>false</joinTeleconfBeforeHost> |
|---|
| 327 | <duration>%(duration)s</duration> |
|---|
| 328 | <timeZoneID>20</timeZoneID><!--Zone 20 is Greenwich GMT/UTC--> |
|---|
| 329 | </schedule> |
|---|
| 330 | <telephony> |
|---|
| 331 | <telephonySupport>CALLIN</telephonySupport> |
|---|
| 332 | </telephony> |
|---|
| 333 | </bodyContent> |
|---|
| 334 | </body> |
|---|
| 335 | </serv:message> |
|---|
| 336 | |
|---|
| 337 | """ % ( { "username" : params['webExUser'], "password" : params['webExPass'], "siteID" : getWebExOptionValueByName("WESiteID"), "partnerID" : getWebExOptionValueByName("WEPartnerID"), "meetingPassword": params['accessPassword'], "startDate" : start_date, "duration" : self._duration, "meetingName" : params['meetingTitle'], "description" : params['meetingDescription'], "participants": participant_xml } ) |
|---|
| 338 | Logger.get('WebEx').debug( "WebEx Response:\n\n%s" % ( request_xml ) ) |
|---|
| 339 | response_xml = sendXMLRequest( request_xml ) |
|---|
| 340 | Logger.get('WebEx').debug( "WebEx Response:\n\n%s" % ( response_xml ) ) |
|---|
| 341 | dom = xml.dom.minidom.parseString( response_xml ) |
|---|
| 342 | status = dom.getElementsByTagName( "serv:result" )[0].firstChild.toxml('utf-8') |
|---|
| 343 | if status == "SUCCESS": |
|---|
| 344 | self._webExKey = dom.getElementsByTagName( "meet:meetingkey" )[0].firstChild.toxml('utf-8') |
|---|
| 345 | self._iCalURL = dom.getElementsByTagName( "serv:attendee" )[0].firstChild.toxml('utf-8') |
|---|
| 346 | #Check if they left the trialing slash in the base URL we need |
|---|
| 347 | if getWebExOptionValueByName("WEhttpServerLocation")[-1] == "/": |
|---|
| 348 | self._url = getWebExOptionValueByName("WEautoJoinURL") + 'm.php?AT=JM&MK=' + self._webExKey |
|---|
| 349 | else: #Add in the slash for them |
|---|
| 350 | self._url = getWebExOptionValueByName("WEautoJoinURL") + '/m.php?AT=JM&MK=' + self._webExKey |
|---|
| 351 | #We do this because the call in number is not returned in create response |
|---|
| 352 | self.bookingOK() |
|---|
| 353 | self.checkCanStart() |
|---|
| 354 | self._checkStatus() |
|---|
| 355 | recipients = [] |
|---|
| 356 | for k in self._participants.keys(): |
|---|
| 357 | recipients.append( self._participants[k]._email ) |
|---|
| 358 | if len(recipients)>0: |
|---|
| 359 | notification = WebExParticipantNotification( self, recipients, 'new' ) |
|---|
| 360 | GenericMailer.send( notification ) |
|---|
| 361 | else: |
|---|
| 362 | self._url = "" |
|---|
| 363 | errorID = dom.getElementsByTagName( "serv:exceptionID" )[0].firstChild.toxml('utf-8') |
|---|
| 364 | errorReason = dom.getElementsByTagName( "serv:reason" )[0].firstChild.toxml('utf-8') |
|---|
| 365 | return WebExError( errorID, userMessage = errorReason ) |
|---|
| 366 | |
|---|
| 367 | if MailTools.needToSendEmails('WebEx'): |
|---|
| 368 | try: |
|---|
| 369 | notification = NewWebExMeetingNotificationAdmin(self) |
|---|
| 370 | GenericMailer.sendAndLog(notification, self.getConference(), |
|---|
| 371 | "MaKaC/plugins/Collaboration/WebEx/collaboration.py", |
|---|
| 372 | self.getConference().getCreator()) |
|---|
| 373 | except Exception,e: |
|---|
| 374 | Logger.get('WebEx').error( |
|---|
| 375 | """Could not send NewWebExMeetingNotificationAdmin for booking with id %s of event with id %s, exception: %s""" % |
|---|
| 376 | (self.getId(), self.getConference().getId(), str(e))) |
|---|
| 377 | |
|---|
| 378 | if self._bookingParams["sendMailToManagers"]: |
|---|
| 379 | try: |
|---|
| 380 | notification = NewWebExMeetingNotificationManager(self) |
|---|
| 381 | GenericMailer.sendAndLog(notification, self.getConference(), |
|---|
| 382 | "MaKaC/plugins/Collaboration/WebEx/collaboration.py", |
|---|
| 383 | self.getConference().getCreator()) |
|---|
| 384 | except Exception,e: |
|---|
| 385 | Logger.get('WebEx').error( |
|---|
| 386 | """Could not send NewEVOMeetingNotificationManager for booking with id %s , exception: %s""" % (self._id, str(e))) |
|---|
| 387 | except WebExControlledException, e: |
|---|
| 388 | Logger.get('WebEx').debug( "caught exception in function _create" ) |
|---|
| 389 | raise WebExException(_("The booking could not be created due to a problem with the WebEx Server\n.It sent the following message: ") + e.message, e) |
|---|
| 390 | |
|---|
| 391 | def _modify(self): |
|---|
| 392 | """ Modifies a booking in the EVO server if all conditions are met. |
|---|
| 393 | """ |
|---|
| 394 | Logger.get('WebEx').debug( "in _modify" ) |
|---|
| 395 | if self._created: |
|---|
| 396 | arguments = self.getCreateModifyArguments() |
|---|
| 397 | #we take care of the participants |
|---|
| 398 | |
|---|
| 399 | try: |
|---|
| 400 | params = self.getBookingParams() |
|---|
| 401 | self.setAccessPassword( params['accessPassword'] ) |
|---|
| 402 | t1 = datetime( *strptime( str(self.getAdjustedStartDate('UTC'))[:-9], "%Y-%m-%d %H:%M" )[0:7]) |
|---|
| 403 | t2 = datetime( *strptime( str(self.getAdjustedEndDate('UTC'))[:-9], "%Y-%m-%d %H:%M" )[0:7]) |
|---|
| 404 | diff = t2 - t1 |
|---|
| 405 | days = diff.days |
|---|
| 406 | minutes,seconds = divmod(diff.seconds, 60) |
|---|
| 407 | duration = minutes + diff.days * 1440 |
|---|
| 408 | start_date = t1.strftime( "%m/%d/%Y %H:%M" ) |
|---|
| 409 | request_xml = """<?xml version="1.0\" encoding="UTF-8"?> |
|---|
| 410 | <serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:serv=\"http://www.webex.com/schemas/2002/06/service" > |
|---|
| 411 | <header> |
|---|
| 412 | <securityContext> |
|---|
| 413 | <webExID>%(username)s</webExID> |
|---|
| 414 | <password>%(password)s</password> |
|---|
| 415 | <siteID>%(siteID)s</siteID> |
|---|
| 416 | <partnerID>%(partnerID)s</partnerID> |
|---|
| 417 | </securityContext> |
|---|
| 418 | </header> |
|---|
| 419 | <body> |
|---|
| 420 | <bodyContent xsi:type="java:com.webex.service.binding.meeting.SetMeeting" xmlns:meet="http://www.webex.com/schemas/2002/06/service/meeting" > |
|---|
| 421 | <meetingkey>%(meetingKey)s</meetingkey> |
|---|
| 422 | <accessControl> |
|---|
| 423 | <meetingPassword>%(meetingPassword)s</meetingPassword> |
|---|
| 424 | </accessControl> |
|---|
| 425 | <metaData> |
|---|
| 426 | <confName>%(meetingName)s</confName> |
|---|
| 427 | <agenda>%(description)s</agenda> |
|---|
| 428 | </metaData> |
|---|
| 429 | %(participants)s |
|---|
| 430 | <enableOptions> |
|---|
| 431 | <chat>true</chat> |
|---|
| 432 | <poll>true</poll> |
|---|
| 433 | <audioVideo>true</audioVideo> |
|---|
| 434 | </enableOptions> |
|---|
| 435 | |
|---|
| 436 | <schedule> |
|---|
| 437 | <startDate>%(startDate)s:00</startDate> |
|---|
| 438 | <joinTeleconfBeforeHost>false</joinTeleconfBeforeHost> |
|---|
| 439 | <duration>%(duration)s</duration> |
|---|
| 440 | <timeZoneID>20</timeZoneID><!--Zone 20 is Greenwich GMT/UTC--> |
|---|
| 441 | </schedule> |
|---|
| 442 | <telephony> |
|---|
| 443 | <telephonySupport>CALLIN</telephonySupport> |
|---|
| 444 | </telephony> |
|---|
| 445 | </bodyContent> |
|---|
| 446 | </body> |
|---|
| 447 | </serv:message> |
|---|
| 448 | |
|---|
| 449 | """ % ( { "username" : params['webExUser'], "password" : params['webExPass'], "siteID" : getWebExOptionValueByName("WESiteID"), "partnerID" : getWebExOptionValueByName("WEPartnerID"), "meetingPassword": params['accessPassword'], "startDate" : start_date, "duration" : self._duration, "meetingName" : params['meetingTitle'], "meetingKey" : self._webExKey, "description": params["meetingDescription"], "participants": makeParticipantXML(self._participants) } ) |
|---|
| 450 | Logger.get('WebEx').debug( "WebEx Modify Request:\n\n%s" % ( request_xml ) ) |
|---|
| 451 | response_xml = sendXMLRequest( request_xml ) |
|---|
| 452 | Logger.get('WebEx').debug( "WebEx Modify Response:\n\n%s" % ( response_xml ) ) |
|---|
| 453 | dom = xml.dom.minidom.parseString( response_xml ) |
|---|
| 454 | status = dom.getElementsByTagName( "serv:result" )[0].firstChild.toxml('utf-8') |
|---|
| 455 | if status != "SUCCESS": |
|---|
| 456 | errorID = dom.getElementsByTagName( "serv:exceptionID" )[0].firstChild.toxml('utf-8') |
|---|
| 457 | errorReason = dom.getElementsByTagName( "serv:reason" )[0].firstChild.toxml('utf-8') |
|---|
| 458 | return WebExError( errorID, userMessage = errorReason ) |
|---|
| 459 | |
|---|
| 460 | self.bookingOK() |
|---|
| 461 | self.checkCanStart() |
|---|
| 462 | self._checkStatus() |
|---|
| 463 | recipients = [] |
|---|
| 464 | for k in self._participants.keys(): |
|---|
| 465 | recipients.append( self._participants[k]._email ) |
|---|
| 466 | if len(recipients)>0: |
|---|
| 467 | notification = WebExParticipantNotification( self, recipients, 'modify' ) |
|---|
| 468 | GenericMailer.send( notification ) |
|---|
| 469 | |
|---|
| 470 | if MailTools.needToSendEmails('WebEx'): |
|---|
| 471 | try: |
|---|
| 472 | notification = WebExMeetingModifiedNotificationAdmin(self) |
|---|
| 473 | GenericMailer.sendAndLog(notification, self.getConference(), |
|---|
| 474 | "MaKaC/plugins/Collaboration/WebEx/collaboration.py", |
|---|
| 475 | self.getConference().getCreator()) |
|---|
| 476 | except Exception,e: |
|---|
| 477 | Logger.get('WebEx').error( |
|---|
| 478 | """Could not send WebExMeetingModifiedNotificationAdmin for booking with id %s of event with id %s, exception: %s""" % |
|---|
| 479 | (self.getId(), self.getConference().getId(), str(e))) |
|---|
| 480 | |
|---|
| 481 | if self._bookingParams["sendMailToManagers"]: |
|---|
| 482 | try: |
|---|
| 483 | notification = WebExMeetingModifiedNotificationManager(self) |
|---|
| 484 | GenericMailer.sendAndLog(notification, self.getConference(), |
|---|
| 485 | "MaKaC/plugins/Collaboration/WebEx/collaboration.py", |
|---|
| 486 | self.getConference().getCreator()) |
|---|
| 487 | except Exception,e: |
|---|
| 488 | Logger.get('WebEx').error( |
|---|
| 489 | """Could not send WebExMeetingModifiedNotificationManager for booking with id %s , exception: %s""" % (self._id, str(e))) |
|---|
| 490 | |
|---|
| 491 | |
|---|
| 492 | except WebExControlledException, e: |
|---|
| 493 | raise WebExException(_("The booking could not be modified due to a problem with the WebEx Server.\n") ) |
|---|
| 494 | else: |
|---|
| 495 | self._create() |
|---|
| 496 | |
|---|
| 497 | def _start(self): |
|---|
| 498 | """ Starts an EVO meeting. |
|---|
| 499 | A last check on the EVO server is performed. |
|---|
| 500 | """ |
|---|
| 501 | Logger.get('WebEx').debug( "in _start" ) |
|---|
| 502 | #Check if they left the trialing slash in the base URL we need |
|---|
| 503 | if getWebExOptionValueByName("WEhttpServerLocation")[-1] == "/": |
|---|
| 504 | start_url = getWebExOptionValueByName("WEautoJoinURL") + 'm.php?AT=HM&AS=WebTour&WL=http://www.aol.com&MK=' + self._webExKey |
|---|
| 505 | else: #Add in the slash for them |
|---|
| 506 | start_url = getWebExOptionValueByName("WEautoJoinURL") + '/m.php?AT=HM&MK=' + self._webExKey |
|---|
| 507 | # urllib.urllibopen( getWebExOptionValueByName("WEhttpServerLocation") ) |
|---|
| 508 | self._checkStatus() |
|---|
| 509 | if self._canBeStarted: |
|---|
| 510 | self._permissionToStart = True |
|---|
| 511 | |
|---|
| 512 | def _notifyOnView(self): |
|---|
| 513 | """ This method is called every time that the user sees a booking. |
|---|
| 514 | It will check the booking status according to the times defined in the 'verifyMinutes' option. |
|---|
| 515 | If a check must be done, the WebEx Server will be contacted. |
|---|
| 516 | """ |
|---|
| 517 | checksToDo = [timedelta(minutes = int(minutes)) for minutes in self._WebExOptions["verifyMinutes"].getValue()] |
|---|
| 518 | checksToDo.sort() |
|---|
| 519 | |
|---|
| 520 | remainingTime = self.getAdjustedStartDate('UTC') - nowutc() |
|---|
| 521 | |
|---|
| 522 | checkDone = False |
|---|
| 523 | |
|---|
| 524 | for index, check in enumerate(checksToDo): |
|---|
| 525 | if remainingTime < check and not check in self._checksDone: |
|---|
| 526 | self._checkStatus() |
|---|
| 527 | self._checksDone.extend(checksToDo[index:]) |
|---|
| 528 | checkDone = True |
|---|
| 529 | break |
|---|
| 530 | |
|---|
| 531 | if not checkDone: |
|---|
| 532 | self.checkCanStart() |
|---|
| 533 | |
|---|
| 534 | def _checkStatus(self): |
|---|
| 535 | if self._created: |
|---|
| 536 | try: |
|---|
| 537 | params = self.getBookingParams() |
|---|
| 538 | request_xml = """<?xml version="1.0" encoding="ISO-8859-1"?> |
|---|
| 539 | <serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|---|
| 540 | <header> |
|---|
| 541 | <securityContext> |
|---|
| 542 | <webExID>%(username)s</webExID> |
|---|
| 543 | <password>%(password)s</password> |
|---|
| 544 | <siteID>%(siteID)s</siteID> |
|---|
| 545 | <partnerID>%(partnerID)s</partnerID> |
|---|
| 546 | </securityContext> |
|---|
| 547 | </header> |
|---|
| 548 | <body> |
|---|
| 549 | <bodyContent xsi:type="java:com.webex.service.binding.meeting.GetMeeting"> |
|---|
| 550 | <meetingKey>%(webex_key)s</meetingKey> |
|---|
| 551 | </bodyContent> |
|---|
| 552 | </body> |
|---|
| 553 | </serv:message> |
|---|
| 554 | |
|---|
| 555 | """ % { "username" : params['webExUser'], "password" : params['webExPass'], "siteID" : getWebExOptionValueByName("WESiteID"), "partnerID" : getWebExOptionValueByName("WEPartnerID"), "webex_key": self._webExKey } |
|---|
| 556 | Logger.get('WebEx').debug( "Check status request XML:\n%s " % ( request_xml ) ) |
|---|
| 557 | response_xml = sendXMLRequest( request_xml ) |
|---|
| 558 | Logger.get('WebEx').debug( "Check status response XML:\n%s " % ( response_xml ) ) |
|---|
| 559 | dom = xml.dom.minidom.parseString( response_xml ) |
|---|
| 560 | status = dom.getElementsByTagName( "serv:result" )[0].firstChild.toxml('utf-8') |
|---|
| 561 | if status != "SUCCESS": |
|---|
| 562 | errorID = dom.getElementsByTagName( "serv:exceptionID" )[0].firstChild.toxml('utf-8') |
|---|
| 563 | errorReason = dom.getElementsByTagName( "serv:reason" )[0].firstChild.toxml('utf-8') |
|---|
| 564 | return WebExError( errorID, userMessage = errorReason ) |
|---|
| 565 | self.assignAttributes( response_xml ) |
|---|
| 566 | |
|---|
| 567 | except WebExControlledException, e: |
|---|
| 568 | raise WebExException(_("Information could not be retrieved due to a problem with the EVO Server\n.The EVO Server sent the following error message: ") + e.message, e) |
|---|
| 569 | |
|---|
| 570 | def _delete(self): |
|---|
| 571 | self._warning = WebExWarning( "a test of the warning system" ) |
|---|
| 572 | params = self.getBookingParams() |
|---|
| 573 | request_xml = """<?xml version="1.0" encoding="ISO-8859-1"?> |
|---|
| 574 | <serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|---|
| 575 | <header> |
|---|
| 576 | <securityContext> |
|---|
| 577 | <webExID>%(username)s</webExID> |
|---|
| 578 | <password>%(password)s</password> |
|---|
| 579 | <siteID>%(siteID)s</siteID> |
|---|
| 580 | <partnerID>%(partnerID)s</partnerID> |
|---|
| 581 | </securityContext> |
|---|
| 582 | </header> |
|---|
| 583 | <body> |
|---|
| 584 | <bodyContent xsi:type="java:com.webex.service.binding.meeting.DelMeeting"> |
|---|
| 585 | <meetingKey>%(webex_key)s</meetingKey> |
|---|
| 586 | </bodyContent> |
|---|
| 587 | </body> |
|---|
| 588 | </serv:message> |
|---|
| 589 | """ % { "username" : params['webExUser'], "password" : params['webExPass'], "siteID" : getWebExOptionValueByName("WESiteID"), "partnerID" : getWebExOptionValueByName("WEPartnerID"), "webex_key": self._webExKey } |
|---|
| 590 | Logger.get('WebEx').debug( "delete func. is self._created? %s XML:\n%s " % ( self._created, request_xml ) ) |
|---|
| 591 | response_xml = sendXMLRequest( request_xml ) |
|---|
| 592 | dom = xml.dom.minidom.parseString( response_xml ) |
|---|
| 593 | status = dom.getElementsByTagName( "serv:result" )[0].firstChild.toxml('utf-8') |
|---|
| 594 | if status != "SUCCESS": |
|---|
| 595 | errorID = dom.getElementsByTagName( "serv:exceptionID" )[0].firstChild.toxml('utf-8') |
|---|
| 596 | errorReason = dom.getElementsByTagName( "serv:reason" )[0].firstChild.toxml('utf-8') |
|---|
| 597 | Logger.get('WebEx').info( "In delete function, appears to have failed: %s" % response_xml ) |
|---|
| 598 | return WebExError( errorID, userMessage = errorReason ) |
|---|
| 599 | # self._warning = WebExWarning( reason ) |
|---|
| 600 | else: |
|---|
| 601 | Logger.get('WebEx').info( "In delete function, appears to have been successful" ) |
|---|
| 602 | |
|---|
| 603 | if self._created: |
|---|
| 604 | try: |
|---|
| 605 | # if MailTools.needToSendEmails('WebEx'): |
|---|
| 606 | if True: |
|---|
| 607 | try: |
|---|
| 608 | # notification = WebExParticipantNotification(self, [ "flannery@gmail.com", "flannery@fnal.gov", "flannery@imsa.edu" ]) |
|---|
| 609 | #send(addto, addcc, addfrom, subject, body): |
|---|
| 610 | Logger.get('WebEx').info("I am in the mailer block") |
|---|
| 611 | recipients = "" |
|---|
| 612 | for k in participants.keys(): |
|---|
| 613 | recipients += participants[k]._email + " , " |
|---|
| 614 | Logger.get('WebEx').info("Recipients: " + recipients ) |
|---|
| 615 | personMail.send(recipients, "", "Kevin O'Flannery", "A Subject", "Some body in here" ) |
|---|
| 616 | #notification, self.getConference(), |
|---|
| 617 | # "MaKaC/plugins/Collaboration/WebEx/collaboration.py", |
|---|
| 618 | # self.getConference().getCreator()) |
|---|
| 619 | except Exception,e: |
|---|
| 620 | Logger.get('WebEx').error( |
|---|
| 621 | """Could not send WebExMeetingRemovalNotificationAdmin for booking with id %s of event with id %s, exception: %s""" % |
|---|
| 622 | (self.getId(), self.getConference().getId(), str(e))) |
|---|
| 623 | |
|---|
| 624 | # if self._bookingParams["sendMailToManagers"]: |
|---|
| 625 | # try: |
|---|
| 626 | # notification = EVOMeetingRemovalNotificationManager(self) |
|---|
| 627 | # GenericMailer.sendAndLog(notification, self.getConference(), |
|---|
| 628 | # "MaKaC/plugins/Collaboration/WebEx/collaboration.py", |
|---|
| 629 | # self.getConference().getCreator()) |
|---|
| 630 | # except Exception,e: |
|---|
| 631 | # Logger.get('EVO').error( |
|---|
| 632 | # """Could not send EVOMeetingRemovalNotificationManager for booking with id %s , exception: %s""" % (self._id, str(e))) |
|---|
| 633 | |
|---|
| 634 | except WebExControlledException, e: |
|---|
| 635 | if e.message == "DELETE_MEETING_OVER": |
|---|
| 636 | return WebExError('cannotDeleteOld', str(requestURL)) |
|---|
| 637 | if e.message == "DELETE_MEETING_ONGOING": |
|---|
| 638 | return WebExError('cannotDeleteOngoing', str(requestURL)) |
|---|
| 639 | if e.message == "DELETE_MEETING_NO_ID": |
|---|
| 640 | self._warning = EVOWarning('cannotDeleteNonExistant') |
|---|
| 641 | else: |
|---|
| 642 | return WebExError( userMessage = "The booking could not be deleted due to a problem with the WebEx Server" ) |
|---|
| 643 | raise WebExException(_("The booking could not be deleted due to a problem with the EVO Server\n.The EVO Server sent the following error message: ") + e.message, e) |
|---|
| 644 | |
|---|
| 645 | self._error = False |
|---|
| 646 | |
|---|
| 647 | |
|---|
| 648 | def _getLaunchDisplayInfo(self): |
|---|
| 649 | return {'launchText' : _("Join Now!"), |
|---|
| 650 | 'launchLink' : str(self.getURL()), |
|---|
| 651 | 'launchTooltip': _("Click here to join the WebEx meeting!")} |
|---|
| 652 | |
|---|
| 653 | def getCreateModifyArguments(self): |
|---|
| 654 | arguments = { |
|---|
| 655 | "meet:meetingkey": self._webExKey, |
|---|
| 656 | "meet:agenda": self._bookingParams["meetingDescription"].replace("\n",""), |
|---|
| 657 | "meet:confName": self._bookingParams["meetingTitle"], |
|---|
| 658 | "meet:hostWebExID": self._bookingParams["webExUser"], |
|---|
| 659 | "meet:startDate": makeTime( self.getAdjustedStartDate('UTC') ), |
|---|
| 660 | "meet:duration": self._duration, |
|---|
| 661 | "meet:meetingPassword": self.getAccessPassword(), |
|---|
| 662 | } |
|---|
| 663 | return arguments |
|---|
| 664 | |
|---|
| 665 | def assignAttributes(self, response_xml): |
|---|
| 666 | |
|---|
| 667 | verboseKeyNames = { |
|---|
| 668 | "meet:meetingkey": "WebEx Meeting ID", |
|---|
| 669 | "meet:agenda": "Meeting description", |
|---|
| 670 | "meet:confName": "Title", |
|---|
| 671 | "meet:hostWebExID": "WebEx host account", |
|---|
| 672 | "meet:startDate": "Start time", |
|---|
| 673 | "meet:duration": "Duration", |
|---|
| 674 | "meet:meetingPassword": "Meeting password", |
|---|
| 675 | } |
|---|
| 676 | |
|---|
| 677 | dom = xml.dom.minidom.parseString( response_xml ) |
|---|
| 678 | oldArguments = self.getCreateModifyArguments() |
|---|
| 679 | |
|---|
| 680 | changesFromWebEx = self._changesFromWebEx |
|---|
| 681 | # changesFromWebEx = [] |
|---|
| 682 | |
|---|
| 683 | start_date = makeTime( self.getAdjustedStartDate('UTC') ).strftime( "%m/%d/%Y %H:%M:%S" ) |
|---|
| 684 | time_discrepancy = False |
|---|
| 685 | for key in oldArguments: |
|---|
| 686 | if not verboseKeyNames.has_key( key ): |
|---|
| 687 | continue |
|---|
| 688 | if key == "meet:startDate" or key == "meet:duration": |
|---|
| 689 | if key == "meet:startDate": |
|---|
| 690 | # Logger.get('WebEx').info( "calc_start_date: " + start_date ) |
|---|
| 691 | # Logger.get('WebEx').info( "found_start_date: " + dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8') ) |
|---|
| 692 | if dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8') != start_date: |
|---|
| 693 | time_discrepancy = True |
|---|
| 694 | Logger.get('WebEx').info( "Local and WebEx time are different. We will need to calculate it." ) |
|---|
| 695 | if key == "meet:duration": |
|---|
| 696 | if dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8') != str(self._duration): |
|---|
| 697 | time_discrepancy = True |
|---|
| 698 | user_msg = "Updated booking duration - old:" + str(self._duration) + " new:" + int( dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8') ) |
|---|
| 699 | self._duration = int( dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8') ) |
|---|
| 700 | Logger.get('WebEx').info( user_msg ) |
|---|
| 701 | changesFromWebEx.append( user_msg ) |
|---|
| 702 | continue |
|---|
| 703 | try: |
|---|
| 704 | if dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8') != str(oldArguments[key]) and key in verboseKeyNames: |
|---|
| 705 | changesFromWebEx.append(verboseKeyNames[key] + ": " + dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8')) |
|---|
| 706 | Logger.get('WebEx').info( "WebEx Val: '" + dom.getElementsByTagName( key )[0].firstChild.toxml('utf-8') + "' and local:'" + str(oldArguments[key]) ) |
|---|
| 707 | except: |
|---|
| 708 | Logger.get('WebEx').info( "caught exception on: " + key ) |
|---|
| 709 | pass |
|---|
| 710 | self._phoneNum = dom.getElementsByTagName( "serv:tollFreeNum" )[0].firstChild.toxml('utf-8') |
|---|
| 711 | |
|---|
| 712 | #We calculate the time from WebEx first assuming it is in UTC. |
|---|
| 713 | #If not, we then apply the offset to keep it simple |
|---|
| 714 | calc_time = naive2local( datetime.strptime( dom.getElementsByTagName( "meet:startDate" )[0].firstChild.toxml('utf-8'), "%m/%d/%Y %H:%M:%S" ), 'UTC' ) |
|---|
| 715 | tz_id = dom.getElementsByTagName( "meet:timeZoneID" )[0].firstChild.toxml('utf-8') |
|---|
| 716 | Logger.get('WebEx').info( "webex TZ id: " + tz_id ) |
|---|
| 717 | Logger.get('WebEx').info( "my start date: " + self.getAdjustedStartDate('UTC').strftime("%m/%d/%Y %H:%M:%S") ) |
|---|
| 718 | #If the specified time zone is not UTC, contact WebEx |
|---|
| 719 | #and find the offset from UTC we must account for |
|---|
| 720 | if tz_id != 20: |
|---|
| 721 | time_offset_mins = self.getWebExTimeZoneToUTC( tz_id, calc_time.strftime("%m/%d/%Y %H:%M:%S")) |
|---|
| 722 | Logger.get('WebEx').info( "raw webex time: " + calc_time.strftime("%A, %d. %B %Y %I:%M%p") ) |
|---|
| 723 | Logger.get('WebEx').info( "time_offset_mins: " + str(time_offset_mins)) |
|---|
| 724 | WE_time = calc_time + timedelta( minutes= -1*int( time_offset_mins ) ) |
|---|
| 725 | if time_discrepancy == True: |
|---|
| 726 | Logger.get('WebEx').info( "webex time with offset in event time zone: " + getAdjustedDate(WE_time, tz=self._conf.getTimezone()).strftime("%m/%d/%Y %H:%M:%S") ) |
|---|
| 727 | changesFromWebEx.append("Updated start time to match WebEx start time (displayed in event timezone): " + getAdjustedDate(WE_time, tz=self._conf.getTimezone()).strftime("%m/%d/%Y %H:%M:%S") ) |
|---|
| 728 | self._startDate = getAdjustedDate(WE_time, tz=self._conf.getTimezone()) |
|---|
| 729 | self._endDate = getAdjustedDate(WE_time, tz=self._conf.getTimezone()) + timedelta( minutes=int( self._duration ) ) |
|---|
| 730 | if time_discrepancy == True: |
|---|
| 731 | recipients = [] |
|---|
| 732 | for k in self._participants.keys(): |
|---|
| 733 | recipients.append( self._participants[k]._email ) |
|---|
| 734 | notification = WebExParticipantNotification( self, recipients, 'modify' ) |
|---|
| 735 | GenericMailer.send( notification ) |
|---|
| 736 | |
|---|
| 737 | self.checkCanStart() |
|---|
| 738 | self._changesFromWebEx = changesFromWebEx |
|---|
| 739 | |
|---|