source: indico/indico/MaKaC/plugins/Collaboration/EVO/common.py @ 837615

burotelhello-world-walkthroughipv6new-webexprov-dual-interfacev0.97-seriesv0.98-seriesv0.98.2v0.98.3v0.98b1v0.98b2v0.99v1.0v1.1
Last change on this file since 837615 was 837615, checked in by David Martín Clavo <david.martin.clavo@…>, 4 years ago

[REFACTOR] Changes to CSErrorBase

-Changed getMessage method to getLogMessage and getUserMessage methods.
-getLogMessage should return a message to be written in the log.
-getUserMessage should return a message to be shown to the user,
for example when a synchronization between event and booking went bad.

  • Property mode set to 100644
File size: 11.1 KB
Line 
1# -*- coding: utf-8 -*-
2##
3## $Id: common.py,v 1.12 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
22
23from MaKaC.plugins.Collaboration.base import CollaborationException, CSErrorBase
24from urllib2 import HTTPError, URLError
25from datetime import timedelta
26from BaseHTTPServer import BaseHTTPRequestHandler
27from MaKaC.common.httpTimeout import urlOpenWithTimeout
28from MaKaC.common.url import URL
29from array import array
30from MaKaC.common.timezoneUtils import nowutc, datetimeToUnixTime
31from MaKaC.common.logger import Logger
32from MaKaC.common.PickleJar import Retrieves
33from MaKaC.plugins.Collaboration.collaborationTools import CollaborationTools
34
35readLimit = 100000;
36secondsToWait = 10;
37
38def getEVOOptionValueByName(optionName):
39    return CollaborationTools.getOptionValue('EVO', optionName)
40
41def getActionURL(actionString):
42    EVOServerURL = getEVOOptionValueByName("httpServerLocation")
43    actionServlet = getEVOOptionValueByName("APIMap")[actionString]
44    if EVOServerURL.endswith('/'):
45        return EVOServerURL + actionServlet
46    else:
47        return EVOServerURL + '/' + actionServlet
48   
49def getRequestURL(action, arguments = {}):
50   
51    actionURL = getActionURL(action)
52   
53    indicoID = getEVOOptionValueByName("indicoUserID")
54    indicoPassword = getEVOOptionValueByName("indicoPassword")
55    expirationTime = int(datetimeToUnixTime(nowutc() + timedelta(minutes = getEVOOptionValueByName('expirationTime'))) * 1000)
56   
57    arguments["from"] = createLoginKey(indicoID, indicoPassword, expirationTime)
58   
59    url = URL(actionURL)
60    url.setParams(arguments)
61    url.setSeparator('&')
62   
63    return url
64   
65def getEVOAnswer(action, arguments = {}, eventId = '', bookingId = ''):
66   
67    url = getRequestURL(action, arguments)
68       
69    Logger.get('EVO').info("""Evt:%s, booking:%s, sending request to EVO: [%s]""" % (eventId, bookingId, str(url)))
70   
71    try:
72        answer = urlOpenWithTimeout(str(url) , secondsToWait).read(readLimit).strip() #we remove any whitespaces, etc. We won't read more than 100k characters
73       
74    except HTTPError, e:
75        code = e.code
76        shortMessage = BaseHTTPRequestHandler.responses[code][0]
77        longMessage = BaseHTTPRequestHandler.responses[code][1]
78       
79        Logger.get('EVO').error("""Evt:%s, booking:%s, request: [%s] triggered HTTPError: %s (code = %s, shortMessage = '%s', longMessage = '%s'""" % (eventId, bookingId, str(url), str(e), code, shortMessage, longMessage))
80       
81        if str(code) == '404':
82            raise EVOException('Indico could not find the EVO Server at ' + getEVOOptionValueByName("httpServerLocation") + "(HTTP error 404)")
83        elif str(code) == '500':
84            raise EVOException("The EVO server has an internal problem (HTTP error 500)", e)
85        else:
86            raise EVOException("""Problem when Indico tried to contact the EVO Server.\nReason: HTTPError: %s (code = %s, shortMessage = '%s', longMessage = '%s', url = '%s'""" % (str(e), code, shortMessage, longMessage, str(url)), e)
87   
88    except URLError, e:
89        Logger.get('EVO').error("""Evt:%s, booking:%s, request: [%s] triggered exception: %s""" % (eventId, bookingId, str(url), str(e)))
90        if str(e.reason).strip() == 'timed out':
91            raise EVOException("The EVO server is not responding.", e)
92        raise EVOException('URLError when contacting the EVO server for action: ' + action + '. Reason="' + str(e.reason)+'"', e)
93   
94    else:
95        if answer.startswith("OK:"):
96            answer = answer[3:].strip() #we remove the "OK:"
97            Logger.get('EVO').info("""Evt:%s, booking:%s, got answer: [%s]""" % (eventId, bookingId, answer))
98            return answer
99       
100        elif answer.startswith("ERROR:"):
101            error = answer[6:].strip()
102            Logger.get('EVO').warning("""Evt:%s, booking:%s, request: [%s] triggered EVO error: %s""" % (eventId, bookingId, str(url), error))
103            if error == 'YOU_ARE_NOT_OWNER_OF_THE_MEETING' or error == 'NOT_AUTHORIZED_SERVER' or error == 'NOT_AUTHORIZED' or\
104                error == 'LOGIN_KEY_WRONG_LENGTH':
105                raise EVOException("Indico's EVO ID / pwd do not seem to be right. Please report to Indico support.", error)
106            elif error == 'REQUEST_EXPIRED':
107                raise EVOException("Problem contacting EVO: REQUEST_EXPIRED", 'REQUEST_EXPIRED. Something is going wrong with the UNIX timestamp?');
108            elif error == 'WRONG_EXPIRATION_TIME':
109                raise EVOException("Problem contacting EVO; WRONG_EXPIRATION_TIME", 'REQUEST_EXPIRED. Something is going wrong with the UNIX timestamp?');
110            else:
111                raise EVOControlledException(error)
112        else:
113            raise EVOException('Error when contacting the EVO server for action: ' + action + '. Message from the EVO server did not start by ERROR or OK', answer)
114       
115def parseEVOAnswer(answer):
116    """ Parses an answer such as
117        meet=48760&&start=0&&end=1000&&com=4&&type=0&&title=NewTestTitle&&desc=TestDesc&&url=[meeting=e9eIeivDveaeaBIDaaI9]
118        and returns a tuple of attributes.
119        the url attribute is transformed to the real koala URL
120    """
121   
122    attributesStringList = answer.split('&&')
123    attributes = {}
124    for attributeString in attributesStringList:
125        name, value = attributeString.split('=',1)
126        name = name.strip()
127        value = value.strip()
128        if name == 'url':
129            value = value[1:-1].strip() #we remove the brackets
130        attributes[name] = value
131    return attributes
132
133
134def createLoginKey(EVOID, password, time):
135    """ Obfuscates an EVOID / password couple with a unix timestamp
136        EVOID has to be an 8 digit (max) number / string number, ex: 123 or '123'
137        password has to be a 4 digits password, ex: 1234 or '1234'
138        time is unix time in milliseconds (13 digits max), ex: 12345
139
140        Returns an "obfuscated" EVO login key of 25 characters.
141    """
142    EVOID = str(EVOID)
143    password = str(password)
144    time = str(time)
145   
146    if len(EVOID) > 8:
147        raise EVOException("EVOID has to be 8 digits max")
148    if len(password) != 4:
149        raise EVOException("password has to be 4 digits")
150    if len(time) > 13:
151        raise EVOException("unix time has to be 13 digits max")
152   
153    key = array('c', ' '*25)
154    EVOID = EVOID.zfill(8)
155    time = time.zfill(13)
156   
157    for index, char in enumerate(time):
158        key[index*2] = char
159
160    for index, char in enumerate(EVOID):
161        key[19 - index * 2] = char
162
163    key[1] = password[0]
164    key[21] = password[1]
165    key[3] = password[2]
166    key[23] = password[3]
167
168    return key.tostring()
169
170
171def parseLoginKey(key):
172    """ Parses an "obfuscated" EVO login key of 25 characters.
173        Returns a tuple (EVOID, password, time)
174        EVOID will be an string with a number of maximum 8 digits.
175        time will be an integer, UNIX time in millesconds (13 digits max)
176        password will be a string of 4 characters
177    """
178    if len(key) != 25:
179        raise EVOException("key has to be a string of 25 characters")
180
181    EVOID = str(int("".join([key[i] for i in range (19,3,-2)])))
182    time = int("".join([key[i] for i in range(0,25,2)]))
183    password = "".join([key[1],key[21], key[3], key[23]])
184
185    return (EVOID, password, time)
186
187def getMinStartDate(conference):
188    return conference.getAdjustedStartDate() - timedelta(0,0,0,0, getEVOOptionValueByName("allowedMinutes"))
189
190def getMaxEndDate(conference):
191    return conference.getAdjustedEndDate() + timedelta(0,0,0,0, getEVOOptionValueByName("allowedMinutes"))
192   
193class EVOError(CSErrorBase):
194   
195    def __init__(self, errorType, requestURL = None, userMessage = None):
196        CSErrorBase.__init__(self)
197        self._errorType = errorType
198        self._requestURL = requestURL
199        self._userMessage = None
200       
201    @Retrieves(['MaKaC.plugins.Collaboration.EVO.common.EVOError',
202                'MaKaC.plugins.Collaboration.EVO.common.OverlappedError',
203                'MaKaC.plugins.Collaboration.EVO.common.ChangesFromEVOError'],
204               'errorType')
205    def getErrorType(self):
206        return self._errorType
207
208    @Retrieves(['MaKaC.plugins.Collaboration.EVO.common.EVOError',
209                'MaKaC.plugins.Collaboration.EVO.common.OverlappedError',
210                'MaKaC.plugins.Collaboration.EVO.common.ChangesFromEVOError'],
211               'requestURL')
212    def getRequestURL(self):
213        return self._requestURL
214   
215    def getUserMessage(self):
216        if self._userMessage:
217            return self._userMessage
218        else:
219            if self._errorType == 'duplicated':
220                return "This EVO meeting could not be created or changed because EVO considers the resulting meeting as duplicated."
221            elif self._errorType == 'start_in_past':
222                return "This EVO meeting could not be created or changed because EVO does not allow meeting starting in the past."
223            else:
224                return self._errorType
225   
226    def getLogMessage(self):
227        return "EVO Error: " + str(self._errorType) + " for request " + str(self._requestURL)
228
229   
230   
231class OverlappedError(EVOError):
232    def __init__(self, overlappedBooking):
233        EVOError.__init__(self, 'overlapped')
234        self._overlappedBooking = overlappedBooking
235       
236    @Retrieves(['MaKaC.plugins.Collaboration.EVO.common.OverlappedError'],
237               'overlappedBooking', isPicklableObject = True)
238    def getSuperposedBookingId(self):
239        return self._overlappedBooking
240   
241class ChangesFromEVOError(EVOError):
242
243    def __init__(self, changes):
244        EVOError.__init__(self, 'changesFromEVO')
245        self._changes = changes
246       
247    @Retrieves(['MaKaC.plugins.Collaboration.EVO.common.ChangesFromEVOError'],
248               'changes')
249    def getChanges(self):
250        return self._changes
251   
252   
253class EVOException(CollaborationException):
254    def __init__(self, msg, inner = None):
255        CollaborationException.__init__(self, msg, 'EVO', inner)
256
257class EVOControlledException(Exception):
258    def __init__(self, message):
259        self.message = message
260       
261class EVOWarning(object):
262   
263    def __init__(self, msg, exception = None):
264        self._msg = msg
265        self._exception = exception
266   
267    @Retrieves(['MaKaC.plugins.Collaboration.EVO.common.EVOWarning'],
268               'message')
269    def getMessage(self):
270        return self._msg
271   
272    @Retrieves(['MaKaC.plugins.Collaboration.EVO.common.EVOWarning'],
273               'exception')
274    def getException(self):
275        return self._exception
Note: See TracBrowser for help on using the repository browser.