Rewrite Menu module, to integrate it in Portal (#29)

This commit is contained in:
Clément Oudot 2010-09-16 15:10:00 +00:00
parent b658c3df43
commit d7fb73b2e2
7 changed files with 142 additions and 224 deletions

View File

@ -75,41 +75,26 @@ if ( $portal->process() ) {
# 1.3 Case : display menu # 1.3 Case : display menu
else { else {
$skinfile = 'menu.tpl';
# Menu creation # Initialize menu elements
use Lemonldap::NG::Portal::Menu; $portal->_sub('menuInit');
my $menu = Lemonldap::NG::Portal::Menu->new(
{ $skinfile = 'menu2.tpl';
portalObject => $portal,
modules => {
appslist => $portal->{portalDisplayAppslist},
password => $portal->{portalDisplayChangePassword},
logout => $portal->{portalDisplayLogout},
},
}
);
%templateParams = ( %templateParams = (
AUTH_USER => $portal->{sessionInfo}->{ $portal->{portalUserAttr} }, AUTH_USER => $portal->{sessionInfo}->{ $portal->{portalUserAttr} },
AUTOCOMPLETE => $portal->{portalAutocomplete}, AUTOCOMPLETE => $portal->{portalAutocomplete},
SKIN => $skin, SKIN => $skin,
AUTH_ERROR => $portal->error, AUTH_ERROR => $portal->error( undef, $portal->{menuError} ),
AUTH_ERROR_TYPE => $portal->error_type, AUTH_ERROR_TYPE => $portal->error_type( $portal->{menuError} ),
DISPLAY_APPSLIST => $menu->displayModule("appslist"), DISPLAY_TAB => $portal->{menuDisplayTab},
DISPLAY_PASSWORD => $menu->displayModule("password"),
DISPLAY_LOGOUT => $menu->displayModule("logout"),
DISPLAY_TAB => $menu->displayTab,
LOGOUT_URL => "$ENV{SCRIPT_NAME}?logout=1", LOGOUT_URL => "$ENV{SCRIPT_NAME}?logout=1",
REQUIRE_OLDPASSWORD => $portal->{portalRequireOldPassword}, REQUIRE_OLDPASSWORD => $portal->{portalRequireOldPassword},
DISPLAY_MODULES => $portal->{menuDisplayModules},
APPSLIST_MENU => $portal->{menuAppslistMenu},
APPSLIST_DESC => $portal->{menuAppslistDesc},
); );
if ( $menu->displayModule("appslist") ) {
%templateParams = (
%templateParams,
APPSLIST_MENU => $menu->appslistMenu,
APPSLIST_DESC => $menu->appslistDescription
);
}
} }
} }

View File

@ -101,8 +101,12 @@
</TMPL_IF> </TMPL_IF>
<TMPL_IF NAME="DISPLAY_PASSWORD">
<TMPL_INCLUDE NAME="password.tpl"> <TMPL_INCLUDE NAME="password.tpl">
</TMPL_IF>
<TMPL_IF NAME="LOGIN_INFO"> <TMPL_IF NAME="LOGIN_INFO">
<div class="login_info"> <div class="login_info">
<TMPL_VAR NAME="LOGIN_INFO"> <TMPL_VAR NAME="LOGIN_INFO">

View File

