# -*- coding: utf-8 -*- # $Id: wuihlpform.py 56295 2015-06-09 14:29:55Z vboxsync $ """ Test Manager Web-UI - Form Helpers. """ __copyright__ = \ """ Copyright (C) 2012-2015 Oracle Corporation This file is part of VirtualBox Open Source Edition (OSE), as available from http://www.virtualbox.org. This file is free software; you can redistribute it and/or modify it under the terms of the GNU 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. """ __version__ = "$Revision: 56295 $" # Standard python imports. import copy; # Validation Kit imports. from common import utils; from common.webutils import escapeAttr, escapeElem; from testmanager import config; from testmanager.core.schedgroup import SchedGroupMemberData, SchedGroupDataEx; from testmanager.core.testcaseargs import TestCaseArgsData; from testmanager.core.testgroup import TestGroupMemberData, TestGroupDataEx; class WuiHlpForm(object): """ Helper for constructing a form. """ ksItemsList = 'ksItemsList' def __init__(self, sId, sAction, dErrors = None, fReadOnly = False): self._fFinalized = False; self._fReadOnly = fReadOnly; self._dErrors = dErrors if dErrors is not None else dict(); self._sBody = u'\n' \ u'
\n' \ u'
\n' \ u' \n' '
\n' '
\n' '
\n' ); return self._sBody; def addTextHidden(self, sName, sValue, sExtraAttribs = ''): """Adds a hidden text input.""" return self._add('
\n' ' \n' '
\n' ' \n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(str(sValue)) )); # # Text input fields. # def addText(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = '', sPostHtml = ''): """Adds a text input.""" if self._fReadOnly: return self.addTextRO(sName, sValue, sLabel, sSubClass, sExtraAttribs); if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp', 'wide'): raise Exception(sSubClass); self._addLabel(sName, sLabel, sSubClass); return self._add(' %s\n' ' \n' ' \n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sValue), sPostHtml )); def addTextRO(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = '', sPostHtml = ''): """Adds a read-only text input.""" if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp', 'wide'): raise Exception(sSubClass); self._addLabel(sName, sLabel, sSubClass); return self._add(' %s\n' ' \n' ' \n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(str(sValue)), sPostHtml )); def addWideText(self, sName, sValue, sLabel, sExtraAttribs = ''): """Adds a wide text input.""" return self.addText(sName, sValue, sLabel, 'wide', sExtraAttribs); def addWideTextRO(self, sName, sValue, sLabel, sExtraAttribs = ''): """Adds a wide read-only text input.""" return self.addTextRO(sName, sValue, sLabel, 'wide', sExtraAttribs); def addMultilineText(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = ''): """Adds a multiline text input.""" if self._fReadOnly: return self.addMultilineTextRO(sName, sValue, sLabel, sSubClass, sExtraAttribs); if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp'): raise Exception(sSubClass) self._addLabel(sName, sLabel, sSubClass) sNewValue = str(sValue) if not isinstance(sValue, list) else '\n'.join(sValue) return self._add(' \n' ' \n' ' \n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sNewValue))) def addMultilineTextRO(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = ''): """Adds a multiline read-only text input.""" if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp'): raise Exception(sSubClass) self._addLabel(sName, sLabel, sSubClass) sNewValue = str(sValue) if not isinstance(sValue, list) else '\n'.join(sValue) return self._add(' \n' ' \n' ' \n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sNewValue))) def addInt(self, sName, iValue, sLabel, sExtraAttribs = ''): """Adds an integer input.""" return self.addText(sName, str(iValue), sLabel, 'int', sExtraAttribs); def addIntRO(self, sName, iValue, sLabel, sExtraAttribs = ''): """Adds an integer input.""" return self.addTextRO(sName, str(iValue), sLabel, 'int', sExtraAttribs); def addLong(self, sName, lValue, sLabel, sExtraAttribs = ''): """Adds a long input.""" return self.addText(sName, str(lValue), sLabel, 'long', sExtraAttribs); def addLongRO(self, sName, lValue, sLabel, sExtraAttribs = ''): """Adds a long input.""" return self.addTextRO(sName, str(lValue), sLabel, 'long', sExtraAttribs); def addUuid(self, sName, uuidValue, sLabel, sExtraAttribs = ''): """Adds an UUID input.""" return self.addText(sName, str(uuidValue), sLabel, 'uuid', sExtraAttribs); def addUuidRO(self, sName, uuidValue, sLabel, sExtraAttribs = ''): """Adds a read-only UUID input.""" return self.addTextRO(sName, str(uuidValue), sLabel, 'uuid', sExtraAttribs); def addTimestampRO(self, sName, sTimestamp, sLabel, sExtraAttribs = ''): """Adds a read-only database string timstamp input.""" return self.addTextRO(sName, sTimestamp, sLabel, 'timestamp', sExtraAttribs); # # Text areas. # # # Combo boxes. # def addComboBox(self, sName, sSelected, sLabel, aoOptions, sExtraAttribs = ''): """Adds a combo box.""" if self._fReadOnly: return self.addComboBoxRO(sName, sSelected, sLabel, aoOptions, sExtraAttribs); self._addLabel(sName, sLabel, 'combobox'); self._add(' \n' ' \n' ' \n' ); def addComboBoxRO(self, sName, sSelected, sLabel, aoOptions, sExtraAttribs = ''): """Adds a read-only combo box.""" self.addTextHidden(sName, sSelected); self._addLabel(sName, sLabel, 'combobox-readonly'); self._add(' \n' ' \n' ' \n' ); # # Check boxes. # @staticmethod def _reinterpretBool(fValue): """Reinterprets a value as a boolean type.""" if fValue is not type(True): if fValue is None: fValue = False; elif str(fValue) in ('True', 'true', '1'): fValue = True; else: fValue = False; return fValue; def addCheckBox(self, sName, fChecked, sLabel, sExtraAttribs = ''): """Adds an check box.""" if self._fReadOnly: return self.addCheckBoxRO(sName, fChecked, sLabel, sExtraAttribs); self._addLabel(sName, sLabel, 'checkbox'); fChecked = self._reinterpretBool(fChecked); return self._add(' \n' ' \n' ' \n' % (escapeAttr(sName), escapeAttr(sName), ' checked' if fChecked else '', sExtraAttribs)); def addCheckBoxRO(self, sName, fChecked, sLabel, sExtraAttribs = ''): """Adds an readonly check box.""" self._addLabel(sName, sLabel, 'checkbox'); fChecked = self._reinterpretBool(fChecked); # Hack Alert! The onclick and onkeydown are for preventing editing and fake readonly/disabled. return self._add(' \n' ' \n' ' \n' % (escapeAttr(sName), escapeAttr(sName), ' checked' if fChecked else '', sExtraAttribs)); # # List of items to check # def _addList(self, sName, aoRows, sLabel, fUseTable = False, sId = 'dummy', sExtraAttribs = ''): """ Adds a list of items to check. @param sName Name of HTML form element @param aoRows List of [sValue, fChecked, sName] sub-arrays. @param sLabel Label of HTML form element """ fReadOnly = self._fReadOnly; ## @todo add this as a parameter. if fReadOnly: sExtraAttribs += ' readonly onclick="return false" onkeydown="return false"'; self._addLabel(sName, sLabel, 'list'); if len(aoRows) == 0: return self._add('No items') sNameEscaped = escapeAttr(sName); self._add('
\n' % (escapeAttr(sId),)); if fUseTable: self._add(' \n'); for asRow in aoRows: assert len(asRow) == 3; # Don't allow sloppy input data! fChecked = self._reinterpretBool(asRow[1]) self._add(' \n' ' \n' ' \n' ' \n' % ( sNameEscaped, escapeAttr(str(asRow[0])), ' checked' if fChecked else '', sExtraAttribs, escapeElem(str(asRow[2])), )); self._add('
%s
\n'); else: for asRow in aoRows: assert len(asRow) == 3; # Don't allow sloppy input data! fChecked = self._reinterpretBool(asRow[1]) self._add('
' ' %s
\n' % ( sNameEscaped, escapeAttr(str(asRow[0])), ' checked' if fChecked else '', sExtraAttribs, escapeElem(str(asRow[2])),)); return self._add('
\n' ' \n'); def addListOfOsArches(self, sName, aoOsArches, sLabel, sExtraAttribs = ''): """ List of checkboxes for OS/ARCH selection. asOsArches is a list of [sValue, fChecked, sName] sub-arrays. """ return self._addList(sName, aoOsArches, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-os-arches', sExtraAttribs = sExtraAttribs); def addListOfTypes(self, sName, aoTypes, sLabel, sExtraAttribs = ''): """ List of checkboxes for build type selection. aoTypes is a list of [sValue, fChecked, sName] sub-arrays. """ return self._addList(sName, aoTypes, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-build-types', sExtraAttribs = sExtraAttribs); def addListOfTestCases(self, sName, aoTestCases, sLabel, sExtraAttribs = ''): """ List of checkboxes for test box (dependency) selection. aoTestCases is a list of [sValue, fChecked, sName] sub-arrays. """ return self._addList(sName, aoTestCases, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-testcases', sExtraAttribs = sExtraAttribs); def addListOfResources(self, sName, aoTestCases, sLabel, sExtraAttribs = ''): """ List of checkboxes for resource selection. aoTestCases is a list of [sValue, fChecked, sName] sub-arrays. """ return self._addList(sName, aoTestCases, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-resources', sExtraAttribs = sExtraAttribs); def addListOfTestGroups(self, sName, aoTestGroups, sLabel, sExtraAttribs = ''): """ List of checkboxes for test group selection. aoTestGroups is a list of [sValue, fChecked, sName] sub-arrays. """ return self._addList(sName, aoTestGroups, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-testgroups', sExtraAttribs = sExtraAttribs); def addListOfTestCaseArgs(self, sName, aoVariations, sLabel): # pylint: disable=R0915 """ Adds a list of test case argument variations to the form. @param sName Name of HTML form element @param aoVariations List of TestCaseArgsData instances. @param sLabel Label of HTML form element """ self._addLabel(sName, sLabel); sTableId = 'TestArgsExtendingListRoot'; fReadOnly = self._fReadOnly; ## @todo argument? sReadOnlyAttr = ' readonly class="tmform-input-readonly"' if fReadOnly else ''; sHtml = '
  • \n' # # Define javascript function for extending the list of test case # variations. Doing it here so we can use the python constants. This # also permits multiple argument lists on one page should that ever be # required... # if not fReadOnly: sHtml += '\n'; # # List current entries. # sHtml += '\n' \ % (sName, sName, ','.join(str(i) for i in range(len(aoVariations))), ); sHtml += ' \n' % (sTableId,) if not fReadOnly: sHtml += ' \n'; dSubErrors = {}; if sName in self._dErrors and isinstance(self._dErrors[sName], dict): dSubErrors = self._dErrors[sName]; for iVar in range(len(aoVariations)): oVar = copy.copy(aoVariations[iVar]); oVar.convertToParamNull(); sHtml += '\n' % (sName, iVar,) sHtml += ' \n' \ ' ' \ ' \n' \ ' ' \ ' \n' \ % ( sName, iVar, TestCaseArgsData.ksParam_cGangMembers, sName, iVar, oVar.cGangMembers, sReadOnlyAttr, sName, iVar, TestCaseArgsData.ksParam_cSecTimeout, sName, iVar, utils.formatIntervalSeconds2(oVar.cSecTimeout), sReadOnlyAttr, ); if not fReadOnly: sHtml += ' \n' \ % (sName, iVar); else: sHtml += ' \n'; sHtml += ' \n' \ ' \n'; sHtml += ' \n' \ ' ' \ ' \n' \ ' \n' \ ' \n' \ % ( sName, iVar, TestCaseArgsData.ksParam_sArgs, sName, iVar, escapeAttr(oVar.sArgs), sReadOnlyAttr) sHtml += ' \n' \ ' ' \ ' \n' \ ' \n' \ ' \n' \ % ( sName, iVar, TestCaseArgsData.ksParam_sTestBoxReqExpr, sName, iVar, escapeAttr(oVar.sTestBoxReqExpr), sReadOnlyAttr) sHtml += ' \n' \ ' ' \ ' \n' \ ' \n' \ ' \n' \ % ( sName, iVar, TestCaseArgsData.ksParam_sBuildReqExpr, sName, iVar, escapeAttr(oVar.sBuildReqExpr), sReadOnlyAttr) if iVar in dSubErrors: sHtml += ' \n' \ % (self._escapeErrorText(dSubErrors[iVar]),); sHtml += '\n'; sHtml += '
    \n' \ ' Add\n' % (sName,); if config.g_kfVBoxSpecific: sHtml += ' [Single CPU Variations\n' % (sName,); sHtml += ' amd64]\n' % (sName,); sHtml += ' [SMP Variations]\n' % (sName,); sHtml += '
    Gang Members:Timeout:Remove
    Arguments:' \ '
    TestBox Reqs:' \ '
    Build Reqs:' \ '

    %s

    \n' sHtml += '
  • \n' return self._add(sHtml) def addListOfTestGroupMembers(self, sName, aoTestGroupMembers, aoAllTestCases, sLabel, # pylint: disable=R0914 fReadOnly = True): """ For WuiTestGroup. """ assert len(aoTestGroupMembers) <= len(aoAllTestCases); self._addLabel(sName, sLabel); if len(aoAllTestCases) == 0: return self._add('
  • No testcases available.
  • \n') self._add('\n' % ( TestGroupDataEx.ksParam_aidTestCases, ','.join([str(oTestCase.idTestCase) for oTestCase in aoAllTestCases]), )); self._add('\n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ); if self._fReadOnly: fReadOnly = True; sCheckBoxAttr = ' readonly onclick="return false" onkeydown="return false"' if fReadOnly else ''; oDefMember = TestGroupMemberData(); aoTestGroupMembers = list(aoTestGroupMembers); # Copy it so we can pop. for iTestCase in range(len(aoAllTestCases)): oTestCase = aoAllTestCases[iTestCase]; # Is it a member? oMember = None; for i in range(len(aoTestGroupMembers)): if aoTestGroupMembers[i].oTestCase.idTestCase == oTestCase.idTestCase: oMember = aoTestGroupMembers.pop(i); break; # Start on the rows... sPrefix = '%s[%d]' % (sName, oTestCase.idTestCase,); self._add(' \n' ' \n' % ( 'tmodd' if iTestCase & 1 else 'tmeven', len(oTestCase.aoTestCaseArgs), sPrefix, TestGroupMemberData.ksParam_idTestCase, oTestCase.idTestCase, sPrefix, TestGroupMemberData.ksParam_idTestGroup, -1 if oMember is None else oMember.idTestGroup, sPrefix, TestGroupMemberData.ksParam_tsExpire, '' if oMember is None else oMember.tsExpire, sPrefix, TestGroupMemberData.ksParam_tsEffective, '' if oMember is None else oMember.tsEffective, sPrefix, TestGroupMemberData.ksParam_uidAuthor, '' if oMember is None else oMember.uidAuthor, TestGroupDataEx.ksParam_aoMembers, '' if oMember is None else ' checked', sCheckBoxAttr, oTestCase.idTestCase, oTestCase.idTestCase, escapeElem(oTestCase.sName), )); self._add(' \n' % ( len(oTestCase.aoTestCaseArgs), escapeElem(oTestCase.sName), )); self._add(' \n' % ( len(oTestCase.aoTestCaseArgs), sPrefix, TestGroupMemberData.ksParam_aidTestCaseArgs, ' checked' if oMember is None or oMember.aidTestCaseArgs is None else '', sCheckBoxAttr, )); self._add(' \n' % ( len(oTestCase.aoTestCaseArgs), sPrefix, TestGroupMemberData.ksParam_iSchedPriority, (oMember if oMember is not None else oDefMember).iSchedPriority, ' readonly class="tmform-input-readonly"' if fReadOnly else '', )); # Argument variations. aidTestCaseArgs = [] if oMember is None or oMember.aidTestCaseArgs is None else oMember.aidTestCaseArgs; for iVar in range(len(oTestCase.aoTestCaseArgs)): oVar = oTestCase.aoTestCaseArgs[iVar]; if iVar > 0: self._add(' \n' % ('tmodd' if iTestCase & 1 else 'tmeven',)); self._add(' \n' % ( sPrefix, TestGroupMemberData.ksParam_aidTestCaseArgs, ' checked' if oVar.idTestCaseArgs in aidTestCaseArgs else '', sCheckBoxAttr, oVar.idTestCaseArgs, )); self._add(' \n' ' \n' ' \n' % ( oVar.cGangMembers, 'Default' if oVar.cSecTimeout is None else oVar.cSecTimeout, escapeElem(oVar.sArgs) )); self._add(' \n'); if len(oTestCase.aoTestCaseArgs) == 0: self._add(' \n' ' \n'); return self._add(' \n' '
    Test CaseAll VarsPriority [0..31]Variations
    IncludedGang sizeTimeoutArguments
    \n' ' \n' # idTestCase ' \n' # idTestGroup ' \n' # tsExpire ' \n' # tsEffective ' \n' # uidAuthor ' \n' # (list) ' %s\n' ' \n' ' \n' ' \n' '
    \n' ' ' ' %s%s%s
    \n'); def addListOfSchedGroupMembers(self, sName, aoSchedGroupMembers, aoAllTestGroups, # pylint: disable=R0914 sLabel, fReadOnly = True): """ For WuiAdminSchedGroup. """ if self._fReadOnly: fReadOnly = True; assert len(aoSchedGroupMembers) <= len(aoAllTestGroups); self._addLabel(sName, sLabel); if len(aoAllTestGroups) == 0: return self._add('
  • No test groups available.
  • \n') self._add('\n' % ( SchedGroupDataEx.ksParam_aidTestGroups, ','.join([str(oTestGroup.idTestGroup) for oTestGroup in aoAllTestGroups]), )); self._add('\n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ' \n' ); sCheckBoxAttr = ' readonly onclick="return false" onkeydown="return false"' if fReadOnly else ''; sComboBoxAttr = ' disabled' if fReadOnly else ''; oDefMember = SchedGroupMemberData(); aoSchedGroupMembers = list(aoSchedGroupMembers); # Copy it so we can pop. for iTestGroup in range(len(aoAllTestGroups)): oTestGroup = aoAllTestGroups[iTestGroup]; # Is it a member? oMember = None; for i in range(len(aoSchedGroupMembers)): if aoSchedGroupMembers[i].oTestGroup.idTestGroup == oTestGroup.idTestGroup: oMember = aoSchedGroupMembers.pop(i); break; # Start on the rows... sPrefix = '%s[%d]' % (sName, oTestGroup.idTestGroup,); self._add(' \n' ' \n' % ( 'tmodd' if iTestGroup & 1 else 'tmeven', sPrefix, SchedGroupMemberData.ksParam_idTestGroup, oTestGroup.idTestGroup, sPrefix, SchedGroupMemberData.ksParam_idSchedGroup, -1 if oMember is None else oMember.idSchedGroup, sPrefix, SchedGroupMemberData.ksParam_tsExpire, '' if oMember is None else oMember.tsExpire, sPrefix, SchedGroupMemberData.ksParam_tsEffective, '' if oMember is None else oMember.tsEffective, sPrefix, SchedGroupMemberData.ksParam_uidAuthor, '' if oMember is None else oMember.uidAuthor, SchedGroupDataEx.ksParam_aoMembers, '' if oMember is None else ' checked', sCheckBoxAttr, oTestGroup.idTestGroup, oTestGroup.idTestGroup, escapeElem(oTestGroup.sName), )); self._add(' \n' % ( escapeElem(oTestGroup.sName), )); self._add(' \n' % ( sPrefix, SchedGroupMemberData.ksParam_iSchedPriority, (oMember if oMember is not None else oDefMember).iSchedPriority, ' readonly class="tmform-input-readonly"' if fReadOnly else '', )); self._add(' \n'); self._add(' \n' % ( sPrefix, SchedGroupMemberData.ksParam_bmHourlySchedule, '' if oMember is None else oMember.bmHourlySchedule, )); self._add(' \n'); return self._add(' \n' '
    Test GroupPriority [0..31]Prerequisite Test GroupWeekly schedule
    \n' ' \n' # idTestGroup ' \n' # idSchedGroup ' \n' # tsExpire ' \n' # tsEffective ' \n' # uidAuthor ' \n' # (list) ' %s\n' ' \n' ' \n' ' \n' ' \n' ' Todo\n' '
    \n'); # # Buttons. # def addSubmit(self, sLabel = 'Submit'): """Adds the submit button to the form.""" if self._fReadOnly: return True; return self._add('
  • \n' '
    \n' '
    \n' ' \n' ' \n' '
    \n' '
  • \n' % (escapeElem(sLabel),)); def addReset(self): """Adds a reset button to the form.""" if self._fReadOnly: return True; return self._add('
  • \n' '
    \n' ' \n' '
    \n' '
  • \n' );