# -*- coding: utf-8 -*-
# $Id$
"""
Test Manager Web-UI - Base Classes.
"""
__copyright__ = \
"""
Copyright (C) 2012-2014 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
General Public License (GPL) as published by the Free Software
Foundation, in version 2 as it comes in the "COPYING" file of the
VirtualBox OSE distribution. VirtualBox OSE is distributed in the
hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
The contents of this file may alternatively be used under the terms
of the Common Development and Distribution License Version 1.0
(CDDL) only, as it comes in the "COPYING.CDDL" file of the
VirtualBox OSE distribution, in which case the provisions of the
CDDL are applicable instead of those of the GPL.
You may elect to license modified versions of this file under the
terms and conditions of either the GPL or the CDDL or both.
"""
# Standard python imports.
import os;
# Validation Kit imports.
"""
For exceptions raised by Web UI code.
"""
pass;
"""
Base class for the Web User Interface (WUI) dispatchers.
The dispatcher class defines the basics of the page (like base template,
menu items, action). It is also responsible for parsing requests and
The content returned by the generator is merged into the template and sent
back to the webserver glue.
"""
## @todo possible that this should all go into presentation.
## The action parameter.
## The name of the default action.
## The name of the current page number parameter used when displaying lists.
## The name of the page length (list items) parameter when displaying lists.
## The name of the effective date (timestamp) parameter.
## The name of the list-action parameter (WuiListContentWithActionBase).
## The name of the parmaeter indicating the change log page number.
## The name of the parameter indicate number of change log entries per page.
## @name Dispatcher debugging parameters.
## {@
## List of all debugging parameters.
## @}
## Special action return code for skipping _generatePage. Useful for
# download pages and the like that messes with the HTTP header and more.
self._oDb = TMDatabaseConnection(self.dprint if config.g_kfWebUiSqlDebug else None, oSrvGlue = oSrvGlue);
self._asCheckedParams = [];
# Template bits.
self._sRedirectTo = None;
# Debugger bits.
# Determine currently logged in user credentials
# Calc a couple of URL base strings for this dispatcher.
"""
Redirects the page to the URL given in self._sRedirectTo.
"""
assert self._sRedirectTo is not None;
assert self._sPageBody is None;
assert self._sPageTitle is None;
return True;
"""
Generates the two menus, returning them as (sTopMenuItems, sSideMenuItems).
"""
#
# We use the action to locate the side menu.
#
aasSideMenu = None;
break;
break;
if aasSideMenu is not None:
break;
#
# Top menu first.
#
sTopMenuItems = '';
sTopMenuItems += '<li class="current_page_item">';
else:
sTopMenuItems += '<li>';
#
# Side menu (if found).
#
sSideMenuItems = '';
if aasSideMenu is not None:
for asSubItem in aasSideMenu:
sSideMenuItems += '<li class="current_page_item">';
else:
sSideMenuItems += '<li>';
return (sTopMenuItems, sSideMenuItems);
"""
Generates the page using _sTemplate, _sPageTitle, _aaoMenus, and _sPageBody.
"""
assert self._sRedirectTo is None;
# Load the template.
# Do replacements.
else:
sTmpl = sTmpl.replace('@@USER_NAME@@', 'unauthorized user "' + self._oSrvGlue.getLoginName() + '"');
# Provide basic auth log out for browsers that supports it.
or False:
# Log in as the logout user in the same realm, the browser forgets
# the old login and the job is done. (see apache sample conf)
sLogOut = ' (<a href="%s://logout:logout@%s%slogout.py">logout</a>)' \
or False:
# For a 401, causing the browser to forget the old login. Works
# with safari as well as the two above. Since safari consider the
# above method a phishing attempt and displays a warning to that
# effect, which when taken seriously aborts the logout, this method
# is preferable, even if it throws logon boxes in the user's face
sLogOut = ' (<a href="logout2.py">logout</a>)'
or False:
## There doesn't seem to be any way to make IE really log out
# without using a cookie and systematically 401 accesses based on
# some logout state associated with it. Not sure how secure that
# can be made and we really want to avoid cookies. So, perhaps,
# just avoid IE for now. :-)
## Chrome/21.0 doesn't want to log out either.
sLogOut = ''
else:
sLogOut = ''
# Debug section.
elif config.g_kfWebUiProcessedIn:
unicode(self._sDebug, errors='ignore') if isinstance(self._sDebug, str) else self._sDebug + '</div>');
else:
# Output the result.
return True;
#
# Interface for WuiContentBase classes.
#
"""
Returns a (shallow) copy of the request parameter dictionary.
"""
"""
Returns the database connection.
"""
#
# Parameter handling.
#
"""
Gets a string parameter.
Raises exception if not found and sDefault is None.
"""
raise WuiException('%s parameter "%s" is given multiple times: "%s"' % (self._sAction, sName, sValue));
elif sDefault is None:
else:
raise WuiException('%s parameter %s value "%s" not in %s '
return sValue;
"""
Gets a boolean parameter.
Raises exception if not found and fDefault is None, or if not a valid boolean.
"""
# HACK: Checkboxes doesn't return a value when unchecked, so we always
# provide a default when dealing with boolean parameters.
"""
Gets a integer parameter.
Raises exception if not found and iDefault is None, if not a valid int,
or if outside the range defined by iMin and iMax.
"""
return iDefault;
try:
except:
raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
return iValue;
"""
Gets a long integer parameter.
Raises exception if not found and lDefault is None, if not a valid long,
or if outside the range defined by lMin and lMax.
"""
return lDefault;
try:
except:
raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
return lValue;
"""
Gets a timestamp parameter.
Raises exception if not found and fRequired is True.
"""
return tsDefault;
if sError is not None:
raise WuiException('%s parameter %s value "%s": %s'
return sValue;
"""
Gets parameter list.
Raises exception if not found and aiDefaults is None, or if any of the
values are not valid integers or outside the range defined by iMin and iMax.
"""
else:
aiValues = [];
try:
except:
raise WuiException('%s parameter %s value "%s" cannot be convert to an integer'
raise WuiException('%s parameter %s value %d is out of range [%s..%s]'
else:
return aiValues;
"""
Gets parameter list.
Raises exception if not found and asDefaults is None.
"""
else:
elif asDefaults is None:
else:
return asValues;
def getListOfTestCasesParam(self, sName, asDefaults = None): # too many local vars - pylint: disable=R0914
"""Get list of test cases and their parameters"""
aoListOfTestCases = []
for idTestCase in aiAllTestCases:
aiDefaults=[])
aiDefaults=[])
for idTestCaseArgs in aiAllTestCaseArgs:
# Dry run
if aoListOfTestCases == []:
if asDefaults is None:
return aoListOfTestCases
"""
Gets the effective date parameter.
Returns a timestamp suitable for database and url parameters.
Returns None if not found or empty.
"""
return None;
raise WuiException('%s parameter "%s" is given multiple times: %s' % (self._sAction, sName, sValue));
if sValue == '':
return None;
#
# Timestamp, just validate it and return.
#
if sError is not None:
raise WuiException('%s parameter "%s" ("%s") is invalid: %s' % (self._sAction, sName, sValue, sError));
return sValue;
#
# Relative timestamp. Validate and convert it to a fixed timestamp.
#
if sError is not None:
raise WuiException('%s parameter "%s" ("%s") is invalid: %s' % (self._sAction, sName, sValue, sError));
raise WuiException('%s parameter "%s" ("%s") is a relative timestamp but incorrectly includes a time zone.'
offTime = 11;
"""
Check if we've handled all parameters, raises exception if anything
unknown was found.
"""
sUnknownParams = '';
return True;
"""
Makes sure that the request we're dispatching is a POST request.
Raises an exception of not.
"""
return True;
#
# Client browser type.
#
## @name Browser types.
## @{
## @}
## @name Browser types.
## @{
## @}
"""
Gets the browser type.
The browser family can be extracted from this using ksBrowserType_FamilyMask.
"""
return self.ksBrowserType_Chrome;
return self.ksBrowserType_Safari;
return self.ksBrowserType_Firefox;
""" Returns true if it's a gecko based browser. """
return False;
if sMinVersion is not None:
if sVersion < sMinVersion:
return False;
return True;
#
# Debugging
#
"""
Processes any debugging parameters in the request and adds them to
_asCheckedParams so they won't cause trouble in the action handler.
"""
if self._fDbgSqlExplain:
return True;
"""
Renders a simple form for controlling WUI debugging.
Returns the HTML for it.
"""
sHtml = '<div id="debug-panel">\n' \
' <form id="debug-panel-form" type="get" action="#">\n';
sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \
for aoCheckBox in (
sHtml += ' <input type="checkbox" name="%s" value="1"%s>%s</input>\n' \
sHtml += ' <button type="submit">Apply</button>\n';
sHtml += ' </form>\n' \
'</div>\n';
return sHtml;
"""
Gets a dictionary with the debug parameters.
For use when links are constructed from scratch instead of self._dParams.
"""
return self._dDbgParams;
#
# Dispatching
#
"""The default action handler, always overridden. """
raise WuiException('The child class shall override WuiBase.actionDefault().')
"""
Generic listing action.
oLogicType implements fetchForListing.
oListContentType is a child of WuiListContentBase.
"""
aoEntries = oLogicType(self._oDb).fetchForListing(iPage * cItemsPerPage, cItemsPerPage + 1, tsEffective);
return True;
"""
Generic add something form display request handler.
oDataType is a ModelDataBase child class.
oFormType is a WuiFormContentBase child class.
"""
return True
def _actionGenericFormDetails(self, oDataType, oLogicType, oFormType, sIdAttr, sGenIdAttr = None): # pylint: disable=R0914
"""
oDataType is a ModelDataBase child class.
oLogicType may implement fetchForChangeLog.
oFormType is a WuiFormContentBase child class.
sIdParamName is the name of the ID parameter (not idGen!).
"""
# Parameters.
idGenObject = -1;
if sGenIdAttr is not None:
if idGenObject != -1:
else:
cChangeLogEntriesPerPage = self.getIntParam(WuiDispatcherBase.ksParamChangeLogEntriesPerPage, 2, 9999, 4);
# Fetch item and display it.
if idGenObject == -1:
else:
# Add change log if supported.
tsNow);
self._sPageBody += oContent.showChangeLog(aoEntries, fMore, iChangeLogPageNo, cChangeLogEntriesPerPage, tsNow);
return True
"""
Generic edit something form display request handler.
oDataType is a ModelDataBase child class.
oFormType is a WuiFormContentBase child class.
sIdParamName is the name of the ID parameter (not idGen!).
"""
return True
"""
Generic modify something form display request handler.
@param oCoreObjectLogic A *Logic class
@param sCoreObjectIdFieldName Name of HTTP POST variable that
contains object ID information
@param oWuiObjectLogic Web interface renderer class
"""
## @todo r=bird: This will return a None object if the object wasn't found... Crash bang in the content generator
# code (that's not logic code btw.).
# Instantiate and render the MODIFY dialog form
return True
"""
Generic clone something form display request handler.
oDataType is a ModelDataBase child class.
oFormType is a WuiFormContentBase child class.
sIdParamName is the name of the ID parameter.
sGenIdParamName is the name of the generation ID parameter, None if not applicable.
"""
# Parameters.
idGenObject = -1;
if sGenIdAttr is not None:
if idGenObject != -1:
else:
# Fetch data and clear identifying attributes not relevant to the clone.
if idGenObject != -1:
else:
if sGenIdAttr is not None:
oData.tsEffective = None;
# Display form.
return True
def _actionGenericFormPost(self, sMode, fnLogicAction, oDataType, oFormType, sRedirectTo, fStrict=True):
"""
Generic POST request handling from a WuiFormContentBase child.
oDataType is a ModelDataBase child class.
oFormType is a WuiFormContentBase child class.
fnLogicAction is a method taking a oDataType instance and uidAuthor as arguments.
"""
#
# Read and validate parameters.
#
#
# Try do the job.
#
try:
else:
#
# Worked, redirect to the specified page.
#
self._sPageTitle = None;
self._sPageBody = None;
else:
return True;
"""
Generic add entry POST request handling from a WuiFormContentBase child.
oDataType is a ModelDataBase child class.
oLogicType is a class that implements addEntry.
oFormType is a WuiFormContentBase child class.
sRedirAction is what action to redirect to on success.
"""
return self._actionGenericFormPost(WuiFormContentBase.ksMode_Add, oLogic.addEntry, oDataType, oFormType,
def _actionGenericFormEditPost(self, oDataType, oLogicType, oFormType, sRedirAction, fStrict = True):
"""
Generic edit POST request handling from a WuiFormContentBase child.
oDataType is a ModelDataBase child class.
oLogicType is a class that implements addEntry.
oFormType is a WuiFormContentBase child class.
sRedirAction is what action to redirect to on success.
"""
return self._actionGenericFormPost(WuiFormContentBase.ksMode_Edit, oLogic.editEntry, oDataType, oFormType,
"""
Displays the unauthorized user message (corresponding record is not
present in DB).
"""
# Report to system log
'Unknown user (%s) attempts to access from %s'
# Display message.
<p>Access denied for user <b>%s</b>.
Please contact an admin user to set up your access.</p>
""" % (sLoginName,)
return True;
"""
Dispatches a request.
"""
#
# Get the parameters and checks for duplicates.
#
try:
# Take care about strings which may contain unicode characters: convert percent-encoded symbols back to unicode.
#
# Figure out the requested action and validate it.
#
else:
#
# Call action handler and generate the page (if necessary).
#
return True;
else:
if self._sRedirectTo is None:
else:
return True;
""" Debug printing. """