Signed-off-by: Francois Gouget fgouget@codeweavers.com --- Again no impact on the website since only the POD documentation changes. With this groundwork in place the framework improvements will then resume. --- .../lib/ObjectModel/CGI/CollectionBlock.pm | 87 +++++++++- .../ObjectModel/CGI/CollectionBlockForPage.pm | 4 + testbot/lib/ObjectModel/CGI/CollectionPage.pm | 8 + testbot/lib/ObjectModel/CGI/FormPage.pm | 158 +++++++++++++++++- testbot/lib/ObjectModel/CGI/ItemPage.pm | 4 +- testbot/lib/ObjectModel/CGI/Page.pm | 68 +++++++- testbot/lib/WineTestBot/CGI/PageBase.pm | 40 ++++- 7 files changed, 359 insertions(+), 10 deletions(-)
diff --git a/testbot/lib/ObjectModel/CGI/CollectionBlock.pm b/testbot/lib/ObjectModel/CGI/CollectionBlock.pm index 13bbc4c3f..6f5c4d5fa 100644 --- a/testbot/lib/ObjectModel/CGI/CollectionBlock.pm +++ b/testbot/lib/ObjectModel/CGI/CollectionBlock.pm @@ -2,6 +2,7 @@ # Base class for list blocks # # Copyright 2009 Ge van Geldorp +# Copyright 2014, 2018, 2021-2022 Francois Gouget # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,45 @@ use strict;
ObjectModel::CGI::CollectionBlock - Base class for list blocks
+Generates a table representing the items contained in the specified collection +and provides support for: +- Linking to a page providing a detailed view of a given item. +- Selecting individual items and performing an action on them. + See GetItemActions() and OnItemActions(). +- Performing a global action. See GetActions() and OnAction(). + +Note that a web page may contain multiple collection blocks. + +Also, because this is only one part of a web page, some methods, such as those +dealing with errors, are delegated to the EnclosingPage object which must +implement the ObjectModel::CGI::Page interface. + +Other methods are designed so they can be overriden by the enclosing page as +a way to allow it to modify how the collection block looks or behaves. These +methods can be identified by their CallXxx() trampoline. The override +mechanism works as follows: +- The CollectionBlock class and any subclass should never call overridable + methods directly. Instead they should call the corresponding CallXxx() + trampoline. +- The CollectionBlock class provides a default CallXxx() implementation which + simply calls the corresponding Xxx() method. This allows using the + CollectionBlock as is. +- Pages that want to customize the CollectionBlock behavior should use the + CollectionBlockForPage class instead. That class provides an alternative + implementation for each CallXxx(...) method that calls + $self->{EnclosingPage}->Xxx($CollectionBlock, ...). Note how the Xxx() + method in the enclosing page gets an extra parameter so it can both know + which collection block it received the call from, and call the collection + block methods. +- The page should in turn provide implementations for all the Xxx() methods. + The simplest way to do so is for such pages use CollectionPage as their base + class. CollectionPage provides default Xxx($CollectionBlock,...) + implementations that just reflect these calls back to + $CollectionBlock->Xxx(). + +Of course an alternative way for a page to customize the collection block +behavior is to subclass it and use that subclass instead. + =cut
package ObjectModel::CGI::CollectionBlock; @@ -103,6 +143,19 @@ sub CallDisplayProperty($$) return $self->DisplayProperty($PropertyDescriptor); }
+=pod +=over 12 + +=item C<DisplayProperty()> + +Specifies whether to hide the given property. + +Any value evaluating to false specifies that the property should be hidden and +all others that it should be shown. + +=back +=cut + sub DisplayProperty($$) { my ($self, $PropertyDescriptor) = @_; @@ -142,6 +195,7 @@ sub GetDisplayValue($$$) { if (defined($Value)) { + # Note: This only supports single-key Itemrefs foreach $PropertyDescriptor (@{$Value->GetPropertyDescriptors()}) { if ($PropertyDescriptor->GetIsKey()) @@ -517,9 +571,12 @@ sub CallGetItemActions($)
Returns the list of per-item actions.
-This is a set of actions that is applied to each selected item in the +This is a set of actions that can be applied to each selected item in the collection.
+If the set is empty the GUI will provide no way to select items. Otherwise a +column of checkboxes is added. + =back =cut
@@ -536,6 +593,19 @@ sub CallOnItemAction($$$) return $self->OnItemAction($Item, $Action); }
+=pod +=over 12 + +=item C<OnItemAction()> + +This method is called to apply $Action to each selected item. + +Note that it is the responsibility of this method to validate the property +values by calling Validate() before performing the action. + +=back +=cut + sub OnItemAction($$$) { my ($self, $Item, $Action) = @_; @@ -588,6 +658,21 @@ sub GetActions($) return @Actions; }
+=pod +=over 12 + +=item C<OnAction()> + +Implements the "Add" and per-item actions. + +Note that it is the responsibility of this method to validate the property +values by calling Validate() before performing the action. + +=back +=cut + +# Note that there is no call to OnAction() in the CollectionBlock class so +# there is no need for a CallOnAction() trampoline. sub OnAction($$) { my ($self, $Action) = @_; diff --git a/testbot/lib/ObjectModel/CGI/CollectionBlockForPage.pm b/testbot/lib/ObjectModel/CGI/CollectionBlockForPage.pm index 94d5f8672..5bdc7d32e 100644 --- a/testbot/lib/ObjectModel/CGI/CollectionBlockForPage.pm +++ b/testbot/lib/ObjectModel/CGI/CollectionBlockForPage.pm @@ -2,6 +2,7 @@ # Collection block for list pages # # Copyright 2009 Ge van Geldorp +# Copyright 2014, 2017-2018, 2022 Francois Gouget # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,6 +26,9 @@ package ObjectModel::CGI::CollectionBlockForPage;
ObjectModel::CGI::CollectionBlockForPage - Collection block for list pages
+Allows the CollectionPage class to provide implementations for most of the +CollectionBlock methods. See CollectionBlock for details. + =cut
use ObjectModel::CGI::CollectionBlock; diff --git a/testbot/lib/ObjectModel/CGI/CollectionPage.pm b/testbot/lib/ObjectModel/CGI/CollectionPage.pm index 993f18685..d59310be5 100644 --- a/testbot/lib/ObjectModel/CGI/CollectionPage.pm +++ b/testbot/lib/ObjectModel/CGI/CollectionPage.pm @@ -2,6 +2,7 @@ # Base class for list pages # # Copyright 2009 Ge van Geldorp +# Copyright 2014, 2017-2018, 2022 Francois Gouget # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,6 +26,13 @@ package ObjectModel::CGI::CollectionPage;
ObjectModel::CGI::CollectionPage - Base class for list pages
+Generates a page containing a single collection block. + +It uses the CollectionBlockForPage class which means CollectionPage implements +both the ObjectModel::CGI::Page and ObjectModel::CGI::CollectionBlock +interfaces. The latter allows it to customize the collection block without +having to define a CollectionBlock subclass. + =cut
use ObjectModel::CGI::Page; diff --git a/testbot/lib/ObjectModel/CGI/FormPage.pm b/testbot/lib/ObjectModel/CGI/FormPage.pm index 588ea55b7..9e34a736d 100644 --- a/testbot/lib/ObjectModel/CGI/FormPage.pm +++ b/testbot/lib/ObjectModel/CGI/FormPage.pm @@ -2,7 +2,7 @@ # Base class for web pages containing a form # # Copyright 2009 Ge van Geldorp -# Copyright 2012 Francois Gouget +# Copyright 2012, 2014, 2017-2018, 2022 Francois Gouget # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -26,12 +26,55 @@ package ObjectModel::CGI::FormPage;
ObjectModel::CGI::FormPage - Base class for web forms
+This class generates a page that: +- Displays a list of properties, allows editing them, or a mix of both. +- Provides a list of actions that can be applied after visualizing or editing + the properties. +- Provides the framework for validating the property values and saving them. + +This page has the following properties: +=over + +=item Method +Specifies how to send the CGI parameters for the property values (get or post). + +=item HasRequired +True if the form has fields that are mandatory. + +=item ActionPerformed +True if an action was specified and performed. + +=back + +A typical use takes this form: + +my $PropertyDescriptors = [ ... ]; +my $MyFormPage = MyFormPage->new($Request, "required-privileges", $PropertyDescriptors); +$MyFormPage->GeneratePage(); + =cut
use ObjectModel::CGI::Page; our @ISA = qw(ObjectModel::CGI::Page);
+=pod +=over 12 + +=item C<_initialize()> + +This method is called by the constructor to initialize the form page. + +The PropertyDescriptors parameter specifies a reference to the list of +properties that the form should show or allow editing, as specified by +DisplayProperty(). It may be undefined if determining the property list is +delegated to GetPropertyDescriptors(). + +See also Page::new(). + +=back +=cut + sub _initialize($$$$) { my ($self, $Request, $RequiredRole, $PropertyDescriptors) = @_; @@ -49,6 +92,20 @@ sub _initialize($$$$) # Property handling #
+=pod +=over 12 + +=item C<GetPropertyDescriptors()> + +Returns a reference to a list of ObjectModel::PropertyDescriptor objects +describing the fields to be displayed / edited. This also defines the set of +CGI parameters that the page supports. + +This must not return undef. + +=back +=cut + sub GetPropertyDescriptors($) { my ($self) = @_; @@ -72,6 +129,32 @@ sub GetPropertyDescriptorByName($$) return undef; }
+=pod +=over 12 + +=item C<DisplayProperty()> + +Specifies whether to hide, display or allow editing the given property. + +Return values: +=over +=item "" +Any value evaluating to false specifies that the property should be hidden. + +=item "ro" +Specifies that the property is read-only, i.e. GenerateField() should display +it instead of generating an edit field. + +=item "rw" +Specifies that GenerateField() should allow editing the property. +Note that this implies that $PropertyDescriptor->GetName() should be a valid +HTTP parameter name. + +=back + +=back +=cut + sub DisplayProperty($$) { my ($self, $PropertyDescriptor) = @_; @@ -92,6 +175,20 @@ sub DisplayProperty($$) "ro"; }
+=pod +=over 12 + +=item C<GetPropertyValue()> + +Returns the underlying property value. + +This is used to initialize the form with the properties of the 'object' to be +modified or displayed. The default implementation considers that there is no +underlying value. + +=back +=cut + sub GetPropertyValue($$) { #my ($self, $PropertyDescriptor) = @_; @@ -135,6 +232,17 @@ sub GetInputType($$) "text"; }
+=pod +=over 12 + +=item C<GenerateRequired()> + +Generates an HTML snippet to be put next to an input field to indicate it must +be set. + +=back +=cut + sub GenerateRequired($$) { my ($self, $PropertyDescriptor) = @_; @@ -356,6 +464,26 @@ sub GeneratePage($) # Validating and saving the form content #
+=pod +=over 12 + +=item C<Validate()> + +Validates the property values. + +Note that this method is not called in the default implementation. Subclasses +would likely want to call it in OnAction() or possibly in _initialize() after +having set up the property descriptors list. + +The default implementation only checks the individual property values using +the corresponding property descriptor's ValidateValue() method. + +Any cross-property consistency checks should be done by redefining this method +in subclasses. + +=back +=cut + sub Validate($) { my ($self) = @_; @@ -419,6 +547,20 @@ sub Save($) # Actions handling #
+=pod +=over 12 + +=item C<GetActions()> + +Returns a list of actions that can be applied after completing or reading this +form. Each action is a string which is used as the label of a button at the +bottom of the form. + +By default there is no action. + +=back +=cut + sub GetActions($) { #my ($self) = @_; @@ -437,6 +579,20 @@ sub GenerateActions($) print "</div>\n"; }
+=pod +=over 12 + +=item C<OnAction()> + +This method should be redefined in subclasses to implement the supported +actions. + +Note that it is the responsibility of this method to validate the property +values by calling Validate() before performing the action. + +=back +=cut + sub OnAction($$) { my ($self, $Action) = @_; diff --git a/testbot/lib/ObjectModel/CGI/ItemPage.pm b/testbot/lib/ObjectModel/CGI/ItemPage.pm index c0105f7d6..66fcab755 100644 --- a/testbot/lib/ObjectModel/CGI/ItemPage.pm +++ b/testbot/lib/ObjectModel/CGI/ItemPage.pm @@ -1,8 +1,8 @@ # -*- Mode: Perl; perl-indent-level: 2; indent-tabs-mode: nil -*- -# Base class for web pages containing a db bound form +# Base class for web pages containing a DB bound form # # Copyright 2009 Ge van Geldorp -# Copyright 2012 Francois Gouget +# Copyright 2012-2014, 2017-2018, 2022 Francois Gouget # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public diff --git a/testbot/lib/ObjectModel/CGI/Page.pm b/testbot/lib/ObjectModel/CGI/Page.pm index 1e8f55d31..d5988803c 100644 --- a/testbot/lib/ObjectModel/CGI/Page.pm +++ b/testbot/lib/ObjectModel/CGI/Page.pm @@ -2,6 +2,7 @@ # Base class for web pages # # Copyright 2009 Ge van Geldorp +# Copyright 2012, 2014, 2017-2018, 2022 Francois Gouget # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,6 +26,29 @@ package ObjectModel::CGI::Page;
ObjectModel::CGI::Page - Base class for web pages
+This class provide a generic framework for generating web pages: retrieving +the HTTP parameters, manipulating cookies, checking the session, handling +errors, generating the HTTP header, etc. + +It also defines their general structure: they shall be composed of a header, a +body and a footer. That structure can then be further refined by child classes +to suit their needs. + +What it does not do is define what the page should look like: what the banner +should contain, which CSS files to reference, how to navigate from one page to +another, etc. It also does not define how to check that the user is allowed to +access the page or how to display error messages. + +All these "look and feel" aspects are delegated to the PageBase object. Thus +many methods are just trampolines to their PageBase equivalent such that child +classes can call them and automatically get the appropriate behavior for the +actual website. + +A typical use takes this form: + +my $MyPage = MyPage->new($Request, "required-privileges"); +$MyPage->GeneratePage(); + =cut
use Exporter 'import'; @@ -35,6 +59,29 @@ use CGI;
my $PageBaseCreator;
+ +=pod +=over 12 + +=item C<new()> + +Creates a new page object. + +Parameters: +=over +=item Request +This is the HTTP request leading to this page. + +=item RequiredRole +This is a string specifying which users can access this page. + +=back + +Both parameters are passed to the PageBase constructor. + +=back +=cut + sub new($$$@) { my $class = shift; @@ -55,6 +102,19 @@ sub _initialize($$$) #my ($self, $Request, $RequiredRole) = @_; }
+=pod +=over 12 + +=item C<SetPageBaseCreator()> + +Sets the function to be used to instantiate a new PageBase object for this +website. The resulting object can be accessed through GetPageBase(). + +See also ObjectModel::CGI::PageBase. + +=back +=cut + sub SetPageBaseCreator($) { ($PageBaseCreator) = @_; @@ -108,7 +168,7 @@ sub GetParamNames($)
=head1 C<GetParam()>
-Returns the specified parameter. +Returns the specified parameter value. Note that unlike CGI::param() this forces the result to scalar context to avoid security issues.
@@ -153,7 +213,7 @@ sub SetParam($$$)
# -# Session support +# Session management #
sub UnsetCookies($) @@ -235,7 +295,7 @@ sub GenerateErrorPopup($) =head1 C<GetPageTitle()>
This returns the page title as put in the HTML header. -Note that this may not be valid HTML and thus need escaping. +Note that this may not be valid HTML and thus may need escaping.
=back =cut @@ -253,7 +313,7 @@ sub GetPageTitle($) =head1 C<GetTitle()>
This returns the title for the current web page or email section. -Note that this may not be valid HTML and thus need escaping. +Note that this may not be valid HTML and thus my need escaping.
=back =cut diff --git a/testbot/lib/WineTestBot/CGI/PageBase.pm b/testbot/lib/WineTestBot/CGI/PageBase.pm index b36b28d9a..6d94ae967 100644 --- a/testbot/lib/WineTestBot/CGI/PageBase.pm +++ b/testbot/lib/WineTestBot/CGI/PageBase.pm @@ -3,6 +3,7 @@ # # Copyright 2009 Ge van Geldorp # Copyright 2010 VMware, Inc. +# Copyright 2012-2014, 2017-2020, 2022 Francois Gouget # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -24,7 +25,13 @@ package WineTestBot::CGI::PageBase;
=head1 NAME
-WineTestBot::CGI::PageBase - Base class for web pages +WineTestBot::CGI::PageBase - Common boilerplate for the WineTestBot web pages + +This class defines the elements common to all the TestBot pages. + +This includes services such as how to check the user session and how to +display errors. And it also defines the general look and feel of the page by +providing a common banner, navigation menu and cascading style sheets.
=cut
@@ -39,6 +46,35 @@ use WineTestBot::CGI::Sessions; use WineTestBot::Config; use WineTestBot::Utils;
+ +=pod +=over 12 + +=item C<new()> + +Creates a PageBase object for the specified web page. + +Parameters: +=over +=Page +This is the page that lead to the creation of this PageBase object. + +=item Request +This is the HTTP request leading to this page. + +=item RequiredRole +This is a role that the user must have in order to be allowed to access this +page (see UserRoles). + +For instance an empty string specifies that any user can access the page, +even users with no account; while "admin" would specify that only logged-in +users with the "admin" role can access it. + +=back + +=back +=cut + sub new($$$$@) { my $class = shift; @@ -77,7 +113,7 @@ sub CreatePageBase($$$@)
# -# Session support +# Session management #
sub UnsetCookies($)