VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/webui/wuibase.py@ 78352

Last change on this file since 78352 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuibase.py 76553 2019-01-01 01:45:53Z vboxsync $
3
4"""
5Test Manager Web-UI - Base Classes.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2019 Oracle Corporation
11
12This file is part of VirtualBox Open Source Edition (OSE), as
13available from http://www.virtualbox.org. This file is free software;
14you can redistribute it and/or modify it under the terms of the GNU
15General Public License (GPL) as published by the Free Software
16Foundation, in version 2 as it comes in the "COPYING" file of the
17VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL) only, as it comes in the "COPYING.CDDL" file of the
23VirtualBox OSE distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28"""
29__version__ = "$Revision: 76553 $"
30
31
32# Standard python imports.
33import os;
34import sys;
35import string;
36
37# Validation Kit imports.
38from common import webutils, utils;
39from testmanager import config;
40from testmanager.core.base import ModelDataBase, ModelLogicBase, TMExceptionBase;
41from testmanager.core.db import TMDatabaseConnection;
42from testmanager.core.systemlog import SystemLogLogic, SystemLogData;
43from testmanager.core.useraccount import UserAccountLogic
44
45# Python 3 hacks:
46if sys.version_info[0] >= 3:
47 unicode = str; # pylint: disable=redefined-builtin,invalid-name
48 long = int; # pylint: disable=redefined-builtin,invalid-name
49
50
51class WuiException(TMExceptionBase):
52 """
53 For exceptions raised by Web UI code.
54 """
55 pass;
56
57
58class WuiDispatcherBase(object):
59 """
60 Base class for the Web User Interface (WUI) dispatchers.
61
62 The dispatcher class defines the basics of the page (like base template,
63 menu items, action). It is also responsible for parsing requests and
64 dispatching them to action (POST) or/and content generators (GET+POST).
65 The content returned by the generator is merged into the template and sent
66 back to the webserver glue.
67 """
68
69 ## @todo possible that this should all go into presentation.
70
71 ## The action parameter.
72 ksParamAction = 'Action';
73 ## The name of the default action.
74 ksActionDefault = 'default';
75
76 ## The name of the current page number parameter used when displaying lists.
77 ksParamPageNo = 'PageNo';
78 ## The name of the page length (list items) parameter when displaying lists.
79 ksParamItemsPerPage = 'ItemsPerPage';
80
81 ## The name of the effective date (timestamp) parameter.
82 ksParamEffectiveDate = 'EffectiveDate';
83
84 ## The name of the redirect-to (test manager relative url) parameter.
85 ksParamRedirectTo = 'RedirectTo';
86
87 ## The name of the list-action parameter (WuiListContentWithActionBase).
88 ksParamListAction = 'ListAction';
89
90 ## One or more columns to sort by.
91 ksParamSortColumns = 'SortBy';
92
93 ## The name of the change log enabled/disabled parameter.
94 ksParamChangeLogEnabled = 'ChangeLogEnabled';
95 ## The name of the parmaeter indicating the change log page number.
96 ksParamChangeLogPageNo = 'ChangeLogPageNo';
97 ## The name of the parameter indicate number of change log entries per page.
98 ksParamChangeLogEntriesPerPage = 'ChangeLogEntriesPerPage';
99
100 ## @name Dispatcher debugging parameters.
101 ## {@
102 ksParamDbgSqlTrace = 'DbgSqlTrace';
103 ksParamDbgSqlExplain = 'DbgSqlExplain';
104 ## List of all debugging parameters.
105 kasDbgParams = (ksParamDbgSqlTrace, ksParamDbgSqlExplain,);
106 ## @}
107
108 ## Special action return code for skipping _generatePage. Useful for
109 # download pages and the like that messes with the HTTP header and more.
110 ksDispatchRcAllDone = 'Done - Page has been rendered already';
111
112
113 def __init__(self, oSrvGlue, sScriptName):
114 self._oSrvGlue = oSrvGlue;
115 self._oDb = TMDatabaseConnection(self.dprint if config.g_kfWebUiSqlDebug else None, oSrvGlue = oSrvGlue);
116 self._tsNow = None; # Set by getEffectiveDateParam.
117 self._asCheckedParams = [];
118 self._dParams = None; # Set by dispatchRequest.
119 self._sAction = None; # Set by dispatchRequest.
120 self._dDispatch = { self.ksActionDefault: self._actionDefault, };
121
122 # Template bits.
123 self._sTemplate = 'template-default.html';
124 self._sPageTitle = '$$TODO$$'; # The page title.
125 self._aaoMenus = []; # List of [sName, sLink, [ [sSideName, sLink], .. ] tuples.
126 self._sPageFilter = ''; # The filter controls (optional).
127 self._sPageBody = '$$TODO$$'; # The body text.
128 self._dSideMenuFormAttrs = {}; # key/value with attributes for the side menu <form> tag.
129 self._sRedirectTo = None;
130 self._sDebug = '';
131
132 # Debugger bits.
133 self._fDbgSqlTrace = False;
134 self._fDbgSqlExplain = False;
135 self._dDbgParams = dict();
136 for sKey, sValue in oSrvGlue.getParameters().iteritems():
137 if sKey in self.kasDbgParams:
138 self._dDbgParams[sKey] = sValue;
139 if self._dDbgParams:
140 from testmanager.webui.wuicontentbase import WuiTmLink;
141 WuiTmLink.kdDbgParams = self._dDbgParams;
142
143 # Determine currently logged in user credentials
144 self._oCurUser = UserAccountLogic(self._oDb).tryFetchAccountByLoginName(oSrvGlue.getLoginName());
145
146 # Calc a couple of URL base strings for this dispatcher.
147 self._sUrlBase = sScriptName + '?';
148 if self._dDbgParams:
149 self._sUrlBase += webutils.encodeUrlParams(self._dDbgParams) + '&';
150 self._sActionUrlBase = self._sUrlBase + self.ksParamAction + '=';
151
152
153 def _redirectPage(self):
154 """
155 Redirects the page to the URL given in self._sRedirectTo.
156 """
157 assert self._sRedirectTo;
158 assert self._sPageBody is None;
159 assert self._sPageTitle is None;
160
161 self._oSrvGlue.setRedirect(self._sRedirectTo);
162 return True;
163
164 def _isMenuMatch(self, sMenuUrl, sActionParam):
165 """ Overridable menu matcher. """
166 return sMenuUrl is not None and sMenuUrl.find(sActionParam) > 0;
167
168 def _isSideMenuMatch(self, sSideMenuUrl, sActionParam):
169 """ Overridable side menu matcher. """
170 return sSideMenuUrl is not None and sSideMenuUrl.find(sActionParam) > 0;
171
172 def _generateMenus(self):
173 """
174 Generates the two menus, returning them as (sTopMenuItems, sSideMenuItems).
175 """
176 fReadOnly = self.isReadOnlyUser();
177
178 #
179 # We use the action to locate the side menu.
180 #
181 aasSideMenu = None;
182 for cchAction in range(len(self._sAction), 1, -1):
183 sActionParam = '%s=%s' % (self.ksParamAction, self._sAction[:cchAction]);
184 for aoItem in self._aaoMenus:
185 if self._isMenuMatch(aoItem[1], sActionParam):
186 aasSideMenu = aoItem[2];
187 break;
188 for asSubItem in aoItem[2]:
189 if self._isMenuMatch(asSubItem[1], sActionParam):
190 aasSideMenu = aoItem[2];
191 break;
192 if aasSideMenu is not None:
193 break;
194
195 #
196 # Top menu first.
197 #
198 sTopMenuItems = '';
199 for aoItem in self._aaoMenus:
200 if aasSideMenu is aoItem[2]:
201 sTopMenuItems += '<li class="current_page_item">';
202 else:
203 sTopMenuItems += '<li>';
204 sTopMenuItems += '<a href="' + webutils.escapeAttr(aoItem[1]) + '">' \
205 + webutils.escapeElem(aoItem[0]) + '</a></li>\n';
206
207 #
208 # Side menu (if found).
209 #
210 sActionParam = '%s=%s' % (self.ksParamAction, self._sAction);
211 sSideMenuItems = '';
212 if aasSideMenu is not None:
213 for asSubItem in aasSideMenu:
214 if asSubItem[1] is not None:
215 if not asSubItem[2] or not fReadOnly:
216 if self._isSideMenuMatch(asSubItem[1], sActionParam):
217 sSideMenuItems += '<li class="current_page_item">';
218 else:
219 sSideMenuItems += '<li>';
220 sSideMenuItems += '<a href="' + webutils.escapeAttr(asSubItem[1]) + '">' \
221 + webutils.escapeElem(asSubItem[0]) + '</a></li>\n';
222 else:
223 sSideMenuItems += '<li class="subheader_item">' + webutils.escapeElem(asSubItem[0]) + '</li>';
224 return (sTopMenuItems, sSideMenuItems);
225
226 def _generatePage(self):
227 """
228 Generates the page using _sTemplate, _sPageTitle, _aaoMenus, and _sPageBody.
229 """
230 assert self._sRedirectTo is None;
231
232 #
233 # Build the replacement string dictionary.
234 #
235
236 # Provide basic auth log out for browsers that supports it.
237 sUserAgent = self._oSrvGlue.getUserAgent();
238 if (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Firefox') > 0) \
239 or False:
240 # Log in as the logout user in the same realm, the browser forgets
241 # the old login and the job is done. (see apache sample conf)
242 sLogOut = ' (<a href="%s://logout:logout@%s%slogout.py">logout</a>)' \
243 % (self._oSrvGlue.getUrlScheme(), self._oSrvGlue.getUrlNetLoc(), self._oSrvGlue.getUrlBasePath());
244 elif (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Safari') > 0) \
245 or False:
246 # For a 401, causing the browser to forget the old login. Works
247 # with safari as well as the two above. Since safari consider the
248 # above method a phishing attempt and displays a warning to that
249 # effect, which when taken seriously aborts the logout, this method
250 # is preferable, even if it throws logon boxes in the user's face
251 # till he/she/it hits escape, because it always works.
252 sLogOut = ' (<a href="logout2.py">logout</a>)'
253 elif (sUserAgent.startswith('Mozilla/') and sUserAgent.find('MSIE') > 0) \
254 or (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Chrome') > 0) \
255 or False:
256 ## There doesn't seem to be any way to make IE really log out
257 # without using a cookie and systematically 401 accesses based on
258 # some logout state associated with it. Not sure how secure that
259 # can be made and we really want to avoid cookies. So, perhaps,
260 # just avoid IE for now. :-)
261 ## Chrome/21.0 doesn't want to log out either.
262 sLogOut = ''
263 else:
264 sLogOut = ''
265
266 # Prep Menus.
267 (sTopMenuItems, sSideMenuItems) = self._generateMenus();
268
269 # The dictionary (max variable length is 28 chars (see further down)).
270 dReplacements = {
271 '@@PAGE_TITLE@@': self._sPageTitle,
272 '@@LOG_OUT@@': sLogOut,
273 '@@TESTMANAGER_VERSION@@': config.g_ksVersion,
274 '@@TESTMANAGER_REVISION@@': config.g_ksRevision,
275 '@@BASE_URL@@': self._oSrvGlue.getBaseUrl(),
276 '@@TOP_MENU_ITEMS@@': sTopMenuItems,
277 '@@SIDE_MENU_ITEMS@@': sSideMenuItems,
278 '@@SIDE_FILTER_CONTROL@@': self._sPageFilter,
279 '@@SIDE_MENU_FORM_ATTRS@@': '',
280 '@@PAGE_BODY@@': self._sPageBody,
281 '@@DEBUG@@': '',
282 };
283
284 # Side menu form attributes.
285 if self._dSideMenuFormAttrs:
286 dReplacements['@@SIDE_MENU_FORM_ATTRS@@'] = ' '.join(['%s="%s"' % (sKey, webutils.escapeAttr(sValue))
287 for sKey, sValue in self._dSideMenuFormAttrs.items()]);
288
289 # Special current user handling.
290 if self._oCurUser is not None:
291 dReplacements['@@USER_NAME@@'] = self._oCurUser.sUsername;
292 else:
293 dReplacements['@@USER_NAME@@'] = 'unauthorized user "' + self._oSrvGlue.getLoginName() + '"';
294
295 # Prep debug section.
296 if self._sDebug == '':
297 if config.g_kfWebUiSqlTrace or self._fDbgSqlTrace or self._fDbgSqlExplain:
298 self._sDebug = '<h3>Processed in %s ns.</h3>\n%s\n' \
299 % ( utils.formatNumber(utils.timestampNano() - self._oSrvGlue.tsStart,),
300 self._oDb.debugHtmlReport(self._oSrvGlue.tsStart));
301 elif config.g_kfWebUiProcessedIn:
302 self._sDebug = '<h3>Processed in %s ns.</h3>\n' \
303 % ( utils.formatNumber(utils.timestampNano() - self._oSrvGlue.tsStart,), );
304 if config.g_kfWebUiDebugPanel:
305 self._sDebug += self._debugRenderPanel();
306 if self._sDebug != '':
307 dReplacements['@@DEBUG@@'] = u'<div id="debug"><br><br><hr/>' \
308 + (unicode(self._sDebug, errors='ignore') if isinstance(self._sDebug, str)
309 else self._sDebug) \
310 + u'</div>\n';
311
312 #
313 # Load the template.
314 #
315 oFile = open(os.path.join(self._oSrvGlue.pathTmWebUI(), self._sTemplate));
316 sTmpl = oFile.read();
317 oFile.close();
318
319 #
320 # Process the template, outputting each part we process.
321 #
322 offStart = 0;
323 offCur = 0;
324 while offCur < len(sTmpl):
325 # Look for a replacement variable.
326 offAtAt = sTmpl.find('@@', offCur);
327 if offAtAt < 0:
328 break;
329 offCur = offAtAt + 2;
330 if sTmpl[offCur] not in string.ascii_uppercase:
331 continue;
332 offEnd = sTmpl.find('@@', offCur, offCur+28);
333 if offEnd <= 0:
334 continue;
335 offCur = offEnd;
336 sReplacement = sTmpl[offAtAt:offEnd+2];
337 if sReplacement in dReplacements:
338 # Got a match! Write out the previous chunk followed by the replacement text.
339 if offStart < offAtAt:
340 self._oSrvGlue.write(sTmpl[offStart:offAtAt]);
341 self._oSrvGlue.write(dReplacements[sReplacement]);
342 # Advance past the replacement point in the template.
343 offCur += 2;
344 offStart = offCur;
345 else:
346 assert False, 'Unknown replacement "%s" at offset %s in %s' % (sReplacement, offAtAt, self._sTemplate );
347
348 # The final chunk.
349 if offStart < len(sTmpl):
350 self._oSrvGlue.write(sTmpl[offStart:]);
351
352 return True;
353
354 #
355 # Interface for WuiContentBase classes.
356 #
357
358 def getParameters(self):
359 """
360 Returns a (shallow) copy of the request parameter dictionary.
361 """
362 return self._dParams.copy();
363
364 def getDb(self):
365 """
366 Returns the database connection.
367 """
368 return self._oDb;
369
370 def getNow(self):
371 """
372 Returns the effective date.
373 """
374 return self._tsNow;
375
376
377 #
378 # Parameter handling.
379 #
380
381 def getStringParam(self, sName, asValidValues = None, sDefault = None, fAllowNull = False):
382 """
383 Gets a string parameter.
384 Raises exception if not found and sDefault is None.
385 """
386 if sName in self._dParams:
387 if sName not in self._asCheckedParams:
388 self._asCheckedParams.append(sName);
389 sValue = self._dParams[sName];
390 if isinstance(sValue, list):
391 raise WuiException('%s parameter "%s" is given multiple times: "%s"' % (self._sAction, sName, sValue));
392 sValue = sValue.strip();
393 elif sDefault is None and fAllowNull is not True:
394 raise WuiException('%s is missing parameters: "%s"' % (self._sAction, sName,));
395 else:
396 sValue = sDefault;
397
398 if asValidValues is not None and sValue not in asValidValues:
399 raise WuiException('%s parameter %s value "%s" not in %s '
400 % (self._sAction, sName, sValue, asValidValues));
401 return sValue;
402
403 def getBoolParam(self, sName, fDefault = None):
404 """
405 Gets a boolean parameter.
406 Raises exception if not found and fDefault is None, or if not a valid boolean.
407 """
408 sValue = self.getStringParam(sName, [ 'True', 'true', '1', 'False', 'false', '0'],
409 '0' if fDefault is None else str(fDefault));
410 # HACK: Checkboxes doesn't return a value when unchecked, so we always
411 # provide a default when dealing with boolean parameters.
412 return sValue == 'True' or sValue == 'true' or sValue == '1';
413
414 def getIntParam(self, sName, iMin = None, iMax = None, iDefault = None):
415 """
416 Gets a integer parameter.
417 Raises exception if not found and iDefault is None, if not a valid int,
418 or if outside the range defined by iMin and iMax.
419 """
420 if iDefault is not None and sName not in self._dParams:
421 return iDefault;
422
423 sValue = self.getStringParam(sName, None, None if iDefault is None else str(iDefault));
424 try:
425 iValue = int(sValue);
426 except:
427 raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
428 % (self._sAction, sName, sValue));
429
430 if (iMin is not None and iValue < iMin) \
431 or (iMax is not None and iValue > iMax):
432 raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
433 % (self._sAction, sName, iValue, iMin, iMax));
434 return iValue;
435
436 def getLongParam(self, sName, lMin = None, lMax = None, lDefault = None):
437 """
438 Gets a long integer parameter.
439 Raises exception if not found and lDefault is None, if not a valid long,
440 or if outside the range defined by lMin and lMax.
441 """
442 if lDefault is not None and sName not in self._dParams:
443 return lDefault;
444
445 sValue = self.getStringParam(sName, None, None if lDefault is None else str(lDefault));
446 try:
447 lValue = long(sValue);
448 except:
449 raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
450 % (self._sAction, sName, sValue));
451
452 if (lMin is not None and lValue < lMin) \
453 or (lMax is not None and lValue > lMax):
454 raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
455 % (self._sAction, sName, lValue, lMin, lMax));
456 return lValue;
457
458 def getTsParam(self, sName, tsDefault = None, fRequired = True):
459 """
460 Gets a timestamp parameter.
461 Raises exception if not found and fRequired is True.
462 """
463 if fRequired is False and sName not in self._dParams:
464 return tsDefault;
465
466 sValue = self.getStringParam(sName, None, None if tsDefault is None else str(tsDefault));
467 (sValue, sError) = ModelDataBase.validateTs(sValue);
468 if sError is not None:
469 raise WuiException('%s parameter %s value "%s": %s'
470 % (self._sAction, sName, sValue, sError));
471 return sValue;
472
473 def getListOfIntParams(self, sName, iMin = None, iMax = None, aiDefaults = None):
474 """
475 Gets parameter list.
476 Raises exception if not found and aiDefaults is None, or if any of the
477 values are not valid integers or outside the range defined by iMin and iMax.
478 """
479 if sName in self._dParams:
480 if sName not in self._asCheckedParams:
481 self._asCheckedParams.append(sName);
482
483 if isinstance(self._dParams[sName], list):
484 asValues = self._dParams[sName];
485 else:
486 asValues = [self._dParams[sName],];
487 aiValues = [];
488 for sValue in asValues:
489 try:
490 iValue = int(sValue);
491 except:
492 raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
493 % (self._sAction, sName, sValue));
494
495 if (iMin is not None and iValue < iMin) \
496 or (iMax is not None and iValue > iMax):
497 raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
498 % (self._sAction, sName, iValue, iMin, iMax));
499 aiValues.append(iValue);
500 else:
501 aiValues = aiDefaults;
502
503 return aiValues;
504
505 def getListOfStrParams(self, sName, asDefaults = None):
506 """
507 Gets parameter list.
508 Raises exception if not found and asDefaults is None.
509 """
510 if sName in self._dParams:
511 if sName not in self._asCheckedParams:
512 self._asCheckedParams.append(sName);
513
514 if isinstance(self._dParams[sName], list):
515 asValues = [str(s).strip() for s in self._dParams[sName]];
516 else:
517 asValues = [str(self._dParams[sName]).strip(), ];
518 elif asDefaults is None:
519 raise WuiException('%s is missing parameters: "%s"' % (self._sAction, sName,));
520 else:
521 asValues = asDefaults;
522
523 return asValues;
524
525 def getListOfTestCasesParam(self, sName, asDefaults = None): # too many local vars - pylint: disable=R0914
526 """Get list of test cases and their parameters"""
527 if sName in self._dParams:
528 if sName not in self._asCheckedParams:
529 self._asCheckedParams.append(sName)
530
531 aoListOfTestCases = []
532
533 aiSelectedTestCaseIds = self.getListOfIntParams('%s[asCheckedTestCases]' % sName, aiDefaults=[])
534 aiAllTestCases = self.getListOfIntParams('%s[asAllTestCases]' % sName, aiDefaults=[])
535
536 for idTestCase in aiAllTestCases:
537 aiCheckedTestCaseArgs = \
538 self.getListOfIntParams(
539 '%s[%d][asCheckedTestCaseArgs]' % (sName, idTestCase),
540 aiDefaults=[])
541
542 aiAllTestCaseArgs = \
543 self.getListOfIntParams(
544 '%s[%d][asAllTestCaseArgs]' % (sName, idTestCase),
545 aiDefaults=[])
546
547 oListEntryTestCaseArgs = []
548 for idTestCaseArgs in aiAllTestCaseArgs:
549 fArgsChecked = True if idTestCaseArgs in aiCheckedTestCaseArgs else False
550
551 # Dry run
552 sPrefix = '%s[%d][%d]' % (sName, idTestCase, idTestCaseArgs,);
553 self.getIntParam(sPrefix + '[idTestCaseArgs]', iDefault = -1,)
554
555 sArgs = self.getStringParam(sPrefix + '[sArgs]', sDefault = '')
556 cSecTimeout = self.getStringParam(sPrefix + '[cSecTimeout]', sDefault = '')
557 cGangMembers = self.getStringParam(sPrefix + '[cGangMembers]', sDefault = '')
558 cGangMembers = self.getStringParam(sPrefix + '[cGangMembers]', sDefault = '')
559
560 oListEntryTestCaseArgs.append((fArgsChecked, idTestCaseArgs, sArgs, cSecTimeout, cGangMembers))
561
562 sTestCaseName = self.getStringParam('%s[%d][sName]' % (sName, idTestCase), sDefault='')
563
564 oListEntryTestCase = \
565 (idTestCase,
566 True if idTestCase in aiSelectedTestCaseIds else False,
567 sTestCaseName,
568 oListEntryTestCaseArgs)
569
570 aoListOfTestCases.append(oListEntryTestCase)
571
572 if aoListOfTestCases == []:
573 if asDefaults is None:
574 raise WuiException('%s is missing parameters: "%s"' % (self._sAction, sName))
575 aoListOfTestCases = asDefaults
576
577 return aoListOfTestCases
578
579 def getEffectiveDateParam(self, sParamName = None):
580 """
581 Gets the effective date parameter.
582
583 Returns a timestamp suitable for database and url parameters.
584 Returns None if not found or empty.
585
586 The first call with sParamName set to None will set the internal _tsNow
587 value upon successfull return.
588 """
589
590 sName = sParamName if sParamName is not None else WuiDispatcherBase.ksParamEffectiveDate
591
592 if sName not in self._dParams:
593 return None;
594
595 if sName not in self._asCheckedParams:
596 self._asCheckedParams.append(sName);
597
598 sValue = self._dParams[sName];
599 if isinstance(sValue, list):
600 raise WuiException('%s parameter "%s" is given multiple times: %s' % (self._sAction, sName, sValue));
601 sValue = sValue.strip();
602 if sValue == '':
603 return None;
604
605 #
606 # Timestamp, just validate it and return.
607 #
608 if sValue[0] not in ['-', '+']:
609 (sValue, sError) = ModelDataBase.validateTs(sValue);
610 if sError is not None:
611 raise WuiException('%s parameter "%s" ("%s") is invalid: %s' % (self._sAction, sName, sValue, sError));
612 if sParamName is None and self._tsNow is None:
613 self._tsNow = sValue;
614 return sValue;
615
616 #
617 # Relative timestamp. Validate and convert it to a fixed timestamp.
618 #
619 chSign = sValue[0];
620 (sValue, sError) = ModelDataBase.validateTs(sValue[1:]);
621 if sError is not None:
622 raise WuiException('%s parameter "%s" ("%s") is invalid: %s' % (self._sAction, sName, sValue, sError));
623 if sValue[-6] in ['-', '+']:
624 raise WuiException('%s parameter "%s" ("%s") is a relative timestamp but incorrectly includes a time zone.'
625 % (self._sAction, sName, sValue));
626 offTime = 11;
627 if sValue[offTime - 1] != ' ':
628 raise WuiException('%s parameter "%s" ("%s") incorrect format.' % (self._sAction, sName, sValue));
629 sInterval = 'P' + sValue[:(offTime - 1)] + 'T' + sValue[offTime:];
630
631 self._oDb.execute('SELECT CURRENT_TIMESTAMP ' + chSign + ' \'' + sInterval + '\'::INTERVAL');
632 oDate = self._oDb.fetchOne()[0];
633
634 sValue = str(oDate);
635 if sParamName is None and self._tsNow is None:
636 self._tsNow = sValue;
637 return sValue;
638
639 def getRedirectToParameter(self, sDefault = None):
640 """
641 Gets the special redirect to parameter if it exists, will Return default
642 if not, with None being a valid default.
643
644 Makes sure the it doesn't got offsite.
645 Raises exception if invalid.
646 """
647 if sDefault is not None or self.ksParamRedirectTo in self._dParams:
648 sValue = self.getStringParam(self.ksParamRedirectTo, sDefault = sDefault);
649 cch = sValue.find("?");
650 if cch < 0:
651 cch = sValue.find("#");
652 if cch < 0:
653 cch = len(sValue);
654 for ch in (':', '/', '\\', '..'):
655 if sValue.find(ch, 0, cch) >= 0:
656 raise WuiException('Invalid character (%c) in redirect-to url: %s' % (ch, sValue,));
657 else:
658 sValue = None;
659 return sValue;
660
661
662 def _checkForUnknownParameters(self):
663 """
664 Check if we've handled all parameters, raises exception if anything
665 unknown was found.
666 """
667
668 if len(self._asCheckedParams) != len(self._dParams):
669 sUnknownParams = '';
670 for sKey in self._dParams:
671 if sKey not in self._asCheckedParams:
672 sUnknownParams += ' ' + sKey + '=' + str(self._dParams[sKey]);
673 raise WuiException('Unknown parameters: ' + sUnknownParams);
674
675 return True;
676
677 def _assertPostRequest(self):
678 """
679 Makes sure that the request we're dispatching is a POST request.
680 Raises an exception of not.
681 """
682 if self._oSrvGlue.getMethod() != 'POST':
683 raise WuiException('Expected "POST" request, got "%s"' % (self._oSrvGlue.getMethod(),))
684 return True;
685
686 #
687 # Client browser type.
688 #
689
690 ## @name Browser types.
691 ## @{
692 ksBrowserFamily_Unknown = 0;
693 ksBrowserFamily_Gecko = 1;
694 ksBrowserFamily_Webkit = 2;
695 ksBrowserFamily_Trident = 3;
696 ## @}
697
698 ## @name Browser types.
699 ## @{
700 ksBrowserType_FamilyMask = 0xff;
701 ksBrowserType_Unknown = 0;
702 ksBrowserType_Firefox = (1 << 8) | ksBrowserFamily_Gecko;
703 ksBrowserType_Chrome = (2 << 8) | ksBrowserFamily_Webkit;
704 ksBrowserType_Safari = (3 << 8) | ksBrowserFamily_Webkit;
705 ksBrowserType_IE = (4 << 8) | ksBrowserFamily_Trident;
706 ## @}
707
708 def getBrowserType(self):
709 """
710 Gets the browser type.
711 The browser family can be extracted from this using ksBrowserType_FamilyMask.
712 """
713 sAgent = self._oSrvGlue.getUserAgent();
714 if sAgent.find('AppleWebKit/') > 0:
715 if sAgent.find('Chrome/') > 0:
716 return self.ksBrowserType_Chrome;
717 if sAgent.find('Safari/') > 0:
718 return self.ksBrowserType_Safari;
719 return self.ksBrowserType_Unknown | self.ksBrowserFamily_Webkit;
720 if sAgent.find('Gecko/') > 0:
721 if sAgent.find('Firefox/') > 0:
722 return self.ksBrowserType_Firefox;
723 return self.ksBrowserType_Unknown | self.ksBrowserFamily_Gecko;
724 return self.ksBrowserType_Unknown | self.ksBrowserFamily_Unknown;
725
726 def isBrowserGecko(self, sMinVersion = None):
727 """ Returns true if it's a gecko based browser. """
728 if (self.getBrowserType() & self.ksBrowserType_FamilyMask) != self.ksBrowserFamily_Gecko:
729 return False;
730 if sMinVersion is not None:
731 sAgent = self._oSrvGlue.getUserAgent();
732 sVersion = sAgent[sAgent.find('Gecko/')+6:].split()[0];
733 if sVersion < sMinVersion:
734 return False;
735 return True;
736
737 #
738 # User related stuff.
739 #
740
741 def isReadOnlyUser(self):
742 """ Returns true if the logged in user is read-only or if no user is logged in. """
743 return self._oCurUser is None or self._oCurUser.fReadOnly;
744
745
746 #
747 # Debugging
748 #
749
750 def _debugProcessDispatch(self):
751 """
752 Processes any debugging parameters in the request and adds them to
753 _asCheckedParams so they won't cause trouble in the action handler.
754 """
755
756 self._fDbgSqlTrace = self.getBoolParam(self.ksParamDbgSqlTrace, False);
757 self._fDbgSqlExplain = self.getBoolParam(self.ksParamDbgSqlExplain, False);
758
759 if self._fDbgSqlExplain:
760 self._oDb.debugEnableExplain();
761
762 return True;
763
764 def _debugRenderPanel(self):
765 """
766 Renders a simple form for controlling WUI debugging.
767
768 Returns the HTML for it.
769 """
770
771 sHtml = '<div id="debug-panel">\n' \
772 ' <form id="debug-panel-form" type="get" action="#">\n';
773
774 for sKey, oValue in self._dParams.iteritems():
775 if sKey not in self.kasDbgParams:
776 if hasattr(oValue, 'startswith'):
777 sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \
778 % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oValue),);
779 else:
780 for oSubValue in oValue:
781 sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \
782 % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oSubValue),);
783
784 for aoCheckBox in (
785 [self.ksParamDbgSqlTrace, self._fDbgSqlTrace, 'SQL trace'],
786 [self.ksParamDbgSqlExplain, self._fDbgSqlExplain, 'SQL explain'], ):
787 sHtml += ' <input type="checkbox" name="%s" value="1"%s />%s\n' \
788 % (aoCheckBox[0], ' checked' if aoCheckBox[1] else '', aoCheckBox[2]);
789
790 sHtml += ' <button type="submit">Apply</button>\n';
791 sHtml += ' </form>\n' \
792 '</div>\n';
793 return sHtml;
794
795
796 def _debugGetParameters(self):
797 """
798 Gets a dictionary with the debug parameters.
799
800 For use when links are constructed from scratch instead of self._dParams.
801 """
802 return self._dDbgParams;
803
804 #
805 # Dispatching
806 #
807
808 def _actionDefault(self):
809 """The default action handler, always overridden. """
810 raise WuiException('The child class shall override WuiBase.actionDefault().')
811
812 def _actionGenericListing(self, oLogicType, oListContentType):
813 """
814 Generic listing action.
815
816 oLogicType implements fetchForListing.
817 oListContentType is a child of WuiListContentBase.
818 """
819 tsEffective = self.getEffectiveDateParam();
820 cItemsPerPage = self.getIntParam(self.ksParamItemsPerPage, iMin = 2, iMax = 9999, iDefault = 300);
821 iPage = self.getIntParam(self.ksParamPageNo, iMin = 0, iMax = 999999, iDefault = 0);
822 aiSortColumnsDup = self.getListOfIntParams(self.ksParamSortColumns,
823 iMin = -getattr(oLogicType, 'kcMaxSortColumns', 0) + 1,
824 iMax = getattr(oLogicType, 'kcMaxSortColumns', 0), aiDefaults = []);
825 aiSortColumns = [];
826 for iSortColumn in aiSortColumnsDup:
827 if iSortColumn not in aiSortColumns:
828 aiSortColumns.append(iSortColumn);
829 self._checkForUnknownParameters();
830
831 aoEntries = oLogicType(self._oDb).fetchForListing(iPage * cItemsPerPage, cItemsPerPage + 1, tsEffective, aiSortColumns);
832 oContent = oListContentType(aoEntries, iPage, cItemsPerPage, tsEffective,
833 fnDPrint = self._oSrvGlue.dprint, oDisp = self, aiSelectedSortColumns = aiSortColumns);
834 (self._sPageTitle, self._sPageBody) = oContent.show();
835 return True;
836
837 def _actionGenericFormAdd(self, oDataType, oFormType, sRedirectTo = None):
838 """
839 Generic add something form display request handler.
840
841 oDataType is a ModelDataBase child class.
842 oFormType is a WuiFormContentBase child class.
843 """
844 assert issubclass(oDataType, ModelDataBase);
845 from testmanager.webui.wuicontentbase import WuiFormContentBase;
846 assert issubclass(oFormType, WuiFormContentBase);
847
848 oData = oDataType().initFromParams(oDisp = self, fStrict = False);
849 sRedirectTo = self.getRedirectToParameter(sRedirectTo);
850 self._checkForUnknownParameters();
851
852 oForm = oFormType(oData, oFormType.ksMode_Add, oDisp = self);
853 oForm.setRedirectTo(sRedirectTo);
854 (self._sPageTitle, self._sPageBody) = oForm.showForm();
855 return True
856
857 def _actionGenericFormDetails(self, oDataType, oLogicType, oFormType, sIdAttr = None, sGenIdAttr = None): # pylint: disable=R0914
858 """
859 Generic handler for showing a details form/page.
860
861 oDataType is a ModelDataBase child class.
862 oLogicType may implement fetchForChangeLog.
863 oFormType is a WuiFormContentBase child class.
864 sIdParamName is the name of the ID parameter (not idGen!).
865 """
866 # Input.
867 assert issubclass(oDataType, ModelDataBase);
868 assert issubclass(oLogicType, ModelLogicBase);
869 from testmanager.webui.wuicontentbase import WuiFormContentBase;
870 assert issubclass(oFormType, WuiFormContentBase);
871
872 if sIdAttr is None:
873 sIdAttr = oDataType.ksIdAttr;
874 if sGenIdAttr is None:
875 sGenIdAttr = getattr(oDataType, 'ksGenIdAttr', None);
876
877 # Parameters.
878 idGenObject = -1;
879 if sGenIdAttr is not None:
880 idGenObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sGenIdAttr), 0, 0x7ffffffe, -1);
881 if idGenObject != -1:
882 idObject = tsNow = None;
883 else:
884 idObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sIdAttr), 0, 0x7ffffffe, -1);
885 tsNow = self.getEffectiveDateParam();
886 fChangeLog = self.getBoolParam(WuiDispatcherBase.ksParamChangeLogEnabled, True);
887 iChangeLogPageNo = self.getIntParam(WuiDispatcherBase.ksParamChangeLogPageNo, 0, 9999, 0);
888 cChangeLogEntriesPerPage = self.getIntParam(WuiDispatcherBase.ksParamChangeLogEntriesPerPage, 2, 9999, 4);
889 self._checkForUnknownParameters();
890
891 # Fetch item and display it.
892 if idGenObject == -1:
893 oData = oDataType().initFromDbWithId(self._oDb, idObject, tsNow);
894 else:
895 oData = oDataType().initFromDbWithGenId(self._oDb, idGenObject);
896
897 oContent = oFormType(oData, oFormType.ksMode_Show, oDisp = self);
898 (self._sPageTitle, self._sPageBody) = oContent.showForm();
899
900 # Add change log if supported.
901 if fChangeLog and hasattr(oLogicType, 'fetchForChangeLog'):
902 (aoEntries, fMore) = oLogicType(self._oDb).fetchForChangeLog(getattr(oData, sIdAttr),
903 iChangeLogPageNo * cChangeLogEntriesPerPage,
904 cChangeLogEntriesPerPage ,
905 tsNow);
906 self._sPageBody += oContent.showChangeLog(aoEntries, fMore, iChangeLogPageNo, cChangeLogEntriesPerPage, tsNow);
907 return True
908
909 def _actionGenericDoRemove(self, oLogicType, sParamId, sRedirAction):
910 """
911 Delete entry (using oLogicType.removeEntry).
912
913 oLogicType is a class that implements addEntry.
914
915 sParamId is the name (ksParam_...) of the HTTP variable hold the ID of
916 the database entry to delete.
917
918 sRedirAction is what action to redirect to on success.
919 """
920 import cgitb;
921
922 idEntry = self.getIntParam(sParamId, iMin = 1, iMax = 0x7ffffffe)
923 fCascade = self.getBoolParam('fCascadeDelete', False);
924 sRedirectTo = self.getRedirectToParameter(self._sActionUrlBase + sRedirAction);
925 self._checkForUnknownParameters()
926
927 try:
928 if self.isReadOnlyUser():
929 raise Exception('"%s" is a read only user!' % (self._oCurUser.sUsername,));
930 self._sPageTitle = None
931 self._sPageBody = None
932 self._sRedirectTo = sRedirectTo;
933 return oLogicType(self._oDb).removeEntry(self._oCurUser.uid, idEntry, fCascade = fCascade, fCommit = True);
934 except Exception as oXcpt:
935 self._oDb.rollback();
936 self._sPageTitle = 'Unable to delete entry';
937 self._sPageBody = str(oXcpt);
938 if config.g_kfDebugDbXcpt:
939 self._sPageBody += cgitb.html(sys.exc_info());
940 self._sRedirectTo = None;
941 return False;
942
943 def _actionGenericFormEdit(self, oDataType, oFormType, sIdParamName = None, sRedirectTo = None):
944 """
945 Generic edit something form display request handler.
946
947 oDataType is a ModelDataBase child class.
948 oFormType is a WuiFormContentBase child class.
949 sIdParamName is the name of the ID parameter (not idGen!).
950 """
951 assert issubclass(oDataType, ModelDataBase);
952 from testmanager.webui.wuicontentbase import WuiFormContentBase;
953 assert issubclass(oFormType, WuiFormContentBase);
954
955 if sIdParamName is None:
956 sIdParamName = getattr(oDataType, 'ksParam_' + oDataType.ksIdAttr);
957 assert len(sIdParamName) > 1;
958
959 tsNow = self.getEffectiveDateParam();
960 idObject = self.getIntParam(sIdParamName, 0, 0x7ffffffe);
961 sRedirectTo = self.getRedirectToParameter(sRedirectTo);
962 self._checkForUnknownParameters();
963 oData = oDataType().initFromDbWithId(self._oDb, idObject, tsNow = tsNow);
964
965 oContent = oFormType(oData, oFormType.ksMode_Edit, oDisp = self);
966 oContent.setRedirectTo(sRedirectTo);
967 (self._sPageTitle, self._sPageBody) = oContent.showForm();
968 return True
969
970 def _actionGenericFormEditL(self, oCoreObjectLogic, sCoreObjectIdFieldName, oWuiObjectLogic):
971 """
972 Generic modify something form display request handler.
973
974 @param oCoreObjectLogic A *Logic class
975
976 @param sCoreObjectIdFieldName Name of HTTP POST variable that
977 contains object ID information
978
979 @param oWuiObjectLogic Web interface renderer class
980 """
981
982 iCoreDataObjectId = self.getIntParam(sCoreObjectIdFieldName, 0, 0x7ffffffe, -1)
983 self._checkForUnknownParameters();
984
985 ## @todo r=bird: This will return a None object if the object wasn't found... Crash bang in the content generator
986 # code (that's not logic code btw.).
987 oData = oCoreObjectLogic(self._oDb).getById(iCoreDataObjectId)
988
989 # Instantiate and render the MODIFY dialog form
990 oContent = oWuiObjectLogic(oData, oWuiObjectLogic.ksMode_Edit, oDisp=self)
991
992 (self._sPageTitle, self._sPageBody) = oContent.showForm()
993
994 return True
995
996 def _actionGenericFormClone(self, oDataType, oFormType, sIdAttr, sGenIdAttr = None):
997 """
998 Generic clone something form display request handler.
999
1000 oDataType is a ModelDataBase child class.
1001 oFormType is a WuiFormContentBase child class.
1002 sIdParamName is the name of the ID parameter.
1003 sGenIdParamName is the name of the generation ID parameter, None if not applicable.
1004 """
1005 # Input.
1006 assert issubclass(oDataType, ModelDataBase);
1007 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1008 assert issubclass(oFormType, WuiFormContentBase);
1009
1010 # Parameters.
1011 idGenObject = -1;
1012 if sGenIdAttr is not None:
1013 idGenObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sGenIdAttr), 0, 0x7ffffffe, -1);
1014 if idGenObject != -1:
1015 idObject = tsNow = None;
1016 else:
1017 idObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sIdAttr), 0, 0x7ffffffe, -1);
1018 tsNow = self.getEffectiveDateParam();
1019 self._checkForUnknownParameters();
1020
1021 # Fetch data and clear identifying attributes not relevant to the clone.
1022 if idGenObject != -1:
1023 oData = oDataType().initFromDbWithGenId(self._oDb, idGenObject);
1024 else:
1025 oData = oDataType().initFromDbWithId(self._oDb, idObject, tsNow);
1026
1027 setattr(oData, sIdAttr, None);
1028 if sGenIdAttr is not None:
1029 setattr(oData, sGenIdAttr, None);
1030 oData.tsEffective = None;
1031 oData.tsExpire = None;
1032
1033 # Display form.
1034 oContent = oFormType(oData, oFormType.ksMode_Add, oDisp = self);
1035 (self._sPageTitle, self._sPageBody) = oContent.showForm()
1036 return True
1037
1038
1039 def _actionGenericFormPost(self, sMode, fnLogicAction, oDataType, oFormType, sRedirectTo, fStrict = True):
1040 """
1041 Generic POST request handling from a WuiFormContentBase child.
1042
1043 oDataType is a ModelDataBase child class.
1044 oFormType is a WuiFormContentBase child class.
1045 fnLogicAction is a method taking a oDataType instance and uidAuthor as arguments.
1046 """
1047 assert issubclass(oDataType, ModelDataBase);
1048 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1049 assert issubclass(oFormType, WuiFormContentBase);
1050
1051 #
1052 # Read and validate parameters.
1053 #
1054 oData = oDataType().initFromParams(oDisp = self, fStrict = fStrict);
1055 sRedirectTo = self.getRedirectToParameter(sRedirectTo);
1056 self._checkForUnknownParameters();
1057 self._assertPostRequest();
1058 if sMode == WuiFormContentBase.ksMode_Add and getattr(oData, 'kfIdAttrIsForForeign', False):
1059 enmValidateFor = oData.ksValidateFor_AddForeignId;
1060 elif sMode == WuiFormContentBase.ksMode_Add:
1061 enmValidateFor = oData.ksValidateFor_Add;
1062 else:
1063 enmValidateFor = oData.ksValidateFor_Edit;
1064 dErrors = oData.validateAndConvert(self._oDb, enmValidateFor);
1065
1066 # Check that the user can do this.
1067 sErrorMsg = None;
1068 assert self._oCurUser is not None;
1069 if self.isReadOnlyUser():
1070 sErrorMsg = 'User %s is not allowed to modify anything!' % (self._oCurUser.sUsername,)
1071
1072 if not dErrors and not sErrorMsg:
1073 oData.convertFromParamNull();
1074
1075 #
1076 # Try do the job.
1077 #
1078 try:
1079 fnLogicAction(oData, self._oCurUser.uid, fCommit = True);
1080 except Exception as oXcpt:
1081 self._oDb.rollback();
1082 oForm = oFormType(oData, sMode, oDisp = self);
1083 oForm.setRedirectTo(sRedirectTo);
1084 sErrorMsg = str(oXcpt) if not config.g_kfDebugDbXcpt else '\n'.join(utils.getXcptInfo(4));
1085 (self._sPageTitle, self._sPageBody) = oForm.showForm(sErrorMsg = sErrorMsg);
1086 else:
1087 #
1088 # Worked, redirect to the specified page.
1089 #
1090 self._sPageTitle = None;
1091 self._sPageBody = None;
1092 self._sRedirectTo = sRedirectTo;
1093 else:
1094 oForm = oFormType(oData, sMode, oDisp = self);
1095 oForm.setRedirectTo(sRedirectTo);
1096 (self._sPageTitle, self._sPageBody) = oForm.showForm(dErrors = dErrors, sErrorMsg = sErrorMsg);
1097 return True;
1098
1099 def _actionGenericFormAddPost(self, oDataType, oLogicType, oFormType, sRedirAction, fStrict=True):
1100 """
1101 Generic add entry POST request handling from a WuiFormContentBase child.
1102
1103 oDataType is a ModelDataBase child class.
1104 oLogicType is a class that implements addEntry.
1105 oFormType is a WuiFormContentBase child class.
1106 sRedirAction is what action to redirect to on success.
1107 """
1108 assert issubclass(oDataType, ModelDataBase);
1109 assert issubclass(oLogicType, ModelLogicBase);
1110 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1111 assert issubclass(oFormType, WuiFormContentBase);
1112
1113 oLogic = oLogicType(self._oDb);
1114 return self._actionGenericFormPost(WuiFormContentBase.ksMode_Add, oLogic.addEntry, oDataType, oFormType,
1115 '?' + webutils.encodeUrlParams({self.ksParamAction: sRedirAction}), fStrict=fStrict)
1116
1117 def _actionGenericFormEditPost(self, oDataType, oLogicType, oFormType, sRedirAction, fStrict = True):
1118 """
1119 Generic edit POST request handling from a WuiFormContentBase child.
1120
1121 oDataType is a ModelDataBase child class.
1122 oLogicType is a class that implements addEntry.
1123 oFormType is a WuiFormContentBase child class.
1124 sRedirAction is what action to redirect to on success.
1125 """
1126 assert issubclass(oDataType, ModelDataBase);
1127 assert issubclass(oLogicType, ModelLogicBase);
1128 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1129 assert issubclass(oFormType, WuiFormContentBase);
1130
1131 oLogic = oLogicType(self._oDb);
1132 return self._actionGenericFormPost(WuiFormContentBase.ksMode_Edit, oLogic.editEntry, oDataType, oFormType,
1133 '?' + webutils.encodeUrlParams({self.ksParamAction: sRedirAction}),
1134 fStrict = fStrict);
1135
1136 def _unauthorizedUser(self):
1137 """
1138 Displays the unauthorized user message (corresponding record is not
1139 present in DB).
1140 """
1141
1142 sLoginName = self._oSrvGlue.getLoginName();
1143
1144 # Report to system log
1145 oSystemLogLogic = SystemLogLogic(self._oDb);
1146 oSystemLogLogic.addEntry(SystemLogData.ksEvent_UserAccountUnknown,
1147 'Unknown user (%s) attempts to access from %s'
1148 % (sLoginName, self._oSrvGlue.getClientAddr()),
1149 24, fCommit = True)
1150
1151 # Display message.
1152 self._sPageTitle = 'User not authorized'
1153 self._sPageBody = """
1154 <p>Access denied for user <b>%s</b>.
1155 Please contact an admin user to set up your access.</p>
1156 """ % (sLoginName,)
1157 return True;
1158
1159 def dispatchRequest(self):
1160 """
1161 Dispatches a request.
1162 """
1163
1164 #
1165 # Get the parameters and checks for duplicates.
1166 #
1167 try:
1168 dParams = self._oSrvGlue.getParameters();
1169 except Exception as oXcpt:
1170 raise WuiException('Error retriving parameters: %s' % (oXcpt,));
1171
1172 for sKey in dParams.keys():
1173
1174 # Take care about strings which may contain unicode characters: convert percent-encoded symbols back to unicode.
1175 for idxItem, _ in enumerate(dParams[sKey]):
1176 dParams[sKey][idxItem] = dParams[sKey][idxItem].decode('utf-8')
1177
1178 if not len(dParams[sKey]) > 1:
1179 dParams[sKey] = dParams[sKey][0];
1180 self._dParams = dParams;
1181
1182 #
1183 # Figure out the requested action and validate it.
1184 #
1185 if self.ksParamAction in self._dParams:
1186 self._sAction = self._dParams[self.ksParamAction];
1187 self._asCheckedParams.append(self.ksParamAction);
1188 else:
1189 self._sAction = self.ksActionDefault;
1190
1191 if isinstance(self._sAction, list) or self._sAction not in self._dDispatch:
1192 raise WuiException('Unknown action "%s" requested' % (self._sAction,));
1193
1194 #
1195 # Call action handler and generate the page (if necessary).
1196 #
1197 if self._oCurUser is not None:
1198 self._debugProcessDispatch();
1199 if self._dDispatch[self._sAction]() is self.ksDispatchRcAllDone:
1200 return True;
1201 else:
1202 self._unauthorizedUser();
1203
1204 if self._sRedirectTo is None:
1205 self._generatePage();
1206 else:
1207 self._redirectPage();
1208 return True;
1209
1210
1211 def dprint(self, sText):
1212 """ Debug printing. """
1213 if config.g_kfWebUiDebug and True:
1214 self._oSrvGlue.dprint(sText);
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette