VirtualBox

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

Last change on this file since 83395 was 83395, checked in by vboxsync, 5 years ago

TestManager/wuibase.py: Fixed attribute typo in debug-panel.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.0 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuibase.py 83395 2020-03-24 18:55:11Z vboxsync $
3
4"""
5Test Manager Web-UI - Base Classes.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2020 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: 83395 $"
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; # pylint: disable=unnecessary-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().items():
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 + (utils.toUnicode(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 getUrlNoParams(self):
359 """
360 Returns the base URL without any parameters (no trailing '?' or &).
361 """
362 return self._sUrlBase[:self._sUrlBase.rindex('?')];
363
364 def getUrlBase(self):
365 """
366 Returns the base URL, ending with '?' or '&'.
367 This may already include some debug parameters.
368 """
369 return self._sUrlBase;
370
371 def getParameters(self):
372 """
373 Returns a (shallow) copy of the request parameter dictionary.
374 """
375 return self._dParams.copy();
376
377 def getDb(self):
378 """
379 Returns the database connection.
380 """
381 return self._oDb;
382
383 def getNow(self):
384 """
385 Returns the effective date.
386 """
387 return self._tsNow;
388
389
390 #
391 # Parameter handling.
392 #
393
394 def getStringParam(self, sName, asValidValues = None, sDefault = None, fAllowNull = False):
395 """
396 Gets a string parameter.
397 Raises exception if not found and sDefault is None.
398 """
399 if sName in self._dParams:
400 if sName not in self._asCheckedParams:
401 self._asCheckedParams.append(sName);
402 sValue = self._dParams[sName];
403 if isinstance(sValue, list):
404 raise WuiException('%s parameter "%s" is given multiple times: "%s"' % (self._sAction, sName, sValue));
405 sValue = sValue.strip();
406 elif sDefault is None and fAllowNull is not True:
407 raise WuiException('%s is missing parameters: "%s"' % (self._sAction, sName,));
408 else:
409 sValue = sDefault;
410
411 if asValidValues is not None and sValue not in asValidValues:
412 raise WuiException('%s parameter %s value "%s" not in %s '
413 % (self._sAction, sName, sValue, asValidValues));
414 return sValue;
415
416 def getBoolParam(self, sName, fDefault = None):
417 """
418 Gets a boolean parameter.
419 Raises exception if not found and fDefault is None, or if not a valid boolean.
420 """
421 sValue = self.getStringParam(sName, [ 'True', 'true', '1', 'False', 'false', '0'],
422 '0' if fDefault is None else str(fDefault));
423 # HACK: Checkboxes doesn't return a value when unchecked, so we always
424 # provide a default when dealing with boolean parameters.
425 return sValue in ('True', 'true', '1',);
426
427 def getIntParam(self, sName, iMin = None, iMax = None, iDefault = None):
428 """
429 Gets a integer parameter.
430 Raises exception if not found and iDefault is None, if not a valid int,
431 or if outside the range defined by iMin and iMax.
432 """
433 if iDefault is not None and sName not in self._dParams:
434 return iDefault;
435
436 sValue = self.getStringParam(sName, None, None if iDefault is None else str(iDefault));
437 try:
438 iValue = int(sValue);
439 except:
440 raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
441 % (self._sAction, sName, sValue));
442
443 if (iMin is not None and iValue < iMin) \
444 or (iMax is not None and iValue > iMax):
445 raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
446 % (self._sAction, sName, iValue, iMin, iMax));
447 return iValue;
448
449 def getLongParam(self, sName, lMin = None, lMax = None, lDefault = None):
450 """
451 Gets a long integer parameter.
452 Raises exception if not found and lDefault is None, if not a valid long,
453 or if outside the range defined by lMin and lMax.
454 """
455 if lDefault is not None and sName not in self._dParams:
456 return lDefault;
457
458 sValue = self.getStringParam(sName, None, None if lDefault is None else str(lDefault));
459 try:
460 lValue = long(sValue);
461 except:
462 raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
463 % (self._sAction, sName, sValue));
464
465 if (lMin is not None and lValue < lMin) \
466 or (lMax is not None and lValue > lMax):
467 raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
468 % (self._sAction, sName, lValue, lMin, lMax));
469 return lValue;
470
471 def getTsParam(self, sName, tsDefault = None, fRequired = True):
472 """
473 Gets a timestamp parameter.
474 Raises exception if not found and fRequired is True.
475 """
476 if fRequired is False and sName not in self._dParams:
477 return tsDefault;
478
479 sValue = self.getStringParam(sName, None, None if tsDefault is None else str(tsDefault));
480 (sValue, sError) = ModelDataBase.validateTs(sValue);
481 if sError is not None:
482 raise WuiException('%s parameter %s value "%s": %s'
483 % (self._sAction, sName, sValue, sError));
484 return sValue;
485
486 def getListOfIntParams(self, sName, iMin = None, iMax = None, aiDefaults = None):
487 """
488 Gets parameter list.
489 Raises exception if not found and aiDefaults is None, or if any of the
490 values are not valid integers or outside the range defined by iMin and iMax.
491 """
492 if sName in self._dParams:
493 if sName not in self._asCheckedParams:
494 self._asCheckedParams.append(sName);
495
496 if isinstance(self._dParams[sName], list):
497 asValues = self._dParams[sName];
498 else:
499 asValues = [self._dParams[sName],];
500 aiValues = [];
501 for sValue in asValues:
502 try:
503 iValue = int(sValue);
504 except:
505 raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
506 % (self._sAction, sName, sValue));
507
508 if (iMin is not None and iValue < iMin) \
509 or (iMax is not None and iValue > iMax):
510 raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
511 % (self._sAction, sName, iValue, iMin, iMax));
512 aiValues.append(iValue);
513 else:
514 aiValues = aiDefaults;
515
516 return aiValues;
517
518 def getListOfStrParams(self, sName, asDefaults = None):
519 """
520 Gets parameter list.
521 Raises exception if not found and asDefaults is None.
522 """
523 if sName in self._dParams:
524 if sName not in self._asCheckedParams:
525 self._asCheckedParams.append(sName);
526
527 if isinstance(self._dParams[sName], list):
528 asValues = [str(s).strip() for s in self._dParams[sName]];
529 else:
530 asValues = [str(self._dParams[sName]).strip(), ];
531 elif asDefaults is None:
532 raise WuiException('%s is missing parameters: "%s"' % (self._sAction, sName,));
533 else:
534 asValues = asDefaults;
535
536 return asValues;
537
538 def getListOfTestCasesParam(self, sName, asDefaults = None): # too many local vars - pylint: disable=too-many-locals
539 """Get list of test cases and their parameters"""
540 if sName in self._dParams:
541 if sName not in self._asCheckedParams:
542 self._asCheckedParams.append(sName)
543
544 aoListOfTestCases = []
545
546 aiSelectedTestCaseIds = self.getListOfIntParams('%s[asCheckedTestCases]' % sName, aiDefaults=[])
547 aiAllTestCases = self.getListOfIntParams('%s[asAllTestCases]' % sName, aiDefaults=[])
548
549 for idTestCase in aiAllTestCases:
550 aiCheckedTestCaseArgs = \
551 self.getListOfIntParams(
552 '%s[%d][asCheckedTestCaseArgs]' % (sName, idTestCase),
553 aiDefaults=[])
554
555 aiAllTestCaseArgs = \
556 self.getListOfIntParams(
557 '%s[%d][asAllTestCaseArgs]' % (sName, idTestCase),
558 aiDefaults=[])
559
560 oListEntryTestCaseArgs = []
561 for idTestCaseArgs in aiAllTestCaseArgs:
562 fArgsChecked = idTestCaseArgs in aiCheckedTestCaseArgs;
563
564 # Dry run
565 sPrefix = '%s[%d][%d]' % (sName, idTestCase, idTestCaseArgs,);
566 self.getIntParam(sPrefix + '[idTestCaseArgs]', iDefault = -1,)
567
568 sArgs = self.getStringParam(sPrefix + '[sArgs]', sDefault = '')
569 cSecTimeout = self.getStringParam(sPrefix + '[cSecTimeout]', sDefault = '')
570 cGangMembers = self.getStringParam(sPrefix + '[cGangMembers]', sDefault = '')
571 cGangMembers = self.getStringParam(sPrefix + '[cGangMembers]', sDefault = '')
572
573 oListEntryTestCaseArgs.append((fArgsChecked, idTestCaseArgs, sArgs, cSecTimeout, cGangMembers))
574
575 sTestCaseName = self.getStringParam('%s[%d][sName]' % (sName, idTestCase), sDefault='')
576
577 oListEntryTestCase = (
578 idTestCase,
579 idTestCase in aiSelectedTestCaseIds,
580 sTestCaseName,
581 oListEntryTestCaseArgs
582 );
583
584 aoListOfTestCases.append(oListEntryTestCase)
585
586 if aoListOfTestCases == []:
587 if asDefaults is None:
588 raise WuiException('%s is missing parameters: "%s"' % (self._sAction, sName))
589 aoListOfTestCases = asDefaults
590
591 return aoListOfTestCases
592
593 def getEffectiveDateParam(self, sParamName = None):
594 """
595 Gets the effective date parameter.
596
597 Returns a timestamp suitable for database and url parameters.
598 Returns None if not found or empty.
599
600 The first call with sParamName set to None will set the internal _tsNow
601 value upon successfull return.
602 """
603
604 sName = sParamName if sParamName is not None else WuiDispatcherBase.ksParamEffectiveDate
605
606 if sName not in self._dParams:
607 return None;
608
609 if sName not in self._asCheckedParams:
610 self._asCheckedParams.append(sName);
611
612 sValue = self._dParams[sName];
613 if isinstance(sValue, list):
614 raise WuiException('%s parameter "%s" is given multiple times: %s' % (self._sAction, sName, sValue));
615 sValue = sValue.strip();
616 if sValue == '':
617 return None;
618
619 #
620 # Timestamp, just validate it and return.
621 #
622 if sValue[0] not in ['-', '+']:
623 (sValue, sError) = ModelDataBase.validateTs(sValue);
624 if sError is not None:
625 raise WuiException('%s parameter "%s" ("%s") is invalid: %s' % (self._sAction, sName, sValue, sError));
626 if sParamName is None and self._tsNow is None:
627 self._tsNow = sValue;
628 return sValue;
629
630 #
631 # Relative timestamp. Validate and convert it to a fixed timestamp.
632 #
633 chSign = sValue[0];
634 (sValue, sError) = ModelDataBase.validateTs(sValue[1:]);
635 if sError is not None:
636 raise WuiException('%s parameter "%s" ("%s") is invalid: %s' % (self._sAction, sName, sValue, sError));
637 if sValue[-6] in ['-', '+']:
638 raise WuiException('%s parameter "%s" ("%s") is a relative timestamp but incorrectly includes a time zone.'
639 % (self._sAction, sName, sValue));
640 offTime = 11;
641 if sValue[offTime - 1] != ' ':
642 raise WuiException('%s parameter "%s" ("%s") incorrect format.' % (self._sAction, sName, sValue));
643 sInterval = 'P' + sValue[:(offTime - 1)] + 'T' + sValue[offTime:];
644
645 self._oDb.execute('SELECT CURRENT_TIMESTAMP ' + chSign + ' \'' + sInterval + '\'::INTERVAL');
646 oDate = self._oDb.fetchOne()[0];
647
648 sValue = str(oDate);
649 if sParamName is None and self._tsNow is None:
650 self._tsNow = sValue;
651 return sValue;
652
653 def getRedirectToParameter(self, sDefault = None):
654 """
655 Gets the special redirect to parameter if it exists, will Return default
656 if not, with None being a valid default.
657
658 Makes sure the it doesn't got offsite.
659 Raises exception if invalid.
660 """
661 if sDefault is not None or self.ksParamRedirectTo in self._dParams:
662 sValue = self.getStringParam(self.ksParamRedirectTo, sDefault = sDefault);
663 cch = sValue.find("?");
664 if cch < 0:
665 cch = sValue.find("#");
666 if cch < 0:
667 cch = len(sValue);
668 for ch in (':', '/', '\\', '..'):
669 if sValue.find(ch, 0, cch) >= 0:
670 raise WuiException('Invalid character (%c) in redirect-to url: %s' % (ch, sValue,));
671 else:
672 sValue = None;
673 return sValue;
674
675
676 def _checkForUnknownParameters(self):
677 """
678 Check if we've handled all parameters, raises exception if anything
679 unknown was found.
680 """
681
682 if len(self._asCheckedParams) != len(self._dParams):
683 sUnknownParams = '';
684 for sKey in self._dParams:
685 if sKey not in self._asCheckedParams:
686 sUnknownParams += ' ' + sKey + '=' + str(self._dParams[sKey]);
687 raise WuiException('Unknown parameters: ' + sUnknownParams);
688
689 return True;
690
691 def _assertPostRequest(self):
692 """
693 Makes sure that the request we're dispatching is a POST request.
694 Raises an exception of not.
695 """
696 if self._oSrvGlue.getMethod() != 'POST':
697 raise WuiException('Expected "POST" request, got "%s"' % (self._oSrvGlue.getMethod(),))
698 return True;
699
700 #
701 # Client browser type.
702 #
703
704 ## @name Browser types.
705 ## @{
706 ksBrowserFamily_Unknown = 0;
707 ksBrowserFamily_Gecko = 1;
708 ksBrowserFamily_Webkit = 2;
709 ksBrowserFamily_Trident = 3;
710 ## @}
711
712 ## @name Browser types.
713 ## @{
714 ksBrowserType_FamilyMask = 0xff;
715 ksBrowserType_Unknown = 0;
716 ksBrowserType_Firefox = (1 << 8) | ksBrowserFamily_Gecko;
717 ksBrowserType_Chrome = (2 << 8) | ksBrowserFamily_Webkit;
718 ksBrowserType_Safari = (3 << 8) | ksBrowserFamily_Webkit;
719 ksBrowserType_IE = (4 << 8) | ksBrowserFamily_Trident;
720 ## @}
721
722 def getBrowserType(self):
723 """
724 Gets the browser type.
725 The browser family can be extracted from this using ksBrowserType_FamilyMask.
726 """
727 sAgent = self._oSrvGlue.getUserAgent();
728 if sAgent.find('AppleWebKit/') > 0:
729 if sAgent.find('Chrome/') > 0:
730 return self.ksBrowserType_Chrome;
731 if sAgent.find('Safari/') > 0:
732 return self.ksBrowserType_Safari;
733 return self.ksBrowserType_Unknown | self.ksBrowserFamily_Webkit;
734 if sAgent.find('Gecko/') > 0:
735 if sAgent.find('Firefox/') > 0:
736 return self.ksBrowserType_Firefox;
737 return self.ksBrowserType_Unknown | self.ksBrowserFamily_Gecko;
738 return self.ksBrowserType_Unknown | self.ksBrowserFamily_Unknown;
739
740 def isBrowserGecko(self, sMinVersion = None):
741 """ Returns true if it's a gecko based browser. """
742 if (self.getBrowserType() & self.ksBrowserType_FamilyMask) != self.ksBrowserFamily_Gecko:
743 return False;
744 if sMinVersion is not None:
745 sAgent = self._oSrvGlue.getUserAgent();
746 sVersion = sAgent[sAgent.find('Gecko/')+6:].split()[0];
747 if sVersion < sMinVersion:
748 return False;
749 return True;
750
751 #
752 # User related stuff.
753 #
754
755 def isReadOnlyUser(self):
756 """ Returns true if the logged in user is read-only or if no user is logged in. """
757 return self._oCurUser is None or self._oCurUser.fReadOnly;
758
759
760 #
761 # Debugging
762 #
763
764 def _debugProcessDispatch(self):
765 """
766 Processes any debugging parameters in the request and adds them to
767 _asCheckedParams so they won't cause trouble in the action handler.
768 """
769
770 self._fDbgSqlTrace = self.getBoolParam(self.ksParamDbgSqlTrace, False);
771 self._fDbgSqlExplain = self.getBoolParam(self.ksParamDbgSqlExplain, False);
772
773 if self._fDbgSqlExplain:
774 self._oDb.debugEnableExplain();
775
776 return True;
777
778 def _debugRenderPanel(self):
779 """
780 Renders a simple form for controlling WUI debugging.
781
782 Returns the HTML for it.
783 """
784
785 sHtml = '<div id="debug-panel">\n' \
786 ' <form id="debug-panel-form" method="get" action="#">\n';
787
788 for sKey, oValue in self._dParams.items():
789 if sKey not in self.kasDbgParams:
790 if hasattr(oValue, 'startswith'):
791 sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \
792 % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oValue),);
793 else:
794 for oSubValue in oValue:
795 sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \
796 % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oSubValue),);
797
798 for aoCheckBox in (
799 [self.ksParamDbgSqlTrace, self._fDbgSqlTrace, 'SQL trace'],
800 [self.ksParamDbgSqlExplain, self._fDbgSqlExplain, 'SQL explain'], ):
801 sHtml += ' <input type="checkbox" name="%s" value="1"%s />%s\n' \
802 % (aoCheckBox[0], ' checked' if aoCheckBox[1] else '', aoCheckBox[2]);
803
804 sHtml += ' <button type="submit">Apply</button>\n';
805 sHtml += ' </form>\n' \
806 '</div>\n';
807 return sHtml;
808
809
810 def _debugGetParameters(self):
811 """
812 Gets a dictionary with the debug parameters.
813
814 For use when links are constructed from scratch instead of self._dParams.
815 """
816 return self._dDbgParams;
817
818 #
819 # Dispatching
820 #
821
822 def _actionDefault(self):
823 """The default action handler, always overridden. """
824 raise WuiException('The child class shall override WuiBase.actionDefault().')
825
826 def _actionGenericListing(self, oLogicType, oListContentType):
827 """
828 Generic listing action.
829
830 oLogicType implements fetchForListing.
831 oListContentType is a child of WuiListContentBase.
832 """
833 tsEffective = self.getEffectiveDateParam();
834 cItemsPerPage = self.getIntParam(self.ksParamItemsPerPage, iMin = 2, iMax = 9999, iDefault = 384);
835 iPage = self.getIntParam(self.ksParamPageNo, iMin = 0, iMax = 999999, iDefault = 0);
836 aiSortColumnsDup = self.getListOfIntParams(self.ksParamSortColumns,
837 iMin = -getattr(oLogicType, 'kcMaxSortColumns', 0) + 1,
838 iMax = getattr(oLogicType, 'kcMaxSortColumns', 0), aiDefaults = []);
839 aiSortColumns = [];
840 for iSortColumn in aiSortColumnsDup:
841 if iSortColumn not in aiSortColumns:
842 aiSortColumns.append(iSortColumn);
843 self._checkForUnknownParameters();
844
845 aoEntries = oLogicType(self._oDb).fetchForListing(iPage * cItemsPerPage, cItemsPerPage + 1, tsEffective, aiSortColumns);
846 oContent = oListContentType(aoEntries, iPage, cItemsPerPage, tsEffective,
847 fnDPrint = self._oSrvGlue.dprint, oDisp = self, aiSelectedSortColumns = aiSortColumns);
848 (self._sPageTitle, self._sPageBody) = oContent.show();
849 return True;
850
851 def _actionGenericFormAdd(self, oDataType, oFormType, sRedirectTo = None):
852 """
853 Generic add something form display request handler.
854
855 oDataType is a ModelDataBase child class.
856 oFormType is a WuiFormContentBase child class.
857 """
858 assert issubclass(oDataType, ModelDataBase);
859 from testmanager.webui.wuicontentbase import WuiFormContentBase;
860 assert issubclass(oFormType, WuiFormContentBase);
861
862 oData = oDataType().initFromParams(oDisp = self, fStrict = False);
863 sRedirectTo = self.getRedirectToParameter(sRedirectTo);
864 self._checkForUnknownParameters();
865
866 oForm = oFormType(oData, oFormType.ksMode_Add, oDisp = self);
867 oForm.setRedirectTo(sRedirectTo);
868 (self._sPageTitle, self._sPageBody) = oForm.showForm();
869 return True
870
871 def _actionGenericFormDetails(self, oDataType, oLogicType, oFormType, sIdAttr = None, sGenIdAttr = None): # pylint: disable=too-many-locals
872 """
873 Generic handler for showing a details form/page.
874
875 oDataType is a ModelDataBase child class.
876 oLogicType may implement fetchForChangeLog.
877 oFormType is a WuiFormContentBase child class.
878 sIdParamName is the name of the ID parameter (not idGen!).
879 """
880 # Input.
881 assert issubclass(oDataType, ModelDataBase);
882 assert issubclass(oLogicType, ModelLogicBase);
883 from testmanager.webui.wuicontentbase import WuiFormContentBase;
884 assert issubclass(oFormType, WuiFormContentBase);
885
886 if sIdAttr is None:
887 sIdAttr = oDataType.ksIdAttr;
888 if sGenIdAttr is None:
889 sGenIdAttr = getattr(oDataType, 'ksGenIdAttr', None);
890
891 # Parameters.
892 idGenObject = -1;
893 if sGenIdAttr is not None:
894 idGenObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sGenIdAttr), 0, 0x7ffffffe, -1);
895 if idGenObject != -1:
896 idObject = tsNow = None;
897 else:
898 idObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sIdAttr), 0, 0x7ffffffe, -1);
899 tsNow = self.getEffectiveDateParam();
900 fChangeLog = self.getBoolParam(WuiDispatcherBase.ksParamChangeLogEnabled, True);
901 iChangeLogPageNo = self.getIntParam(WuiDispatcherBase.ksParamChangeLogPageNo, 0, 9999, 0);
902 cChangeLogEntriesPerPage = self.getIntParam(WuiDispatcherBase.ksParamChangeLogEntriesPerPage, 2, 9999, 4);
903 self._checkForUnknownParameters();
904
905 # Fetch item and display it.
906 if idGenObject == -1:
907 oData = oDataType().initFromDbWithId(self._oDb, idObject, tsNow);
908 else:
909 oData = oDataType().initFromDbWithGenId(self._oDb, idGenObject);
910
911 oContent = oFormType(oData, oFormType.ksMode_Show, oDisp = self);
912 (self._sPageTitle, self._sPageBody) = oContent.showForm();
913
914 # Add change log if supported.
915 if fChangeLog and hasattr(oLogicType, 'fetchForChangeLog'):
916 (aoEntries, fMore) = oLogicType(self._oDb).fetchForChangeLog(getattr(oData, sIdAttr),
917 iChangeLogPageNo * cChangeLogEntriesPerPage,
918 cChangeLogEntriesPerPage ,
919 tsNow);
920 self._sPageBody += oContent.showChangeLog(aoEntries, fMore, iChangeLogPageNo, cChangeLogEntriesPerPage, tsNow);
921 return True
922
923 def _actionGenericDoRemove(self, oLogicType, sParamId, sRedirAction):
924 """
925 Delete entry (using oLogicType.removeEntry).
926
927 oLogicType is a class that implements addEntry.
928
929 sParamId is the name (ksParam_...) of the HTTP variable hold the ID of
930 the database entry to delete.
931
932 sRedirAction is what action to redirect to on success.
933 """
934 import cgitb;
935
936 idEntry = self.getIntParam(sParamId, iMin = 1, iMax = 0x7ffffffe)
937 fCascade = self.getBoolParam('fCascadeDelete', False);
938 sRedirectTo = self.getRedirectToParameter(self._sActionUrlBase + sRedirAction);
939 self._checkForUnknownParameters()
940
941 try:
942 if self.isReadOnlyUser():
943 raise Exception('"%s" is a read only user!' % (self._oCurUser.sUsername,));
944 self._sPageTitle = None
945 self._sPageBody = None
946 self._sRedirectTo = sRedirectTo;
947 return oLogicType(self._oDb).removeEntry(self._oCurUser.uid, idEntry, fCascade = fCascade, fCommit = True);
948 except Exception as oXcpt:
949 self._oDb.rollback();
950 self._sPageTitle = 'Unable to delete entry';
951 self._sPageBody = str(oXcpt);
952 if config.g_kfDebugDbXcpt:
953 self._sPageBody += cgitb.html(sys.exc_info());
954 self._sRedirectTo = None;
955 return False;
956
957 def _actionGenericFormEdit(self, oDataType, oFormType, sIdParamName = None, sRedirectTo = None):
958 """
959 Generic edit something form display request handler.
960
961 oDataType is a ModelDataBase child class.
962 oFormType is a WuiFormContentBase child class.
963 sIdParamName is the name of the ID parameter (not idGen!).
964 """
965 assert issubclass(oDataType, ModelDataBase);
966 from testmanager.webui.wuicontentbase import WuiFormContentBase;
967 assert issubclass(oFormType, WuiFormContentBase);
968
969 if sIdParamName is None:
970 sIdParamName = getattr(oDataType, 'ksParam_' + oDataType.ksIdAttr);
971 assert len(sIdParamName) > 1;
972
973 tsNow = self.getEffectiveDateParam();
974 idObject = self.getIntParam(sIdParamName, 0, 0x7ffffffe);
975 sRedirectTo = self.getRedirectToParameter(sRedirectTo);
976 self._checkForUnknownParameters();
977 oData = oDataType().initFromDbWithId(self._oDb, idObject, tsNow = tsNow);
978
979 oContent = oFormType(oData, oFormType.ksMode_Edit, oDisp = self);
980 oContent.setRedirectTo(sRedirectTo);
981 (self._sPageTitle, self._sPageBody) = oContent.showForm();
982 return True
983
984 def _actionGenericFormEditL(self, oCoreObjectLogic, sCoreObjectIdFieldName, oWuiObjectLogic):
985 """
986 Generic modify something form display request handler.
987
988 @param oCoreObjectLogic A *Logic class
989
990 @param sCoreObjectIdFieldName Name of HTTP POST variable that
991 contains object ID information
992
993 @param oWuiObjectLogic Web interface renderer class
994 """
995
996 iCoreDataObjectId = self.getIntParam(sCoreObjectIdFieldName, 0, 0x7ffffffe, -1)
997 self._checkForUnknownParameters();
998
999 ## @todo r=bird: This will return a None object if the object wasn't found... Crash bang in the content generator
1000 # code (that's not logic code btw.).
1001 oData = oCoreObjectLogic(self._oDb).getById(iCoreDataObjectId)
1002
1003 # Instantiate and render the MODIFY dialog form
1004 oContent = oWuiObjectLogic(oData, oWuiObjectLogic.ksMode_Edit, oDisp=self)
1005
1006 (self._sPageTitle, self._sPageBody) = oContent.showForm()
1007
1008 return True
1009
1010 def _actionGenericFormClone(self, oDataType, oFormType, sIdAttr, sGenIdAttr = None):
1011 """
1012 Generic clone something form display request handler.
1013
1014 oDataType is a ModelDataBase child class.
1015 oFormType is a WuiFormContentBase child class.
1016 sIdParamName is the name of the ID parameter.
1017 sGenIdParamName is the name of the generation ID parameter, None if not applicable.
1018 """
1019 # Input.
1020 assert issubclass(oDataType, ModelDataBase);
1021 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1022 assert issubclass(oFormType, WuiFormContentBase);
1023
1024 # Parameters.
1025 idGenObject = -1;
1026 if sGenIdAttr is not None:
1027 idGenObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sGenIdAttr), 0, 0x7ffffffe, -1);
1028 if idGenObject != -1:
1029 idObject = tsNow = None;
1030 else:
1031 idObject = self.getIntParam(getattr(oDataType, 'ksParam_' + sIdAttr), 0, 0x7ffffffe, -1);
1032 tsNow = self.getEffectiveDateParam();
1033 self._checkForUnknownParameters();
1034
1035 # Fetch data and clear identifying attributes not relevant to the clone.
1036 if idGenObject != -1:
1037 oData = oDataType().initFromDbWithGenId(self._oDb, idGenObject);
1038 else:
1039 oData = oDataType().initFromDbWithId(self._oDb, idObject, tsNow);
1040
1041 setattr(oData, sIdAttr, None);
1042 if sGenIdAttr is not None:
1043 setattr(oData, sGenIdAttr, None);
1044 oData.tsEffective = None;
1045 oData.tsExpire = None;
1046
1047 # Display form.
1048 oContent = oFormType(oData, oFormType.ksMode_Add, oDisp = self);
1049 (self._sPageTitle, self._sPageBody) = oContent.showForm()
1050 return True
1051
1052
1053 def _actionGenericFormPost(self, sMode, fnLogicAction, oDataType, oFormType, sRedirectTo, fStrict = True):
1054 """
1055 Generic POST request handling from a WuiFormContentBase child.
1056
1057 oDataType is a ModelDataBase child class.
1058 oFormType is a WuiFormContentBase child class.
1059 fnLogicAction is a method taking a oDataType instance and uidAuthor as arguments.
1060 """
1061 assert issubclass(oDataType, ModelDataBase);
1062 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1063 assert issubclass(oFormType, WuiFormContentBase);
1064
1065 #
1066 # Read and validate parameters.
1067 #
1068 oData = oDataType().initFromParams(oDisp = self, fStrict = fStrict);
1069 sRedirectTo = self.getRedirectToParameter(sRedirectTo);
1070 self._checkForUnknownParameters();
1071 self._assertPostRequest();
1072 if sMode == WuiFormContentBase.ksMode_Add and getattr(oData, 'kfIdAttrIsForForeign', False):
1073 enmValidateFor = oData.ksValidateFor_AddForeignId;
1074 elif sMode == WuiFormContentBase.ksMode_Add:
1075 enmValidateFor = oData.ksValidateFor_Add;
1076 else:
1077 enmValidateFor = oData.ksValidateFor_Edit;
1078 dErrors = oData.validateAndConvert(self._oDb, enmValidateFor);
1079
1080 # Check that the user can do this.
1081 sErrorMsg = None;
1082 assert self._oCurUser is not None;
1083 if self.isReadOnlyUser():
1084 sErrorMsg = 'User %s is not allowed to modify anything!' % (self._oCurUser.sUsername,)
1085
1086 if not dErrors and not sErrorMsg:
1087 oData.convertFromParamNull();
1088
1089 #
1090 # Try do the job.
1091 #
1092 try:
1093 fnLogicAction(oData, self._oCurUser.uid, fCommit = True);
1094 except Exception as oXcpt:
1095 self._oDb.rollback();
1096 oForm = oFormType(oData, sMode, oDisp = self);
1097 oForm.setRedirectTo(sRedirectTo);
1098 sErrorMsg = str(oXcpt) if not config.g_kfDebugDbXcpt else '\n'.join(utils.getXcptInfo(4));
1099 (self._sPageTitle, self._sPageBody) = oForm.showForm(sErrorMsg = sErrorMsg);
1100 else:
1101 #
1102 # Worked, redirect to the specified page.
1103 #
1104 self._sPageTitle = None;
1105 self._sPageBody = None;
1106 self._sRedirectTo = sRedirectTo;
1107 else:
1108 oForm = oFormType(oData, sMode, oDisp = self);
1109 oForm.setRedirectTo(sRedirectTo);
1110 (self._sPageTitle, self._sPageBody) = oForm.showForm(dErrors = dErrors, sErrorMsg = sErrorMsg);
1111 return True;
1112
1113 def _actionGenericFormAddPost(self, oDataType, oLogicType, oFormType, sRedirAction, fStrict=True):
1114 """
1115 Generic add entry POST request handling from a WuiFormContentBase child.
1116
1117 oDataType is a ModelDataBase child class.
1118 oLogicType is a class that implements addEntry.
1119 oFormType is a WuiFormContentBase child class.
1120 sRedirAction is what action to redirect to on success.
1121 """
1122 assert issubclass(oDataType, ModelDataBase);
1123 assert issubclass(oLogicType, ModelLogicBase);
1124 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1125 assert issubclass(oFormType, WuiFormContentBase);
1126
1127 oLogic = oLogicType(self._oDb);
1128 return self._actionGenericFormPost(WuiFormContentBase.ksMode_Add, oLogic.addEntry, oDataType, oFormType,
1129 '?' + webutils.encodeUrlParams({self.ksParamAction: sRedirAction}), fStrict=fStrict)
1130
1131 def _actionGenericFormEditPost(self, oDataType, oLogicType, oFormType, sRedirAction, fStrict = True):
1132 """
1133 Generic edit POST request handling from a WuiFormContentBase child.
1134
1135 oDataType is a ModelDataBase child class.
1136 oLogicType is a class that implements addEntry.
1137 oFormType is a WuiFormContentBase child class.
1138 sRedirAction is what action to redirect to on success.
1139 """
1140 assert issubclass(oDataType, ModelDataBase);
1141 assert issubclass(oLogicType, ModelLogicBase);
1142 from testmanager.webui.wuicontentbase import WuiFormContentBase;
1143 assert issubclass(oFormType, WuiFormContentBase);
1144
1145 oLogic = oLogicType(self._oDb);
1146 return self._actionGenericFormPost(WuiFormContentBase.ksMode_Edit, oLogic.editEntry, oDataType, oFormType,
1147 '?' + webutils.encodeUrlParams({self.ksParamAction: sRedirAction}),
1148 fStrict = fStrict);
1149
1150 def _unauthorizedUser(self):
1151 """
1152 Displays the unauthorized user message (corresponding record is not
1153 present in DB).
1154 """
1155
1156 sLoginName = self._oSrvGlue.getLoginName();
1157
1158 # Report to system log
1159 oSystemLogLogic = SystemLogLogic(self._oDb);
1160 oSystemLogLogic.addEntry(SystemLogData.ksEvent_UserAccountUnknown,
1161 'Unknown user (%s) attempts to access from %s'
1162 % (sLoginName, self._oSrvGlue.getClientAddr()),
1163 24, fCommit = True)
1164
1165 # Display message.
1166 self._sPageTitle = 'User not authorized'
1167 self._sPageBody = """
1168 <p>Access denied for user <b>%s</b>.
1169 Please contact an admin user to set up your access.</p>
1170 """ % (sLoginName,)
1171 return True;
1172
1173 def dispatchRequest(self):
1174 """
1175 Dispatches a request.
1176 """
1177
1178 #
1179 # Get the parameters and checks for duplicates.
1180 #
1181 try:
1182 dParams = self._oSrvGlue.getParameters();
1183 except Exception as oXcpt:
1184 raise WuiException('Error retriving parameters: %s' % (oXcpt,));
1185
1186 for sKey in dParams.keys():
1187
1188 # Take care about strings which may contain unicode characters: convert percent-encoded symbols back to unicode.
1189 for idxItem, _ in enumerate(dParams[sKey]):
1190 dParams[sKey][idxItem] = utils.toUnicode(dParams[sKey][idxItem], 'utf-8');
1191
1192 if not len(dParams[sKey]) > 1:
1193 dParams[sKey] = dParams[sKey][0];
1194 self._dParams = dParams;
1195
1196 #
1197 # Figure out the requested action and validate it.
1198 #
1199 if self.ksParamAction in self._dParams:
1200 self._sAction = self._dParams[self.ksParamAction];
1201 self._asCheckedParams.append(self.ksParamAction);
1202 else:
1203 self._sAction = self.ksActionDefault;
1204
1205 if isinstance(self._sAction, list) or self._sAction not in self._dDispatch:
1206 raise WuiException('Unknown action "%s" requested' % (self._sAction,));
1207
1208 #
1209 # Call action handler and generate the page (if necessary).
1210 #
1211 if self._oCurUser is not None:
1212 self._debugProcessDispatch();
1213 if self._dDispatch[self._sAction]() is self.ksDispatchRcAllDone:
1214 return True;
1215 else:
1216 self._unauthorizedUser();
1217
1218 if self._sRedirectTo is None:
1219 self._generatePage();
1220 else:
1221 self._redirectPage();
1222 return True;
1223
1224
1225 def dprint(self, sText):
1226 """ Debug printing. """
1227 if config.g_kfWebUiDebug and True:
1228 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