@ -8,30 +8,47 @@
<div class="user"><lang en="Connected as" fr="Connect&eacute; en tant que" /> <TMPL_VAR NAME="AUTH_USER"></div> <div class="user"><lang en="Connected as" fr="Connect&eacute; en tant que" /> <TMPL_VAR NAME="AUTH_USER"></div>
<TMPL_IF DISPLAY_MODULES>
<!-- Tabs list -->
<ul> <ul>
<TMPL_IF NAME="DISPLAY_APPSLIST"> <TMPL_LOOP NAME="DISPLAY_MODULES">
<TMPL_IF NAME="Appslist">
<li><a href="#appslist"><span><img src="/skins/common/application_cascade.png" width="16" height="16" alt="appslist" /> <lang en="Your applications" fr="Vos applications" /></span></a></li> <li><a href="#appslist"><span><img src="/skins/common/application_cascade.png" width="16" height="16" alt="appslist" /> <lang en="Your applications" fr="Vos applications" /></span></a></li>
</TMPL_IF> </TMPL_IF>
<TMPL_IF NAME="DISPLAY_PASSWORD"> <TMPL_IF NAME="ChangePassword">
<li><a href="#password"><span><img src="/skins/common/vcard_edit.png" width="16" height="16" alt="password" /> <lang en="Password" fr="Mot de passe" /></span></a></li> <li><a href="#password"><span><img src="/skins/common/vcard_edit.png" width="16" height="16" alt="password" /> <lang en="Password" fr="Mot de passe" /></span></a></li>
</TMPL_IF> </TMPL_IF>
<TMPL_IF NAME="DISPLAY_LOGOUT"> <TMPL_IF NAME="Logout">
<li><a href="#logout"><span><img src="/skins/common/door_out.png" width="16" height="16" alt="logout" /> <lang en="Logout" fr="D&eacute;connexion" /></span></a></li> <li><a href="#logout"><span><img src="/skins/common/door_out.png" width="16" height="16" alt="logout" /> <lang en="Logout" fr="D&eacute;connexion" /></span></a></li>
</TMPL_IF> </TMPL_IF>
</TMPL_LOOP>
</ul> </ul>
</TMPL_IF>
<div class="menulogo"></div> <div class="menulogo"></div>
<TMPL_IF NAME="DISPLAY_APPSLIST"> <!-- Tabs content -->
<TMPL_LOOP NAME="DISPLAY_MODULES">
<TMPL_IF NAME="Appslist">
<!-- The old fashion -->
<div id="appslist"> <div id="appslist">
<TMPL_VAR NAME="APPSLIST_MENU"> <TMPL_VAR NAME="APPSLIST_MENU">
<TMPL_VAR NAME="APPSLIST_DESC"> <TMPL_VAR NAME="APPSLIST_DESC">
</div> </div>
<!-- TODO use LOOPS -->
</TMPL_IF> </TMPL_IF>
<TMPL_IF NAME="ChangePassword">
<TMPL_INCLUDE NAME="password.tpl"> <TMPL_INCLUDE NAME="password.tpl">
</TMPL_IF>
<TMPL_IF NAME="DISPLAY_LOGOUT"> <TMPL_IF NAME="Logout">
<div id="logout"> <div id="logout">
<h3><lang en="Are you sure ?" fr="&Ecirc;tes vous s&ucirc;r ?" /></h3> <h3><lang en="Are you sure ?" fr="&Ecirc;tes vous s&ucirc;r ?" /></h3>
<div class="buttons"> <div class="buttons">
@ -41,6 +58,9 @@
</div> </div>
</div> </div>
</TMPL_IF> </TMPL_IF>
</TMPL_LOOP>
</div> </div>
</div> </div>

View File

@ -1,4 +1,3 @@
<TMPL_IF NAME="DISPLAY_PASSWORD">
<div id="password"> <div id="password">
<form action="#" method="post" class="password"> <form action="#" method="post" class="password">
<h3><lang en="Change your password" fr="Changez votre mot de passe" /></h3> <h3><lang en="Change your password" fr="Changez votre mot de passe" /></h3>
@ -29,4 +28,3 @@
</td></tr></table> </td></tr></table>
</form> </form>
</div> </div>
</TMPL_IF>

View File

