Adapt Display.pm

This commit is contained in:
Xavier Guimard 2016-04-07 21:31:56 +00:00
parent e25d286b9a
commit 72a076d980
18 changed files with 512 additions and 127 deletions

View File

@ -184,7 +184,7 @@ sub sendHtml {
STATIC_PREFIX => $sp,
AVAILABLE_LANGUAGES => $self->languages,
PORTAL => $self->portal,
( $self->can('tplParams') ? %{ $self->tplParams } : () ),
( $args{params} ? %{ $args{params} } : () ),
);
};
if ($@) {

View File

@ -6,6 +6,13 @@
</div>
</div>
<!-- Constants -->
<script type="text/JavaScript">
var staticPrefix = '<TMPL_VAR NAME="STATIC_PREFIX">'.replace(/\/*$/,'/');
var scriptname='<TMPL_VAR NAME="SCRIPT_NAME">'.replace(/^$/,'.').replace(/\/*$/,'/');
var availableLanguages='<TMPL_VAR NAME="AVAILABLE_LANGUAGES">'.split(/[,;] */);
var portal ='<TMPL_VAR NAME="PORTAL">';
</script>
</body>
</html>

View File

@ -2,6 +2,13 @@
</div>
<!-- Constants -->
<script type="text/JavaScript">
var staticPrefix = '<TMPL_VAR NAME="STATIC_PREFIX">'.replace(/\/*$/,'/');
var scriptname='<TMPL_VAR NAME="SCRIPT_NAME">'.replace(/^$/,'.').replace(/\/*$/,'/');
var availableLanguages='<TMPL_VAR NAME="AVAILABLE_LANGUAGES">'.split(/[,;] */);
var portal ='<TMPL_VAR NAME="PORTAL">';
</script>
</body>
</html>

View File

@ -1,5 +1,12 @@
<div id="footer"><TMPL_INCLUDE NAME="customfooter.tpl"></div>
</div><!-- end div "page" -->
<!-- Constants -->
<script type="text/JavaScript">
var staticPrefix = '<TMPL_VAR NAME="STATIC_PREFIX">'.replace(/\/*$/,'/');
var scriptname='<TMPL_VAR NAME="SCRIPT_NAME">'.replace(/^$/,'.').replace(/\/*$/,'/');
var availableLanguages='<TMPL_VAR NAME="AVAILABLE_LANGUAGES">'.split(/[,;] */);
var portal ='<TMPL_VAR NAME="PORTAL">';
</script>
</body>
</html>

View File

@ -1,4 +1,4 @@
package Lemonldap::NG::Portal::Main::Auth;
package Lemonldap::NG::Portal::Auth::Base;
use strict;
use Mouse;

View File

@ -11,7 +11,7 @@ use Lemonldap::NG::Portal::Main::Constants;
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::Auth';
extends 'Lemonldap::NG::Portal::Auth::Base';
## @apmethod int authInit()
# Does nothing.

View File

@ -3,11 +3,17 @@ package Lemonldap::NG::Portal::Main;
use strict;
use Mouse;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Portal::Main::Constants;
use Lemonldap::NG::Portal::Main::Request;
use Lemonldap::NG::Portal::Main::Plugins;
use Lemonldap::NG::Portal::Main::Init;
use Lemonldap::NG::Portal::Main::Run;
use Lemonldap::NG::Portal::Main::Process;
use Lemonldap::NG::Portal::Main::Display;
our $VERSION = '2.0.0';
extends(
'Lemonldap::NG::Portal::Main::Run',
'Lemonldap::NG::Portal::Main::Init',
);
extends 'Lemonldap::NG::Handler::PSGI::Try';
1;

View File

@ -0,0 +1,431 @@
## @file
# Display functions for LemonLDAP::NG Portal
package Lemonldap::NG::Portal::Main::Display;
our $VERSION = '2.0.0';
package Lemonldap::NG::Portal::Main;
use strict;
# Call portal process and set template parameters
# @return template name and template parameters
sub display {
my ( $self, $req ) = @_;
my $skin_dir = $self->conf->{templatesDir};
my ( $skinfile, %templateParams );
# 0. Display error page
if ( my $http_error = $req->param('lmError') ) {
$skinfile = 'error';
# Check URL
$self->_sub('controlUrlOrigin');
# Load session content
$self->_sub('controlExistingSession');
%templateParams = (
PORTAL_URL => $self->conf->{portal},
LOGOUT_URL => $self->conf->{portal} . "?logout=1",
URL => $req->{urldc},
);
# Error code
foreach ( 403, 500, 503 ) {
$templateParams{"ERROR$_"} = ( $http_error == $_ ? 1 : 0 );
}
}
# 1. Good authentication
elsif ( $req->error eq PE_OK ) {
# 1.1 Image mode
if ( $req->{error} == PE_IMG_OK || $req->{error} == PE_IMG_NOK ) {
return staticFile( "common/"
. ( $req->{error} == PE_IMG_OK ? 'ok.png' : 'warning.png' ) );
}
# 1.2 Case : there is a message to display
elsif ( my $info = $req->info() ) {
$skinfile = 'info';
%templateParams = (
AUTH_ERROR_TYPE => $req->error_type,
MSG => $info,
URL => $req->{urldc},
HIDDEN_INPUTS => $self->buildHiddenForm(),
ACTIVE_TIMER => $self->conf->{activeTimer},
FORM_METHOD => $self->conf->{infoFormMethod},
);
}
# 1.3 Redirection
elsif ( $req->{error} == PE_REDIRECT ) {
$skinfile = "redirect";
%templateParams = (
URL => $req->{urldc},
HIDDEN_INPUTS => $self->buildHiddenForm(),
FORM_METHOD => $self->conf->{redirectFormMethod},
);
}
# 1.4 Case : display menu
else {
# Initialize menu elements
$self->menuInit;
$skinfile = 'menu';
my $auth_user =
$req->{sessionInfo}->{ $self->conf->{portalUserAttr} };
#utf8::decode($auth_user);
%templateParams = (
AUTH_USER => $auth_user,
NEWWINDOW => $self->conf->{portalOpenLinkInNewWindow},
AUTH_ERROR => $req->errorString( $req->{menuError} ),
AUTH_ERROR_TYPE => $req->error_type( $req->{menuError} ),
DISPLAY_TAB => $self->conf->{menuDisplayTab},
LOGOUT_URL => $self->conf->{portal} . "?logout=1",
REQUIRE_OLDPASSWORD => $self->conf->{portalRequireOldPassword},
HIDE_OLDPASSWORD =>
0, # Do not hide old password if it is required
DISPLAY_MODULES => $self->conf->{menuDisplayModules},
APPSLIST_MENU => $self->conf->{menuAppslistMenu}
, # For old templates
APPSLIST_DESC => $self->conf->{menuAppslistDesc}
, # For old templates
APPSLIST_ORDER => $req->{sessionInfo}->{'appsListOrder'},
PING => $self->conf->{portalPingInterval},
);
}
}
# 2. Authentication not complete
# 2.1 A notification has to be done (session is created but hidden and unusable
# until the user has accept the message)
elsif ( my $notif = $req->notification ) {
$skinfile = 'notification';
%templateParams = (
AUTH_ERROR_TYPE => $req->error_type,
NOTIFICATION => $notif,
HIDDEN_INPUTS => $self->buildHiddenForm(),
AUTH_URL => $self->get_url,
CHOICE_PARAM => $self->conf->{authChoiceParam},
CHOICE_VALUE => $req->{_authChoice},
);
}
# 2.2 An authentication (or userDB) module needs to ask a question
# before processing to the request
elsif ( $req->{error} == PE_CONFIRM ) {
$skinfile = 'confirm';
%templateParams = (
AUTH_ERROR => $req->error,
AUTH_ERROR_TYPE => $req->error_type,
AUTH_URL => $self->get_url,
MSG => $req->info,
HIDDEN_INPUTS => $self->buildHiddenForm(),
ACTIVE_TIMER => $self->conf->{activeTimer},
FORM_METHOD => $self->conf->{confirmFormMethod},
CHOICE_PARAM => $self->conf->{authChoiceParam},
CHOICE_VALUE => $req->{_authChoice},
CHECK_LOGINS => $self->conf->{portalCheckLogins}
&& $self->conf->{login},
ASK_LOGINS => $self->conf->{checkLogins},
CONFIRMKEY => $self->stamp(),
LIST => $req->datas->{list} || [],
REMEMBER => $self->conf->{confirmRemember},
);
}
# 2.3 There is a message to disp->conf->conflay
elsif ( my $info = $req->info ) {
$skinfile = 'info';
%templateParams = (
AUTH_ERROR => $self->error,
AUTH_ERROR_TYPE => $req->error_type,
MSG => $info,
URL => $req->{urldc},
HIDDEN_INPUTS => $self->buildHiddenForm(),
ACTIVE_TIMER => $self->conf->{activeTimer},
FORM_METHOD => $self->conf->{infoFormMethod},
CHOICE_PARAM => $self->conf->{authChoiceParam},
CHOICE_VALUE => $req->{_authChoice},
);
}
# 2.4 OpenID menu page
elsif ($req->{error} == PE_OPENID_EMPTY
or $req->{error} == PE_OPENID_BADID )
{
$skinfile = 'openid';
my $p = $self->{portal} . $self->{issuerDBOpenIDPath};
$p =~ s#(?<!:)/\^?/#/#g;
%templateParams = (
AUTH_ERROR => $self->error,
AUTH_ERROR_TYPE => $req->error_type,
PROVIDERURI => $p,
ID => $self->{_openidPortal}
. $req->{sessionInfo}
->{ $self->conf->{openIdAttr} || $self->conf->{whatToTrace} },
PORTAL_URL => $self->conf->{portal},
MSG => $req->info(),
);
}
# 2.5 Authentication has been refused OR this is the first access
else {
$skinfile = 'login';
%templateParams = (
AUTH_ERROR => $req->error,
AUTH_ERROR_TYPE => $req->error_type,
AUTH_URL => $self->get_url,
LOGIN => $self->user($req),
CHECK_LOGINS => $self->conf->{portalCheckLogins},
ASK_LOGINS => $self->conf->{checkLogins},
DISPLAY_RESETPASSWORD => $self->conf->{portalDisplayResetPassword},
DISPLAY_REGISTER => $self->conf->{portalDisplayRegister},
MAIL_URL => $self->conf->{mailUrl},
REGISTER_URL => $self->conf->{registerUrl},
HIDDEN_INPUTS => $self->buildHiddenForm(),
LOGIN_INFO => $req->loginInfo(),
);
# Display captcha if it's enabled
if ( $self->{captcha_login_enabled} ) {
%templateParams = (
%templateParams,
CAPTCHA_IMG => $req->{captcha_img},
CAPTCHA_CODE => $req->{captcha_code},
CAPTCHA_SIZE => $req->{captcha_size}
);
}
# Show password form if password policy error
if (
$req->{error} == PE_PP_CHANGE_AFTER_RESET
or $req->{error} == PE_PP_MUST_SUPPLY_OLD_PASSWORD
or $req->{error} == PE_PP_INSUFFICIENT_PASSWORD_QUALITY
or $req->{error} == PE_PP_PASSWORD_TOO_SHORT
or $req->{error} == PE_PP_PASSWORD_TOO_YOUNG
or $req->{error} == PE_PP_PASSWORD_IN_HISTORY
or $req->{error} == PE_PASSWORD_MISMATCH
or $req->{error} == PE_BADOLDPASSWORD
or $req->{error} == PE_PASSWORDFORMEMPTY
)
{
%templateParams = (
%templateParams,
REQUIRE_OLDPASSWORD =>
1, # Old password is required to check user credentials
DISPLAY_FORM => 0,
DISPLAY_OPENID_FORM => 0,
DISPLAY_YUBIKEY_FORM => 0,
DISPLAY_PASSWORD => 1,
DISPLAY_RESETPASSWORD => 0,
AUTH_LOOP => [],
CHOICE_PARAM => $self->conf->{authChoiceParam},
CHOICE_VALUE => $req->{_authChoice},
OLDPASSWORD =>
$self->checkXSSAttack( 'oldpassword', $req->{oldpassword} )
? ""
: $self->{oldpassword},
HIDE_OLDPASSWORD => $self->conf->{hideOldPassword},
);
}
# Disable all forms on:
# * Logout message
# * Bad URL error
elsif ($req->{error} == PE_LOGOUT_OK
or $req->{error} == PE_BADURL )
{
%templateParams = (
%templateParams,
DISPLAY_RESETPASSWORD => 0,
DISPLAY_FORM => 0,
DISPLAY_OPENID_FORM => 0,
DISPLAY_YUBIKEY_FORM => 0,
AUTH_LOOP => [],
PORTAL_URL => $self->conf->{portal},
MSG => $req->info(),
);
}
# Display authentifcation form
else {
# Authentication loop
if ( $self->{authLoop} ) {
%templateParams = (
%templateParams,
AUTH_LOOP => $self->conf->{authLoop},
CHOICE_PARAM => $self->conf->{authChoiceParam},
CHOICE_VALUE => $req->{_authChoice},
DISPLAY_FORM => 0,
DISPLAY_OPENID_FORM => 0,
DISPLAY_YUBIKEY_FORM => 0,
);
}
# Choose what form to display if not in a loop
else {
my $displayType = $self->_authentication->getDisplayType();
$self->lmLog( "Display type $displayType ", 'debug' );
%templateParams = (
%templateParams,
DISPLAY_FORM => $displayType eq "standardform" ? 1 : 0,
DISPLAY_OPENID_FORM => $displayType eq "openidform" ? 1 : 0,
DISPLAY_YUBIKEY_FORM => $displayType eq "yubikeyform" ? 1
: 0,
DISPLAY_LOGO_FORM => $displayType eq "logo" ? 1 : 0,
module => $displayType eq "logo" ? $self->get_module('auth')
: "",
AUTH_LOOP => [],
PORTAL_URL =>
( $displayType eq "logo" ? $self->conf->{portal} : 0 ),
MSG => $req->info(),
);
}
}
}
## Common template params
my $skin = $self->getSkin($req);
my $portalPath = $self->conf->{portal};
$portalPath =~ s#^https?://[^/]+/?#/#;
$portalPath =~ s#[^/]+\.pl$##;
%templateParams = (
%templateParams,
SKIN_PATH => $portalPath . "skins",
SKIN => $skin,
ANTIFRAME => $self->conf->{portalAntiFrame},
SKIN_BG => $self->conf->{portalSkinBackground},
);
## Custom template params
if ( my $customParams = $self->getCustomTemplateParameters() ) {
%templateParams = ( %templateParams, %$customParams );
}
return $self->sendHtml( $req, "$skinfile", params => \%templateParams );
}
##@method public void printImage(string file, string type)
# Print image to STDOUT
# @param $file The path to the file to print
# @param $type The content-type to use (ie: image/png)
# @return void
sub staticFile {
my ( $self, $file, $type ) = @_;
require Plack::Util;
require Cwd;
require HTTP::Date;
open my $fh, '<:raw', $self->conf->{templatesDir} . "/$file"
or return $self->sendError( $!, 403 );
my @stat = stat $file;
Plack::Util::set_io_path( $fh, Cwd::realpath($file) );
return [
200,
[
'Content-Type' => $type,
'Content-Length' => $stat[7],
'Last-Modified' => HTTP::Date::time2str( $stat[9] )
],
$fh,
];
}
sub buildHiddenForm {
my ($self) = @_;
my @keys = keys %{ $self->conf->{portalHiddenFormValues} };
my $val = '';
foreach (@keys) {
# Check XSS attacks
next
if $self->checkXSSAttack( $_,
$self->conf->{portalHiddenFormValues}->{$_} );
# Build hidden input HTML code
$val .= qq{<input type="hidden" name="$_" id="$_" value="}
. $self->conf->{portalHiddenFormValues}->{$_} . '" />';
}
return $val;
}
# Return skin name
# @return skin name
sub getSkin {
my ( $self, $req ) = @_;
my $skin = $self->conf->{portalSkin};
# Fill sessionInfo to eval rule if empty (unauthenticated user)
$req->{sessionInfo}->{_url} ||= $req->{urldc};
$req->{sessionInfo}->{ipAddr} ||= $req->remote_ip;
# Load specific skin from skinRules
if ( $self->conf->{portalSkinRules} ) {
foreach my $skinRule ( sort keys %{ $self->conf->{portalSkinRules} } ) {
if ( HANDLER->tsv->{jail}->reval($skinRule) ) {
$skin = $self->conf->{portalSkinRules}->{$skinRule};
$self->lmLog( "Skin $skin selected from skin rule", 'debug' );
}
}
}
# Check skin GET/POST parameter
my $skinParam = $req->param('skin');
if ( defined $skinParam && !$self->checkXSSAttack( 'skin', $skinParam ) ) {
$skin = $skinParam;
$self->lmLog( "Skin $skin selected from GET/POST parameter", 'debug' );
}
return $skin;
}
# Find custom templates parameters
# @return Custom parameters
sub getCustomTemplateParameters {
my ($self) = @_;
my $conf = $self->conf;
my $customTplParams = {};
foreach ( keys %$conf ) {
next unless ( $_ =~ /^tpl_(.+)$/ );
my $tplParam = $1;
my $tplValue = $conf->{$_};
$self->lmLog( "Set custom template parameter $tplParam with $tplValue",
'debug' );
$customTplParams->{$tplParam} = $tplValue;
}
return $customTplParams;
}
sub menuInit {
}
sub get_url {
}
1;

View File

@ -8,17 +8,13 @@
# of lemonldap-ng.ini) and underlying handler configuration
package Lemonldap::NG::Portal::Main::Init;
use strict;
use Mouse;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Portal::Main::Constants;
use Lemonldap::NG::Portal::Main::Plugins;
use Regexp::Assemble;
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Handler::PSGI::Try',
'Lemonldap::NG::Portal::Main::Plugins';
package Lemonldap::NG::Portal::Main;
use strict;
use Mouse;
use Regexp::Assemble;
# Configuration storage
has localConfig => ( is => 'rw', default => sub { {} } );

View File

@ -2,11 +2,12 @@
# into "plugins" list in lemonldap-ng.ini, section "portal"
package Lemonldap::NG::Portal::Main::Plugins;
use strict;
use Mouse;
our $VERSION = '2.0.0';
package Lemonldap::NG::Portal::Main;
use strict;
##@method list enabledPlugins
#
#@return list of enabled plugins

View File

@ -1,14 +1,13 @@
package Lemonldap::NG::Portal::Main::Process;
our $VERSION = '2.0.0';
package Lemonldap::NG::Portal::Main;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants;
use Lemonldap::NG::Portal::Main::Request;
use MIME::Base64;
use POSIX qw(strftime);
our $VERSION = '2.0.0';
# Main method
# -----------
# Launch all methods declared in request "steps" array. Methods can be

View File

@ -31,8 +31,35 @@ has mustRedirect => ( is => 'rw' );
# Boolean to indicate that url isn't Base64 encoded
has urlNotBase64 => ( is => 'rw' );
# Info to display at login
has info => ( is => 'rw' );
# Menu error
has menuError => ( is => 'rw' );
# Notification
has notification => ( is => 'rw' );
has _authChoice => ( is => 'rw' );
has _openidPortal => ( is => 'rw' );
sub wantJSON {
return $_[0]->accept =~ m#(?:application|text)/json# ? 1 : 0;
}
# Error type
sub error_type {
#TODO
}
sub errorString {
#TODO
}
sub loginInfo {
}
# TODO: oldpassword
1;

View File

@ -9,15 +9,12 @@
#
package Lemonldap::NG::Portal::Main::Run;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants;
use Lemonldap::NG::Portal::Main::Request;
extends 'Lemonldap::NG::Portal::Main::Process';
our $VERSION = '2.0.0';
package Lemonldap::NG::Portal::Main;
use strict;
# List constants
sub authProcess { qw(extractFormInfo getUser authenticate) }
@ -116,11 +113,7 @@ sub do {
}
else {
if ($err) {
return $self->sendHtml(
$req,
$req->template || 'login',
headers => $req->respHeaders
);
return $self->display($req);
}
else {
return $self->autoRedirect($req);
@ -170,7 +163,7 @@ sub autoRedirect {
];
}
else {
return $self->sendHtml( $req, $req->template || 'menu' );
return $self->display($req);
}
}

View File

@ -1,2 +0,0 @@
</body>
</html>

View File

@ -1,28 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title trspan="authenticationPortal">Authentication portal</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="cache-control" content="no-cache" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- //if:usedebianlibs
<link rel="stylesheet" type="text/css" href="/javascript/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="/javascript/bootstrap/css/bootstrap-theme.min.css" />
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/portal.min.css" />
//elsif:useexternallibs
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" />
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/portal.min.css" />
//elsif:cssminified
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/bootstrap-theme.min.css" />
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/portal.min.css" />
//else -->
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/bootstrap-theme.css" />
<link rel="stylesheet" type="text/css" href="<TMPL_VAR NAME="STATIC_PREFIX">css/portal.css" />
<!-- //endif -->
<link rel="shortcut icon" type="image/vnd.microsoft.icon" sizes="16x16 32x32 48x48 64x64 128x128" href="<TMPL_VAR NAME="STATIC_PREFIX">logos/favicon.ico" />
<link rel="icon" type="image/vnd.microsoft.icon" sizes="16x16 32x32 48x48 64x64 128x128" href="<TMPL_VAR NAME="STATIC_PREFIX">logos/favicon.ico" />

View File

@ -1,24 +0,0 @@
<TMPL_INCLUDE NAME="header.tpl">
</head>
<body>
<div id="logincontent" class="container">
<TMPL_IF NAME="AUTH_ERROR">
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"><TMPL_VAR NAME="AUTH_ERROR"></div>
</TMPL_IF>
<div class="panel panel-default">
<form action="#" method="post" class="login" role="form">
<!-- Hidden fields -->
<TMPL_VAR NAME="HIDDEN_INPUTS">
<input type="hidden" name="url" value="<TMPL_VAR NAME="AUTH_URL">" />
<input type="hidden" name="timezone" />
<TMPL_INCLUDE NAME="standardform.tpl">
</form>
</div>
</div>
<TMPL_INCLUDE NAME="scripts.tpl">
<TMPL_INCLUDE NAME="footer.tpl">

View File

@ -1,36 +0,0 @@
<!-- Constants -->
<script type="text/JavaScript">
var staticPrefix = '<TMPL_VAR NAME="STATIC_PREFIX">'.replace(/\/*$/,'/');
var formPrefix = staticPrefix+'forms/';
var scriptname='<TMPL_VAR NAME="SCRIPT_NAME">'.replace(/^$/,'.').replace(/\/*$/,'/');
var confPrefix=scriptname+'confs/';
var availableLanguages='<TMPL_VAR NAME="AVAILABLE_LANGUAGES">'.split(/[,;] */);
var links=<TMPL_VAR NAME="LINKS">;
var menulinks=<TMPL_VAR NAME="MENULINKS">;
var portal ='<TMPL_VAR NAME="PORTAL">';
</script>
<!-- //if:usedebianlibs
<script type="text/javascript" src="/javascript/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/javascript/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">js/portal.min.js"></script>
//elsif:useexternallibs
<script type="text/javascript" src="http://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">js/portal.min.js"></script>
//elsif:jsminified
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">bwr/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">bwr/bootstrap/dist/js/bootstrap.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">js/portal.min.js"></script>
//else -->
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">bwr/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">bwr/bootstrap/dist/js/bootstrap.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">js/portal.js"></script>
<!-- //endif -->
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->

View File

@ -20,6 +20,7 @@ sub init {
$ini->{logLevel} ||= 'error';
$ini->{cookieName} ||= 'lemonldap';
$ini->{templateDir} ||= 'site/templates';
$ini->{staticPrefix} ||= '/index.fcgi';
$ini->{securedCookie} //= 0;
$ini->{https} //= 0;
ok( $client = My::Cli->new(), 'Portal app' );