| [9033fd] | 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. |
|---|
| [9881d7] | 20 | |
|---|
| [9033fd] | 21 | from MaKaC.conference import Category |
|---|
| 22 | |
|---|
| 23 | import sys, traceback, time, os |
|---|
| 24 | |
|---|
| 25 | from pytz import timezone |
|---|
| 26 | from datetime import datetime, date |
|---|
| 27 | |
|---|
| 28 | from MaKaC import conference |
|---|
| 29 | from MaKaC.common.timezoneUtils import setAdjustedDate |
|---|
| [3afe015] | 30 | from MaKaC.common import security, Config |
|---|
| [bc991f] | 31 | from MaKaC.common.externalOperationsManager import ExternalOperationsManager |
|---|
| [13ce65] | 32 | from MaKaC.common.utils import parseDateTime |
|---|
| [9881d7] | 33 | |
|---|
| [872d48] | 34 | from MaKaC.errors import MaKaCError, HtmlScriptError, HtmlForbiddenTag, TimingError |
|---|
| [e83ea5] | 35 | from MaKaC.services.interface.rpc.common import ServiceError, ServiceAccessError, HTMLSecurityError, Warning,\ |
|---|
| 36 | ResultWithWarning |
|---|
| [9033fd] | 37 | |
|---|
| [6328a5] | 38 | from MaKaC.webinterface.rh.base import RequestHandlerBase |
|---|
| [9033fd] | 39 | from MaKaC.webinterface.mail import GenericMailer, GenericNotification |
|---|
| 40 | |
|---|
| 41 | from MaKaC.accessControl import AccessWrapper |
|---|
| 42 | |
|---|
| [60f883] | 43 | from MaKaC.i18n import _ |
|---|
| [ba62ee] | 44 | from MaKaC.common.contextManager import ContextManager |
|---|
| [97a9da] | 45 | import MaKaC.common.info as info |
|---|
| [9033fd] | 46 | |
|---|
| 47 | """ |
|---|
| 48 | base module for asynchronous server requests |
|---|
| 49 | """ |
|---|
| 50 | |
|---|
| 51 | class ExpectedParameterException(ServiceError): |
|---|
| 52 | """ |
|---|
| 53 | Represents an exception that occurs when a type of parameter was expected |
|---|
| 54 | but another one was obtained |
|---|
| 55 | """ |
|---|
| [61589d] | 56 | |
|---|
| [9033fd] | 57 | def __init__(self, paramName, expected, got): |
|---|
| 58 | ServiceError.__init__(self, "ERR-P2","'%s': Expected '%s', got instead '%s'" % (paramName, expected, got)) |
|---|
| 59 | |
|---|
| [3bc472] | 60 | |
|---|
| [9033fd] | 61 | class EmptyParameterException(ServiceError): |
|---|
| 62 | """ |
|---|
| 63 | Thrown when a parameter that should have a value is empty |
|---|
| 64 | """ |
|---|
| 65 | def __init__(self, paramName=""): |
|---|
| 66 | ServiceError.__init__(self, "ERR-P3","Expected parameter '%s' is empty"%paramName) |
|---|
| 67 | |
|---|
| [3c0c20] | 68 | class DateTimeParameterException(ServiceError): |
|---|
| 69 | """ |
|---|
| 70 | Thrown when a parameter that should have a value is empty |
|---|
| 71 | """ |
|---|
| 72 | def __init__(self, paramName, value): |
|---|
| 73 | ServiceError.__init__(self, "ERR-P4","Date/Time %s = '%s' is not valid " % (paramName, value)) |
|---|
| 74 | |
|---|
| [3bc472] | 75 | |
|---|
| [9033fd] | 76 | class ParameterManager(object): |
|---|
| 77 | |
|---|
| 78 | """ |
|---|
| 79 | The ParameterManager makes parameter processing a bit easier, by providing |
|---|
| 80 | some default transformations |
|---|
| 81 | """ |
|---|
| [61589d] | 82 | |
|---|
| [9033fd] | 83 | def __init__(self, paramList, allowEmpty=False, timezone=None): |
|---|
| 84 | self._paramList = paramList |
|---|
| 85 | self._allowEmpty = allowEmpty |
|---|
| 86 | self._timezone = timezone |
|---|
| [61589d] | 87 | |
|---|
| [9033fd] | 88 | def extract(self, paramName, pType=None, allowEmpty=None, defaultValue=None): |
|---|
| 89 | """ |
|---|
| 90 | Extracts a parameter, given a parameter name, and optional type |
|---|
| 91 | """ |
|---|
| 92 | |
|---|
| 93 | # "global" policy applies if allowEmpty not set |
|---|
| 94 | if (allowEmpty == None): |
|---|
| 95 | allowEmpty = self._allowEmpty |
|---|
| [61589d] | 96 | |
|---|
| [9033fd] | 97 | value = self._paramList.get(paramName) |
|---|
| 98 | |
|---|
| [12296f] | 99 | if (not allowEmpty) and (value == None): |
|---|
| [9033fd] | 100 | raise EmptyParameterException(paramName) |
|---|
| [61589d] | 101 | |
|---|
| [9033fd] | 102 | if pType == str: |
|---|
| 103 | if value != None: |
|---|
| 104 | value = str(value) |
|---|
| 105 | else: |
|---|
| 106 | value = defaultValue |
|---|
| [61589d] | 107 | |
|---|
| [9033fd] | 108 | if (value == '' or value == None) and not allowEmpty: |
|---|
| 109 | raise EmptyParameterException(paramName) |
|---|
| 110 | elif pType == datetime: |
|---|
| 111 | # format will possibly be accomodated to different standards, |
|---|
| 112 | # in the future |
|---|
| 113 | |
|---|
| [3c0c20] | 114 | try: |
|---|
| 115 | # both strings and objects are accepted |
|---|
| 116 | if type(value) == str: |
|---|
| 117 | naiveDate = datetime.strptime(value, '%Y/%m/%d %H:%M') |
|---|
| [dba09b] | 118 | elif value: |
|---|
| [3c0c20] | 119 | naiveDate = datetime.strptime(value['date']+' '+value['time'][:5], '%Y/%m/%d %H:%M') |
|---|
| [dba09b] | 120 | elif not allowEmpty: |
|---|
| 121 | raise EmptyParameterException(paramName) |
|---|
| 122 | else: |
|---|
| 123 | naiveDate = None |
|---|
| [3c0c20] | 124 | except ValueError: |
|---|
| 125 | raise DateTimeParameterException(paramName, value) |
|---|
| [61589d] | 126 | |
|---|
| [dba09b] | 127 | if self._timezone and naiveDate: |
|---|
| [9033fd] | 128 | value = timezone(self._timezone).localize(naiveDate).astimezone(timezone('utc')) |
|---|
| 129 | else: |
|---|
| 130 | value = naiveDate |
|---|
| 131 | elif pType == date: |
|---|
| 132 | # format will possibly be accomodated to different standards, |
|---|
| 133 | # in the future |
|---|
| [3c0c20] | 134 | value = datetime.strptime(value,'%Y/%m/%d').date() |
|---|
| [9033fd] | 135 | elif pType == int: |
|---|
| 136 | if value == None and allowEmpty: |
|---|
| 137 | value = None |
|---|
| 138 | else: |
|---|
| 139 | value = int(value) |
|---|
| 140 | elif pType == float: |
|---|
| 141 | if value == None and allowEmpty: |
|---|
| 142 | value = None |
|---|
| 143 | else: |
|---|
| 144 | value = float(value) |
|---|
| 145 | elif pType == dict: |
|---|
| 146 | if not (type(value) == dict or (allowEmpty and value == None)): |
|---|
| 147 | raise ExpectedParameterException(paramName, dict, type(value)) |
|---|
| 148 | elif pType == list: |
|---|
| 149 | if not (type(value) == list or (allowEmpty and value == None)): |
|---|
| 150 | raise ExpectedParameterException(paramName, list, type(value)) |
|---|
| [12296f] | 151 | elif pType == bool: |
|---|
| 152 | if not (type(value) == bool or (allowEmpty and value == None)): |
|---|
| [f7f228] | 153 | raise ExpectedParameterException(paramName, bool, type(value)) |
|---|
| [9033fd] | 154 | |
|---|
| 155 | return value |
|---|
| 156 | |
|---|
| 157 | def setTimezone(self, tz): |
|---|
| 158 | self._timezone = tz |
|---|
| 159 | |
|---|
| [3bc472] | 160 | |
|---|
| [12296f] | 161 | class ServiceBase(RequestHandlerBase): |
|---|
| [9033fd] | 162 | """ |
|---|
| 163 | The ServiceBase class is the basic class for services. |
|---|
| [12296f] | 164 | """ |
|---|
| 165 | |
|---|
| [59dfb4] | 166 | def __init__(self, params, session, req): |
|---|
| [9033fd] | 167 | """ |
|---|
| 168 | Constructor. Initializes provate variables |
|---|
| 169 | @param req: HTTP Request provided by the previous layer |
|---|
| 170 | """ |
|---|
| [59dfb4] | 171 | RequestHandlerBase.__init__(self, req) |
|---|
| [490053] | 172 | self._reqParams = self._params = params |
|---|
| [9033fd] | 173 | self._requestStarted = False |
|---|
| 174 | self._websession = session |
|---|
| 175 | # Fill in the aw instance with the current information |
|---|
| 176 | self._aw = AccessWrapper() |
|---|
| [59dfb4] | 177 | self._aw.setIP(self.getHostIP()) |
|---|
| [9033fd] | 178 | self._aw.setSession(session) |
|---|
| 179 | self._aw.setUser(session.getUser()) |
|---|
| 180 | self._target = None |
|---|
| 181 | self._startTime = None |
|---|
| [175fad] | 182 | self._tohttps = self._req.is_https() |
|---|
| [9033fd] | 183 | self._endTime = None |
|---|
| 184 | self._doProcess = True #Flag which indicates whether the RH process |
|---|
| 185 | # must be carried out; this is useful for |
|---|
| 186 | # the checkProtection methods |
|---|
| 187 | self._tempFilesToDelete = [] |
|---|
| [928829] | 188 | |
|---|
| [9033fd] | 189 | # Methods ============================================================= |
|---|
| [928829] | 190 | |
|---|
| [9033fd] | 191 | def _getSession( self ): |
|---|
| 192 | """ |
|---|
| [928829] | 193 | Returns the web session associated to the received mod_python |
|---|
| [9033fd] | 194 | request. |
|---|
| 195 | """ |
|---|
| 196 | return self._websession |
|---|
| [928829] | 197 | |
|---|
| [9033fd] | 198 | def _checkParams(self): |
|---|
| 199 | """ |
|---|
| 200 | Checks the request parameters (normally overloaded) |
|---|
| 201 | """ |
|---|
| 202 | pass |
|---|
| [928829] | 203 | |
|---|
| [9033fd] | 204 | def _checkProtection( self ): |
|---|
| 205 | """ |
|---|
| 206 | Checks protection when accessing resources (normally overloaded) |
|---|
| 207 | """ |
|---|
| 208 | pass |
|---|
| 209 | |
|---|
| 210 | def _processError(self): |
|---|
| 211 | """ |
|---|
| 212 | Treats errors occured during the process of a RH, returning an error string. |
|---|
| 213 | @param e: the exception |
|---|
| 214 | @type e: An Exception-derived type |
|---|
| 215 | """ |
|---|
| [928829] | 216 | |
|---|
| [9033fd] | 217 | trace = traceback.format_exception(*sys.exc_info()) |
|---|
| [928829] | 218 | |
|---|
| [9033fd] | 219 | return ''.join(trace) |
|---|
| 220 | |
|---|
| 221 | def _deleteTempFiles( self ): |
|---|
| 222 | if len(self._tempFilesToDelete) > 0: |
|---|
| 223 | for file in self._tempFilesToDelete: |
|---|
| 224 | os.remove(file) |
|---|
| [928829] | 225 | |
|---|
| [9033fd] | 226 | def process(self): |
|---|
| 227 | """ |
|---|
| 228 | Processes the request, analyzing the parameters, and feeding them to the |
|---|
| 229 | _getAnswer() method (implemented by derived classes) |
|---|
| 230 | """ |
|---|
| 231 | |
|---|
| [ba62ee] | 232 | ContextManager.set('currentRH', self) |
|---|
| 233 | |
|---|
| [f25f07] | 234 | self._setLang() |
|---|
| [9033fd] | 235 | self._checkParams() |
|---|
| 236 | self._checkProtection() |
|---|
| 237 | |
|---|
| 238 | try: |
|---|
| [310d46] | 239 | security.Sanitization.sanitizationCheck(self._target, |
|---|
| [9033fd] | 240 | self._params, |
|---|
| 241 | self._aw) |
|---|
| [872d48] | 242 | except (HtmlScriptError, HtmlForbiddenTag), e: |
|---|
| [40cfd6] | 243 | raise HTMLSecurityError('ERR-X0','HTML Security problem. %s ' % str(e)) |
|---|
| [928829] | 244 | |
|---|
| [9033fd] | 245 | if self._doProcess: |
|---|
| [3afe015] | 246 | if Config.getInstance().getProfile(): |
|---|
| 247 | import profile, pstats, random |
|---|
| 248 | proffilename = os.path.join(Config.getInstance().getTempDir(), "service%s.prof" % random.random()) |
|---|
| 249 | result = [None] |
|---|
| 250 | profile.runctx("result[0] = self._getAnswer()", globals(), locals(), proffilename) |
|---|
| 251 | answer = result[0] |
|---|
| 252 | rep = Config.getInstance().getTempDir() |
|---|
| 253 | stats = pstats.Stats(proffilename) |
|---|
| 254 | stats.strip_dirs() |
|---|
| 255 | stats.sort_stats('cumulative', 'time', 'calls') |
|---|
| 256 | stats.dump_stats(os.path.join(rep, "IndicoServiceRequestProfile.log")) |
|---|
| 257 | os.remove(proffilename) |
|---|
| 258 | else: |
|---|
| 259 | answer = self._getAnswer() |
|---|
| [9033fd] | 260 | self._deleteTempFiles() |
|---|
| [928829] | 261 | |
|---|
| 262 | return answer |
|---|
| [9033fd] | 263 | |
|---|
| 264 | def _getAnswer(self): |
|---|
| 265 | """ |
|---|
| 266 | To be overloaded. It should contain the code that does the actual |
|---|
| 267 | business logic and returns a result (python JSON-serializable object). |
|---|
| 268 | If this method is not overloaded, an exception will occur. |
|---|
| 269 | If you don't want to return an answer, you should still implement this method with 'pass'. |
|---|
| 270 | """ |
|---|
| 271 | # This exception will happen if the _getAnswer method is not implemented in a derived class |
|---|
| 272 | raise MaKaCError("No answer was returned") |
|---|
| 273 | |
|---|
| 274 | |
|---|
| 275 | class ProtectedService(ServiceBase): |
|---|
| 276 | """ |
|---|
| [f78b0c] | 277 | ProtectedService is a parent class for ProtectedDisplayService and ProtectedModificationService |
|---|
| [9033fd] | 278 | """ |
|---|
| 279 | |
|---|
| [928829] | 280 | def _checkSessionUser(self): |
|---|
| 281 | """ |
|---|
| 282 | Checks that the current user exists (is authenticated) |
|---|
| 283 | """ |
|---|
| 284 | |
|---|
| 285 | if self._getUser() == None: |
|---|
| 286 | self._doProcess = False |
|---|
| [a755c1] | 287 | raise ServiceAccessError("You are currently not authenticated. Please log in again.") |
|---|
| [928829] | 288 | |
|---|
| [9033fd] | 289 | |
|---|
| 290 | class ProtectedDisplayService(ProtectedService): |
|---|
| 291 | """ |
|---|
| 292 | A ProtectedDisplayService can only be accessed by users that |
|---|
| 293 | are authorized to "see" the target resource |
|---|
| 294 | """ |
|---|
| [f78b0c] | 295 | |
|---|
| [9033fd] | 296 | def _checkProtection( self ): |
|---|
| 297 | """ |
|---|
| 298 | Overloads ProtectedService._checkProtection, assuring that |
|---|
| 299 | the user is authorized to view the target resource |
|---|
| 300 | """ |
|---|
| [f7f228] | 301 | if not self._target.canAccess( self.getAW() ): |
|---|
| [f78b0c] | 302 | |
|---|
| [9033fd] | 303 | from MaKaC.conference import Link, LocalFile |
|---|
| 304 | |
|---|
| 305 | # in some cases, the target does not directly have an owner |
|---|
| 306 | if (isinstance(self._target, Link) or |
|---|
| 307 | isinstance(self._target, LocalFile)): |
|---|
| 308 | target = self._target.getOwner() |
|---|
| 309 | else: |
|---|
| 310 | target = self._target |
|---|
| 311 | if not isinstance(target, Category): |
|---|
| 312 | if target.getAccessKey() != "" or target.getConference().getAccessKey() != "": |
|---|
| [a755c1] | 313 | raise ServiceAccessError("You are currently not authenticated or cannot access this service. Please log in again if necessary.") |
|---|
| [9033fd] | 314 | if self._getUser() == None: |
|---|
| 315 | self._checkSessionUser() |
|---|
| 316 | else: |
|---|
| [a755c1] | 317 | raise ServiceAccessError("You cannot access this service. Please log in again if necessary.") |
|---|
| [9033fd] | 318 | |
|---|
| 319 | |
|---|
| 320 | class LoggedOnlyService(ProtectedService): |
|---|
| 321 | """ |
|---|
| [f78b0c] | 322 | Only accessible to users who are logged in (access keys not allowed) |
|---|
| [9033fd] | 323 | """ |
|---|
| 324 | |
|---|
| [f78b0c] | 325 | def _checkProtection( self ): |
|---|
| 326 | self._checkSessionUser() |
|---|
| 327 | |
|---|
| [9033fd] | 328 | |
|---|
| 329 | class ProtectedModificationService(ProtectedService): |
|---|
| 330 | """ |
|---|
| 331 | A ProtectedModificationService can only be accessed by users that |
|---|
| 332 | are authorized to modify the target resource |
|---|
| 333 | """ |
|---|
| 334 | def _checkProtection( self ): |
|---|
| 335 | """ |
|---|
| 336 | Overloads ProtectedService._checkProtection, so that it is |
|---|
| 337 | verified if the user has modification access to the resource |
|---|
| 338 | """ |
|---|
| 339 | |
|---|
| 340 | target = self._target |
|---|
| 341 | if (type(target) == conference.SessionSlot): |
|---|
| 342 | target = target.getSession() |
|---|
| [928829] | 343 | |
|---|
| [9033fd] | 344 | if not target.canModify( self.getAW() ): |
|---|
| 345 | if target.getModifKey() != "": |
|---|
| [a755c1] | 346 | raise ServiceAccessError("You don't have the rights to modify this object") |
|---|
| [9033fd] | 347 | if self._getUser() == None: |
|---|
| 348 | self._checkSessionUser() |
|---|
| 349 | else: |
|---|
| [a755c1] | 350 | raise ServiceAccessError("You don't have the rights to modify this object") |
|---|
| [cbf814] | 351 | if hasattr(self._target, "getConference") and hasattr(self._target, "isClosed"): |
|---|
| [9033fd] | 352 | if target.getConference().isClosed(): |
|---|
| [a755c1] | 353 | raise ServiceAccessError("Conference %s is closed"%target.getConference().getId()) |
|---|
| [9033fd] | 354 | |
|---|
| [f78b0c] | 355 | class AdminService(LoggedOnlyService): |
|---|
| [9033fd] | 356 | """ |
|---|
| 357 | A AdminService can only be accessed by administrators |
|---|
| 358 | """ |
|---|
| 359 | def _checkProtection( self ): |
|---|
| 360 | """ |
|---|
| 361 | Overloads ProtectedService._checkProtection |
|---|
| 362 | """ |
|---|
| 363 | |
|---|
| [f78b0c] | 364 | LoggedOnlyService._checkProtection(self) |
|---|
| [9033fd] | 365 | |
|---|
| 366 | if not self._getUser().isAdmin(): |
|---|
| [a755c1] | 367 | raise ServiceAccessError(_("Only administrators can perform this operation")) |
|---|
| [9033fd] | 368 | |
|---|
| [3bc472] | 369 | class TextModificationBase: |
|---|
| [9033fd] | 370 | """ |
|---|
| 371 | Base class for text field modification |
|---|
| 372 | """ |
|---|
| [41eb27] | 373 | |
|---|
| [9033fd] | 374 | def _getAnswer( self ): |
|---|
| [e83ea5] | 375 | """ Calls _handleGet() or _handleSet() on the derived classes, in order to make it happen. Provides |
|---|
| 376 | them with self._value. |
|---|
| [928829] | 377 | |
|---|
| [e83ea5] | 378 | When calling _handleGet(), it will return the value to return. |
|---|
| 379 | When calling _handleSet(), it will return: |
|---|
| 380 | -either self._value if there were no problems |
|---|
| 381 | -either a FieldModificationWarning object (pickled) if there are warnings to give to the user |
|---|
| [9033fd] | 382 | """ |
|---|
| [41eb27] | 383 | |
|---|
| 384 | # fetch the 'value' parameter (default for text) |
|---|
| [9033fd] | 385 | if self._params.has_key('value'): |
|---|
| 386 | self._value = self._params['value'] |
|---|
| 387 | else: |
|---|
| [41eb27] | 388 | # None if not passed |
|---|
| [9033fd] | 389 | self._value = None |
|---|
| [41eb27] | 390 | |
|---|
| [9033fd] | 391 | if self._value == None: |
|---|
| 392 | return self._handleGet() |
|---|
| 393 | else: |
|---|
| [e83ea5] | 394 | setResult = self._handleSet() |
|---|
| 395 | if isinstance(setResult, Warning): |
|---|
| [d25c08] | 396 | return ResultWithWarning(self._value, setResult).fossilize() |
|---|
| [e83ea5] | 397 | else: |
|---|
| 398 | return self._value |
|---|
| [9033fd] | 399 | |
|---|
| [3bc472] | 400 | class HTMLModificationBase: |
|---|
| [9033fd] | 401 | """ |
|---|
| 402 | Base class for HTML field modification |
|---|
| 403 | """ |
|---|
| 404 | def _getAnswer( self ): |
|---|
| 405 | """ |
|---|
| 406 | Calls _handle() on the derived classes, in order to make it happen. Provides |
|---|
| 407 | them with self._value. |
|---|
| 408 | """ |
|---|
| [928829] | 409 | |
|---|
| [9033fd] | 410 | if self._params.has_key('value'): |
|---|
| 411 | self._value = self._params['value'] |
|---|
| 412 | else: |
|---|
| 413 | self._value = None |
|---|
| [928829] | 414 | |
|---|
| [9033fd] | 415 | if self._value == None: |
|---|
| 416 | return self._handleGet() |
|---|
| 417 | else: |
|---|
| 418 | self._handleSet() |
|---|
| [928829] | 419 | |
|---|
| [9033fd] | 420 | return self._value |
|---|
| 421 | |
|---|
| 422 | |
|---|
| 423 | class DateTimeModificationBase( TextModificationBase ): |
|---|
| [e83ea5] | 424 | """ Date and time modification base class |
|---|
| 425 | Its _handleSet method is called by TextModificationBase's _getAnswer method. |
|---|
| 426 | DateTimeModificationBase's _handletSet method will call the _setParam method |
|---|
| 427 | from the classes that inherits from DateTimeModificationBase. |
|---|
| 428 | _handleSet will return whatever _setParam returns (usually None if there were no problems, |
|---|
| [928829] | 429 | or a FieldModificationWarning object with information about a problem / warning to give to the user) |
|---|
| [9033fd] | 430 | """ |
|---|
| 431 | def _handleSet(self): |
|---|
| 432 | try: |
|---|
| [13ce65] | 433 | naiveDate = parseDateTime(self._value) |
|---|
| [9033fd] | 434 | except ValueError: |
|---|
| 435 | raise ServiceError("ERR-E2", |
|---|
| 436 | "Date/time is not in the correct format") |
|---|
| [9881d7] | 437 | |
|---|
| [ef4d2c] | 438 | try: |
|---|
| 439 | self._pTime = setAdjustedDate(naiveDate, self._conf) |
|---|
| [9881d7] | 440 | return self._setParam() |
|---|
| [ef4d2c] | 441 | except TimingError,e: |
|---|
| 442 | raise ServiceError("ERR-E2", e.getMsg()) |
|---|
| 443 | |
|---|
| [fe1e0a] | 444 | class ListModificationBase: |
|---|
| [9033fd] | 445 | """ Base class for a list modification. |
|---|
| 446 | The class that inherits from this must have: |
|---|
| 447 | -a _handleGet() method that returns a list. |
|---|
| 448 | -a _handleSet() method which can use self._value to process the input. self._value will be a list. |
|---|
| 449 | """ |
|---|
| [928829] | 450 | |
|---|
| [9033fd] | 451 | def _getAnswer(self): |
|---|
| 452 | if self._params.has_key('value'): |
|---|
| 453 | pm = ParameterManager(self._params) |
|---|
| 454 | self._value = pm.extract("value", pType=list, allowEmpty=True) |
|---|
| 455 | else: |
|---|
| 456 | self._value = None |
|---|
| [928829] | 457 | |
|---|
| [9033fd] | 458 | if self._value == None: |
|---|
| 459 | return self._handleGet() |
|---|
| 460 | else: |
|---|
| 461 | self._handleSet() |
|---|
| [928829] | 462 | |
|---|
| [9033fd] | 463 | return self._value |
|---|
| 464 | |
|---|
| [fe1e0a] | 465 | class TwoListModificationBase: |
|---|
| [9033fd] | 466 | """ Base class for two lists modification. |
|---|
| 467 | The class that inherits from this must have: |
|---|
| 468 | -a _handleGet() method that returns a list, given self._destination |
|---|
| 469 | -a _handleSet() method which can use self._value and self._destination to process the input. |
|---|
| 470 | self._value will be a list. self._destination will be 'left' or 'right' |
|---|
| 471 | """ |
|---|
| [928829] | 472 | |
|---|
| [9033fd] | 473 | def _getAnswer(self): |
|---|
| 474 | self._destination = self._params.get('destination', None) |
|---|
| 475 | if self._destination == None or (self._destination != 'right' and self._destination != 'left'): |
|---|
| 476 | #TODO: add this error to the wiki |
|---|
| 477 | raise ServiceError("ERR-E4", 'Destination list not set to "right" or "left"') |
|---|
| [928829] | 478 | |
|---|
| [9033fd] | 479 | if self._params.has_key('value'): |
|---|
| 480 | pm = ParameterManager(self._params) |
|---|
| 481 | self._value = pm.extract("value", pType=list, allowEmpty=False) |
|---|
| 482 | else: |
|---|
| 483 | self._value = None |
|---|
| [928829] | 484 | |
|---|
| [9033fd] | 485 | if self._value == None: |
|---|
| 486 | return self._handleGet() |
|---|
| 487 | else: |
|---|
| 488 | self._handleSet() |
|---|
| 489 | |
|---|
| [928829] | 490 | return self._value |
|---|
| [97a9da] | 491 | |
|---|
| [b4a8e5] | 492 | |
|---|
| 493 | class ExportToICalBase(object): |
|---|
| [97a9da] | 494 | |
|---|
| 495 | def _checkParams(self): |
|---|
| 496 | minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance() |
|---|
| 497 | self._apiMode = minfo.getAPIMode() |
|---|
| [b4a8e5] | 498 | user = self._getUser() |
|---|
| [97a9da] | 499 | if not user: |
|---|
| [b4a8e5] | 500 | raise ServiceError("ERR-U0", "User is not logged in!") |
|---|
| [97a9da] | 501 | apiKey = user.getAPIKey() |
|---|
| 502 | if not apiKey: |
|---|
| [b4a8e5] | 503 | raise ServiceError("ERR-U1", "User has no API key!") |
|---|
| [97a9da] | 504 | elif apiKey.isBlocked(): |
|---|
| [b4a8e5] | 505 | raise ServiceError("ERR-U1", "This API key is blocked!") |
|---|
| [97a9da] | 506 | self._apiKey = apiKey |
|---|