@ -7,143 +7,48 @@ package Lemonldap::NG::Portal::Menu;
use strict; use strict;
use warnings; use warnings;
require Lemonldap::NG::Common::CGI; use Lemonldap::NG::Portal::Simple;
use Lemonldap::NG::Portal::SharedConf;
use Lemonldap::NG::Common::Safelib; #link protected safe Safe object use Lemonldap::NG::Common::Safelib; #link protected safe Safe object
use Safe; use Safe;
use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 ); use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 );
#inherits Net::LDAP::Control::PasswordPolicy our $VERSION = '0.4';
our $VERSION = '0.3'; # Global variables
our ( $defaultCondition, $locationCondition, $locationRegexp, $cfgNum,
$catlevel ) = ( undef, undef, undef, 0, 0 );
### ACCESS CONTROL DISPLAY SYSTEM ## @method void menuInit()
# Prepare menu template elements
our ( $defaultCondition, $locationCondition, $locationRegexp, $cfgNum, $path ) = # @return nothing
( undef, undef, undef, 0 ); sub menuInit {
## @method private Safe _safe()
# Build and returns security jail.
# Includes custom functions
# @return Safe object
sub _safe {
my $self = shift; my $self = shift;
return $self->{_safe} if ( $self->{_safe} );
$self->{_safe} = new Safe;
$self->{customFunctions} ||= $self->{portalObject}->{customFunctions};
my @t =
$self->{customFunctions} ? split( /\s+/, $self->{customFunctions} ) : ();
foreach (@t) {
my $sub = $_;
unless (/::/) {
$sub = "$self->{caller}::$_";
}
else {
s/^.*:://;
}
next if ( __PACKAGE__->can($_) );
eval "sub $_ {
return $sub(\$path,\@_);
}";
$self->{portalObject}->lmLog( $@, 'error' ) if ($@);
}
$self->{_safe}->share_from( 'main', ['%ENV'] );
$self->{_safe}->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$self->{_safe}->share( '&encode_base64', @t );
return $self->{_safe};
}
my $catlevel = 0;
##@cmethod Lemonldap::NG::Portal::Menu new(hashRef args)
# Constructor.
# $args->{portalObject} is required.
#@param $args hash reference
#@return new object
sub new {
my $class = shift;
my $self = {};
bless( $self, $class );
# Get configuration
$self->Lemonldap::NG::Portal::Simple::getConf(@_)
or Lemonldap::NG::Common::CGI->abort(
"Unable to read $class->new() parameters");
# Portal is required
Lemonldap::NG::Common::CGI->abort("Portal object required")
unless ( $self->{portalObject} );
# Fill sessionInfo (yet done in portal...)
#&Lemonldap::NG::Portal::Simple::getSessionInfo( $self->{portalObject} );
# Default values
$self->{apps}->{imgpath} ||= '/apps/'; $self->{apps}->{imgpath} ||= '/apps/';
$self->{modules}->{appslist} = 0
unless defined $self->{modules}->{appslist};
$self->{modules}->{password} = 0
unless defined $self->{modules}->{password};
$self->{modules}->{logout} = 1 unless defined $self->{modules}->{logout};
$self->{'caller'} = caller;
# Store POST data in $self->{portalObject} # Modules to display
$self->{portalObject}->{'newpassword'} = $self->{menuModules} ||= "Appslist ChangePassword Logout";
$self->{portalObject}->param('newpassword'); $self->{menuDisplayModules} = $self->displayModules();
$self->{portalObject}->{'confirmpassword'} =
$self->{portalObject}->param('confirmpassword');
$self->{portalObject}->{'oldpassword'} =
$self->{portalObject}->param('oldpassword');
$self->{portalObject}->{'dn'} =
$self->{portalObject}->{sessionInfo}->{'dn'};
$self->{portalObject}->{'user'} =
$self->{portalObject}->{sessionInfo}->{'_user'};
# Change password (only if newpassword submitted) # Extract password from POST data
$self->{portalObject}->{error} = $self->{oldpassword} = $self->param('oldpassword');
$self->{portalObject}->_subProcess(qw(passwordDBInit modifyPassword)) $self->{newpassword} = $self->param('newpassword');
if $self->{portalObject}->{'newpassword'}; $self->{confirmpassword} = $self->param('confirmpassword');
$self->{dn} = $self->{sessionInfo}->{dn};
$self->{user} = $self->{sessionInfo}->{_user};
return $self; # Try to change password
} $self->{menuError} = $self->_subProcess(qw(passwordDBInit modifyPassword));
## @method boolean displayModule(string modulename) # Default menu error code
# Return true if the user can see the module. $self->{menuError} ||= $self->{error};
# Use for HTML::Template variable.
# @param $modulename string
# @return boolean
sub displayModule {
my ( $self, $modulename ) = splice @_;
# Manage "0" and "1" rules # Tab to display
return 1 if ( $self->{modules}->{$modulename} eq "1" ); $self->{menuDisplayTab} = "appslist";
return 0 if ( $self->{modules}->{$modulename} eq "0" ); $self->{menuDisplayTab} = "password"
# Else parse display condition
my $cond = $self->{modules}->{$modulename};
$cond =~ s/\$(\w+)/$self->{portalObject}->{sessionInfo}->{$1}/g;
return (
SAFEWRAP
? $self->_safe->wrap_code_ref(
$self->_safe->reval("sub{return($cond)}")
)
: $self->_safe->reval("sub{return($cond)}")
);
}
## @method string displayTab()
# Tells which tab should be selected.
# Design for Jquery tabs.
# @return password, appslist or logout
sub displayTab {
my $self = shift;
# Display password tab if password change is needed or failed
return "password"
if ( if (
( (
scalar( scalar(
grep { $_ == $self->{portalObject}->{error} } ( grep { $_ == $self->{menuError} } (
25, #PE_PP_CHANGE_AFTER_RESET 25, #PE_PP_CHANGE_AFTER_RESET
27, #PE_PP_MUST_SUPPLY_OLD_PASSWORD 27, #PE_PP_MUST_SUPPLY_OLD_PASSWORD
28, #PE_PP_INSUFFICIENT_PASSWORD_QUALITY 28, #PE_PP_INSUFFICIENT_PASSWORD_QUALITY
@ -157,11 +62,40 @@ sub displayTab {
) )
) )
) )
&& $self->displayModule("password")
); );
return "appslist" if ( $self->displayModule("appslist") ); # Application list
return "logout"; $self->{menuAppslistMenu} = $self->appslistMenu();
$self->{menuAppslistDesc} = $self->appslistDescription();
return;
}
## @method arrayref displayModules()
# List modules that can be displayed in Menu
# @return modules list
sub displayModules {
my $self = shift;
my $displayModules = [];
# Modules list
my @modules = split( /\s/, $self->{menuModules} );
# Foreach module, eval condition
# Store module in result if condition is valid
foreach my $module (@modules) {
my $cond = $self->{ 'portalDisplay' . $module };
$cond = 1 unless defined $cond;
$cond =~ s/\$(\w+)/$self->{sessionInfo}->{$1}/g;
$self->lmLog( "Evaluate condition $cond for module $module", 'debug' );
if ( $self->safe->reval($cond) ) {
push @$displayModules, { $module => 1 };
}
}
return $displayModules;
} }
## @method string appslistMenu() ## @method string appslistMenu()
@ -171,15 +105,15 @@ sub appslistMenu {
my $self = shift; my $self = shift;
# We no more use XML file for menu configuration # We no more use XML file for menu configuration
unless ( defined $self->{portalObject}->{applicationList} ) { unless ( defined $self->{applicationList} ) {
$self->{portalObject}->abort( $self->abort(
"XML menu configuration is deprecated", "XML menu configuration is deprecated",
"Please use lmMigrateConfFiles2ini to migrate your menu configuration" "Please use lmMigrateConfFiles2ini to migrate your menu configuration"
); );
} }
# Use configuration to get menu parameters # Use configuration to get menu parameters
my $applicationList = $self->{portalObject}->{applicationList}; my $applicationList = $self->{applicationList};
my $filteredList = $self->_filter($applicationList); my $filteredList = $self->_filter($applicationList);
return $self->_displayConfCategory( "", $applicationList, $catlevel ); return $self->_displayConfCategory( "", $applicationList, $catlevel );
} }
@ -191,8 +125,8 @@ sub appslistDescription {
my $self = shift; my $self = shift;
# We no more use XML file for menu configuration # We no more use XML file for menu configuration
unless ( defined $self->{portalObject}->{applicationList} ) { unless ( defined $self->{applicationList} ) {
$self->{portalObject}->lmLog( $self->lmLog(
"XML menu configuration is deprecated. Please use lmMigrateConfFiles2ini to migrate your menu configuration", "XML menu configuration is deprecated. Please use lmMigrateConfFiles2ini to migrate your menu configuration",
'error' 'error'
); );
@ -200,7 +134,7 @@ sub appslistDescription {
} }
# Use configuration to get menu parameters # Use configuration to get menu parameters
my $applicationList = $self->{portalObject}->{applicationList}; my $applicationList = $self->{applicationList};
return $self->_displayConfDescription( "", $applicationList ); return $self->_displayConfDescription( "", $applicationList );
} }
@ -257,16 +191,6 @@ sub _displayConfCategory {
return $html; return $html;
} }
## @method private string _userParam(string arg)
# Returns value of $arg variable stored in session.
# @param $arg string to modify
# @return string modified
sub _userParam {
my ( $self, $arg ) = splice @_;
$arg =~ s/\$([\w]+)/$self->{portalObject}->{sessionInfo}->{$1}/g;
return $arg;
}
## @method private string _displayConfApplication() ## @method private string _displayConfApplication()
# Creates HTML code for an application. # Creates HTML code for an application.
# @param $appid Application ID # @param $appid Application ID
@ -475,11 +399,11 @@ sub _isCategoryEmpty {
sub _grant { sub _grant {
my ( $self, $uri ) = splice @_; my ( $self, $uri ) = splice @_;
$uri =~ m{(\w+)://([^/:]+)(:\d+)?(/.*)?$} or return 0; $uri =~ m{(\w+)://([^/:]+)(:\d+)?(/.*)?$} or return 0;
my ( $protocol, $vhost, $port ); my ( $protocol, $vhost, $port, $path );
( $protocol, $vhost, $port, $path ) = ( $1, $2, $3, $4 ); ( $protocol, $vhost, $port, $path ) = ( $1, $2, $3, $4 );
$path ||= '/'; $path ||= '/';
$self->_compileRules() $self->_compileRules()
if ( $cfgNum != $self->{portalObject}->{cfgNum} ); if ( $cfgNum != $self->{cfgNum} );
return -1 unless ( defined( $defaultCondition->{$vhost} ) ); return -1 unless ( defined( $defaultCondition->{$vhost} ) );
if ( defined $locationRegexp->{$vhost} ) { # Not just a default rule if ( defined $locationRegexp->{$vhost} ) { # Not just a default rule
@ -490,8 +414,8 @@ sub _grant {
} }
} }
unless ( $defaultCondition->{$vhost} ) { unless ( $defaultCondition->{$vhost} ) {
$self->{portalObject} $self->lmLog(
->lmLog( "Application $uri did not match any configured virtual host", "Application $uri did not match any configured virtual host",
'warn' ); 'warn' );
return 0; return 0;
} }
@ -504,18 +428,18 @@ sub _grant {
# @return True # @return True
sub _compileRules { sub _compileRules {
my $self = shift; my $self = shift;
foreach my $vhost ( keys %{ $self->{portalObject}->{locationRules} } ) { foreach my $vhost ( keys %{ $self->{locationRules} } ) {
my $i = 0; my $i = 0;
foreach ( keys %{ $self->{portalObject}->{locationRules}->{$vhost} } ) { foreach ( keys %{ $self->{locationRules}->{$vhost} } ) {
if ( $_ eq 'default' ) { if ( $_ eq 'default' ) {
$defaultCondition->{$vhost} = $defaultCondition->{$vhost} =
$self->_conditionSub( $self->_conditionSub(
$self->{portalObject}->{locationRules}->{$vhost}->{$_} ); $self->{locationRules}->{$vhost}->{$_} );
} }
else { else {
$locationCondition->{$vhost}->[$i] = $locationCondition->{$vhost}->[$i] =
$self->_conditionSub( $self->_conditionSub(
$self->{portalObject}->{locationRules}->{$vhost}->{$_} ); $self->{locationRules}->{$vhost}->{$_} );
$locationRegexp->{$vhost}->[$i] = qr/$_/; $locationRegexp->{$vhost}->[$i] = qr/$_/;
$i++; $i++;
} }
@ -524,7 +448,7 @@ sub _compileRules {
# Default policy # Default policy
$defaultCondition->{$vhost} ||= $self->_conditionSub('accept'); $defaultCondition->{$vhost} ||= $self->_conditionSub('accept');
} }
$cfgNum = $self->{portalObject}->{cfgNum}; $cfgNum = $self->{cfgNum};
1; 1;
} }
@ -539,12 +463,12 @@ sub _conditionSub {
return sub { 0 } return sub { 0 }
if ( $cond =~ /^(?:deny$|logout)/i ); if ( $cond =~ /^(?:deny$|logout)/i );
$cond =~ s/\$date/&POSIX::strftime("%Y%m%d%H%M%S",localtime())/e; $cond =~ s/\$date/&POSIX::strftime("%Y%m%d%H%M%S",localtime())/e;
$cond =~ s/\$(\w+)/\$self->{portalObject}->{sessionInfo}->{$1}/g; $cond =~ s/\$(\w+)/\$self->{sessionInfo}->{$1}/g;
my $sub = "sub {my \$self = shift; return ( $cond )}"; my $sub = "sub {my \$self = shift; return ( $cond )}";
$sub = ( $sub = (
SAFEWRAP SAFEWRAP
? $self->_safe->wrap_code_ref( $self->_safe->reval($sub) ) ? $self->safe->wrap_code_ref( $self->safe->reval($sub) )
: $self->_safe->reval($sub) : $self->safe->reval($sub)
); );
return $sub; return $sub;
} }
@ -557,45 +481,23 @@ __END__
=encoding utf8 =encoding utf8
Lemonldap::NG::Portal::Menu - Enhanced menu to display to authenticated users Lemonldap::NG::Portal::Menu - Portal menu functions
=head1 SYNOPSIS =head1 SYNOPSIS
use Lemonldap::NG::Portal::Menu; use Lemonldap::NG::Portal::Simple;
my $menu = Lemonldap::NG::Portal::Menu->new( my $portal = Lemonldap::NG::Portal::Simple->new(
{ {
portalObject => $portal,
apps => {
xmlfile => "/var/lib/lemonldap-ng/conf/apps-list.xml",
imgpath => "apps/",
},
modules => {
appslist => 1,
password => 1,
logout => 1,
},
} }
); );
# Print HTML code of authorized applications list # Init portal menu
print $menu->appslistMenu; $portal->menuInit();
=head1 DESCRIPTION =head1 DESCRIPTION
Lemonldap::NG::Portal::Menu provides these web modules: Lemonldap::NG::Portal::Menu is used to build menu.
=over
=item * Application list: display a full menu with all authorized applications
=item * Password: allow the user to change its password (with LDAP auth only)
=item * Logout: display a simple logout confirmation page
=back
These web modules are designed to be used in HTML::Template, with the help of
Jquery scripts. Without that, this will only output raw HTML code.
=head1 SEE ALSO =head1 SEE ALSO

View File

@ -362,6 +362,9 @@ sub new {
. ')'; . ')';
} }
# Load Menu functions
$self->loadModule('Lemonldap::NG::Portal::Menu');
return $self; return $self;
} }
@ -644,9 +647,10 @@ _RETURN $string Error string
=cut =cut
##@method string error(string lang) ##@method string error(string lang, int code)
# error calls Portal/_i18n.pm to display error in the wanted language. # error calls Portal/_i18n.pm to display error in the wanted language.
#@param $lang optional (browser language is used instead) #@param $lang optional (browser language is used instead)
#@param $code optional error code
#@return error message #@return error message
sub error { sub error {
my $self = shift; my $self = shift;
@ -1904,7 +1908,7 @@ sub issuerForAuthUser {
sub autoRedirect { sub autoRedirect {
my $self = shift; my $self = shift;
# default redirection URL # Default redirection URL
$self->{urldc} ||= $self->{portal} $self->{urldc} ||= $self->{portal}
if ( $self->{mustRedirect} or $self->info() ); if ( $self->{mustRedirect} or $self->info() );

View File

@ -5,7 +5,7 @@
# change 'tests => 1' to 'tests => last_test_to_print'; # change 'tests => 1' to 'tests => last_test_to_print';
use Test::More tests => 3; use Test::More tests => 2;
BEGIN { use_ok('Lemonldap::NG::Portal::Menu') } BEGIN { use_ok('Lemonldap::NG::Portal::Menu') }
######################### #########################
@ -13,14 +13,19 @@ BEGIN { use_ok('Lemonldap::NG::Portal::Menu') }
# Insert your test code below, the Test::More module is use()ed here so read # Insert your test code below, the Test::More module is use()ed here so read
# its man page ( perldoc Test::More ) for help writing this test script. # its man page ( perldoc Test::More ) for help writing this test script.
my $tmp; $ENV{REQUEST_METHOD} = 'GET';
my ( $m, $p ); # Build portal
my $p = Lemonldap::NG::Portal::Simple->new({
globalStorage => 'Apache::Session::File',
domain => 'example.com',
error => 0,
applicationList => {},
});
$p = bless { cookieName => 'lemonldap', }, 'Lemonldap::NG::Portal::SharedConf'; # Init menu
$p->menuInit();
ok( $m = Lemonldap::NG::Portal::Menu->new( { portalObject => $p } ), ok( ref $p->{menuDisplayModules} eq 'ARRAY' ,
'constructor' ); 'Modules displayed' );
ok( $m->isa('Lemonldap::NG::Portal::Menu'), 'object returned' );