This commit is contained in:
Xavier Guimard 2015-05-14 06:44:38 +00:00
parent ab0b6e7190
commit 3e2322fe3a
248 changed files with 21070 additions and 49232 deletions

View File

@ -11,10 +11,11 @@ use strict;
use AutoLoader 'AUTOLOAD';
use Apache::Session;
use base qw(Apache::Session);
use Lemonldap::NG::Common::Apache::Session::Serialize::JSON;
use Lemonldap::NG::Common::Apache::Session::Store;
use Lemonldap::NG::Common::Apache::Session::Lock;
our $VERSION = '1.4.4';
our $VERSION = '1.5.99';
sub _load {
my $backend = shift;
@ -34,7 +35,6 @@ sub populate {
$self = $self->$backend(@_);
}
if ( $self->{args}->{jsonSerialize} ) {
require Lemonldap::NG::Common::Apache::Session::Serialize::JSON;
$self->{serialize} =
\&Lemonldap::NG::Common::Apache::Session::Serialize::JSON::serialize;
$self->{unserialize} =

View File

@ -1,12 +1,3 @@
#######################################################
#
# Lemonldap::NG::Common::Apache::Session::Serialize::JSON
# Serializes session objects using JSON
# Copyright(c) 2015 Xavier Guimard (x.guimard@free.fr)
# Distribute under the GPL2 License
#
#######################################################
package Lemonldap::NG::Common::Apache::Session::Serialize::JSON;
use strict;
@ -35,6 +26,8 @@ sub unserialize {
=head1 NAME
=encoding utf8
Lemonldap::NG::Common::Apache::Session::Serialize::JSON - Use JSON to zip up data
=head1 SYNOPSIS
@ -50,11 +43,54 @@ This module fulfills the serialization interface of Apache::Session.
It serializes the data in the session object by use of JSON C<encode_json>
and C<decode_json>. The serialized data is UTF-8 text.
=head1 AUTHOR
This module was written by Xavier Guimard <x.guimard@free.fr> using other
Apache::Session serializer written by Jeffrey William Baker <jwbaker@acm.org>.
=head1 SEE ALSO
L<JSON>, L<Apache::Session>
=head1 AUTHORS
=over
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
=item François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
=item Thomas Chemineau, E<lt>thomas.chemineau@gmail.comE<gt>
=back
=head1 BUG REPORT
Use OW2 system to report bug or ask for features:
L<http://jira.ow2.org>
=head1 DOWNLOAD
Lemonldap::NG is available at
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
=head1 COPYRIGHT AND LICENSE
=over
=item Copyright (C) 2015 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
=back
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see L<http://www.gnu.org/licenses/>.
=cut

View File

@ -10,7 +10,9 @@ package Lemonldap::NG::Common::Conf;
use strict;
no strict 'refs';
use Lemonldap::NG::Common::Conf::Constants; #inherits
use Lemonldap::NG::Common::Conf::Attributes; #inherits
# TODO: don't import this big file, use a proxy
use Lemonldap::NG::Common::Conf::DefaultValues; #inherits
use Lemonldap::NG::Common::Crypto
; #link protected cipher Object "cypher" in configuration hash
use Config::IniFiles;
@ -20,7 +22,7 @@ use Config::IniFiles;
#inherits Lemonldap::NG::Common::Conf::SOAP
#inherits Lemonldap::NG::Common::Conf::LDAP
our $VERSION = '1.4.4';
our $VERSION = '1.5.99';
our $msg = '';
our $iniObj;
@ -108,12 +110,12 @@ sub new {
# @param $conf Lemonldap::NG configuration hashRef
# @return Number of the saved configuration, 0 if case of error.
sub saveConf {
my ( $self, $conf ) = @_;
my ( $self, $conf, %args ) = @_;
my $last = $self->lastCfg;
# If configuration was modified, return an error
if ( not $self->{force} ) {
if ( not $args{force} ) {
return CONFIG_WAS_CHANGED if ( $conf->{cfgNum} != $last );
return DATABASE_LOCKED if ( $self->isLocked() or not $self->lock() );
}
@ -169,24 +171,31 @@ sub getConf {
else {
eval { $r = $self->{refLocalStorage}->get('conf') } if ($>);
$msg = "Warn: $@" if ($@);
if ( ref($r) and $r->{cfgNum} == $args->{cfgNum} ) {
if ( ref($r)
and $r->{cfgNum}
and $args->{cfgNum}
and $r->{cfgNum} == $args->{cfgNum} )
{
$msg .=
"Configuration unchanged, get configuration from cache.\n";
$args->{noCache} = 1;
}
else {
$r = $self->getDBConf($args);
return undef unless ( ref($r) );
return undef unless ( $r->{cfgNum} );
# Adapt some values before storing in local cache
# Get default values
my $confAttributes =
Lemonldap::NG::Common::Conf::Attributes->new();
# TODO: default values may not be set here
unless ( $args->{raw} ) {
my @attributes = $confAttributes->meta()->get_attribute_list();
# Adapt some values before storing in local cache
# Get default values
my $defaultValues =
Lemonldap::NG::Common::Conf::DefaultValues
->defaultValues();
foreach my $name (@attributes) {
$r->{$name} //= $confAttributes->$name;
foreach my $k ( keys %$defaultValues ) {
$r->{$k} //= $defaultValues->{$k};
}
}
# Convert old option useXForwardedForIP into trustedProxies
@ -211,15 +220,20 @@ sub getConf {
# Store modified configuration in cache
$self->setLocalConf($r)
if ( $self->{refLocalStorage} and not( $args->{noCache} ) );
if ( $self->{refLocalStorage}
and not( $args->{noCache} or $args->{raw} ) );
}
}
# Create cipher object
eval { $r->{cipher} = Lemonldap::NG::Common::Crypto->new( $r->{key} ); };
if ($@) {
$msg .= "Bad key: $@. \n";
unless ( $args->{raw} ) {
eval {
$r->{cipher} = Lemonldap::NG::Common::Crypto->new( $r->{key} );
};
if ($@) {
$msg .= "Bad key: $@. \n";
}
}
# Return configuration hash
@ -345,7 +359,8 @@ sub getDBConf {
: $a[0];
}
my $conf = $self->load( $args->{cfgNum} );
$msg .= "Get configuration $conf->{cfgNum}.\n";
$msg .= "Get configuration $conf->{cfgNum}.\n"
if ( defined $conf->{cfgNum} );
$self->setLocalConf($conf)
if ( ref($conf)
and $self->{refLocalStorage}
@ -418,7 +433,7 @@ sub load {
sub delete {
my ( $self, $c ) = @_;
my @a = $self->available();
return 0 unless ( grep {$_ eq $c} @a );
return 0 unless ( grep { $_ eq $c } @a );
return &{ $self->{type} . '::delete' }( $self, $c );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,315 @@
# This file is generated by scripts/jsongenerator.pl. Don't modify it by hand
package Lemonldap::NG::Common::Conf::DefaultValues;
our $VERSION = '1.5.99';
sub defaultValues {
return {
'activeTimer' => 1,
'apacheAuthnLevel' => 4,
'applicationList' => {
'default' => {
'catname' => 'Default category',
'type' => 'category'
}
},
'authentication' => 'Demo',
'browserIdAuthnLevel' => 1,
'captcha_login_enabled' => 0,
'captcha_mail_enabled' => 0,
'captcha_register_enabled' => 1,
'captcha_size' => 6,
'captchaStorage' => 'Apache::Session::File',
'captchaStorageOptions' => {
'Directory' => '/var/lib/lemonldap-ng/captcha/'
},
'CAS_authnLevel' => 1,
'CAS_pgtFile' => '/tmp/pgt.txt',
'casAccessControlPolicy' => 'none',
'cda' => 0,
'cfgNum' => 0,
'checkXSS' => 1,
'confirmFormMethod' => 'post',
'cookieName' => 'lemonldap',
'dbiAuthnLevel' => 2,
'dbiExportedVars' => {},
'demoExportedVars' => {
'cn' => 'cn',
'mail' => 'mail',
'uid' => 'uid'
},
'domain' => 'example.com',
'exportedVars' => {
'UA' => 'HTTP_USER_AGENT'
},
'facebookAuthnLevel' => 1,
'facebookExportedVars' => {},
'failedLoginNumber' => 5,
'globalStorage' => 'Apache::Session::File',
'globalStorageOptions' => {
'Directory' => '/var/lib/lemonldap-ng/sessions/',
'generateModule' =>
'Lemonldap::NG::Common::Apache::Session::Generate::SHA256',
'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock/'
},
'googleAuthnLevel' => 1,
'googleExportedVars' => {},
'groups' => {},
'hiddenAttributes' => '_password',
'hideOldPassword' => 0,
'httpOnly' => 1,
'https' => 0,
'infoFormMethod' => 'get',
'issuerDBCASActivation' => 0,
'issuerDBCASPath' => '^/cas/',
'issuerDBCASRule' => 1,
'issuerDBOpenIDActivation' => 0,
'issuerDBOpenIDConnectActivation' => '0',
'issuerDBOpenIDConnectPath' => '^/oauth2/',
'issuerDBOpenIDConnectRule' => 1,
'issuerDBOpenIDPath' => '^/openidserver/',
'issuerDBOpenIDRule' => 1,
'issuerDBSAMLActivation' => 0,
'issuerDBSAMLPath' => '^/saml/',
'issuerDBSAMLRule' => 1,
'jsRedirect' => 0,
'ldapAuthnLevel' => 2,
'ldapBase' => 'dc=example,dc=com',
'ldapChangePasswordAsUser' => 0,
'ldapExportedVars' => {
'cn' => 'cn',
'mail' => 'mail',
'uid' => 'uid'
},
'ldapGroupAttributeName' => 'member',
'ldapGroupAttributeNameGroup' => 'dn',
'ldapGroupAttributeNameSearch' => 'cn',
'ldapGroupAttributeNameUser' => 'dn',
'ldapGroupObjectClass' => 'groupOfNames',
'ldapGroupRecursive' => 0,
'ldapPasswordResetAttribute' => 'pwdReset',
'ldapPasswordResetAttributeValue' => 'TRUE',
'ldapPort' => 389,
'ldapPpolicyControl' => 0,
'ldapPwdEnc' => 'utf-8',
'ldapServer' => 'ldap://localhost',
'ldapSetPassword' => 0,
'ldapTimeout' => 120,
'ldapUsePasswordResetAttribute' => 1,
'ldapVersion' => 3,
'localSessionStorage' => 'Cache::FileCache',
'localSessionStorageOptions' => {
'cache_depth' => 3,
'cache_root' => '/tmp',
'default_expires_in' => 600,
'directory_umask' => '007',
'namespace' => 'lemonldap-ng-sessions'
},
'locationRules' => {
'default' => 'deny'
},
'loginHistoryEnabled' => 1,
'logoutServices' => {},
'macros' => {},
'mailCharset' => 'utf-8',
'mailConfirmSubject' => '[LemonLDAP::NG] Password reset confirmation',
'mailFrom' => 'noreply@example.com',
'mailOnPasswordChange' => 0,
'mailSessionKey' => 'mail',
'mailSubject' => '[LemonLDAP::NG] Your new password',
'mailTimeout' => 0,
'mailUrl' => 'http://auth.example.com/mail.pl',
'maintenance' => 0,
'managerDn' => '',
'managerPassword' => '',
'multiValuesSeparator' => '; ',
'notification' => 0,
'notificationStorage' => 'File',
'notificationStorageOptions' => {
'dirName' => '/var/lib/lemonldap-ng/notifications'
},
'notificationWildcard' => 'allusers',
'notifyDeleted' => 1,
'notifyOther' => 0,
'nullAuthnLevel' => 2,
'oidcAuthnLevel' => 1,
'oidcRPCallbackGetParam' => 'openidconnectcallback',
'oidcRPStateTimeout' => 600,
'oidcServiceMetaDataAuthnContext' => {
'loa-1' => 1,
'loa-2' => 2,
'loa-3' => 3,
'loa-4' => 4,
'loa-5' => 5
},
'oidcServiceMetaDataAuthorizeURI' => 'authorize',
'oidcServiceMetaDataEndSessionURI' => 'logout',
'oidcServiceMetaDataJWKSURI' => 'jwks',
'oidcServiceMetaDataRegistrationURI' => 'register',
'oidcServiceMetaDataTokenURI' => 'token',
'oidcServiceMetaDataUserInfoURI' => 'userinfo',
'openIdAuthnLevel' => 1,
'openIdExportedVars' => {},
'openIdIDPList' => '0;',
'openIdSPList' => '0;',
'openIdSreg_email' => 'mail',
'openIdSreg_fullname' => 'cn',
'openIdSreg_nickname' => 'uid',
'openIdSreg_timezone' => '_timezone',
'passwordDB' => 'Demo',
'portal' => 'http://auth.example.com/',
'portalAntiFrame' => 1,
'portalAutocomplete' => 0,
'portalCheckLogins' => 1,
'portalDisplayAppslist' => 1,
'portalDisplayChangePassword' => '$_auth =~ /^(LDAP|DBI|Demo)$/',
'portalDisplayLoginHistory' => 1,
'portalDisplayLogout' => 1,
'portalDisplayRegister' => 1,
'portalDisplayResetPassword' => 1,
'portalForceAuthn' => 0,
'portalForceAuthnInterval' => 0,
'portalOpenLinkInNewWindow' => 0,
'portalPingInterval' => 60000,
'portalRequireOldPassword' => 1,
'portalSkin' => 'bootstrap',
'portalUserAttr' => '_user',
'protection' => 'none',
'radiusAuthnLevel' => 3,
'randomPasswordRegexp' => '[A-Z]{3}[a-z]{5}.\\d{2}',
'redirectFormMethod' => 'get',
'registerConfirmSubject' =>
'[LemonLDAP::NG] Account register confirmation',
'registerDB' => 'Demo',
'registerDoneSubject' => '[LemonLDAP::NG] Your new account',
'registerTimeout' => 0,
'registerUrl' => 'http://auth.example.com/register.pl',
'remoteGlobalStorage' => 'Lemonldap::NG::Common::Apache::Session::SOAP',
'remoteGlobalStorageOptions' => {
'ns' =>
'http://auth.example.com/Lemonldap/NG/Common/CGI/SOAPService',
'proxy' => 'http://auth.example.com/index.pl/sessions'
},
'samlAttributeAuthorityDescriptorAttributeServiceSOAP' =>
'urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/AA/SOAP;',
'samlAuthnContextMapKerberos' => 4,
'samlAuthnContextMapPassword' => 2,
'samlAuthnContextMapPasswordProtectedTransport' => 3,
'samlAuthnContextMapTLSClient' => 5,
'samlCommonDomainCookieActivation' => 0,
'samlEntityID' => '#PORTAL#/saml/metadata',
'samlIDPMetaDataExportedAttributes' => ';;;',
'samlIDPMetaDataOptionsAdaptSessionUtime' => 0,
'samlIDPMetaDataOptionsAllowLoginFromIDP' => 0,
'samlIDPMetaDataOptionsAllowProxiedAuthn' => 0,
'samlIDPMetaDataOptionsCheckConditions' => 0,
'samlIDPMetaDataOptionsCheckSLOMessageSignature' => 0,
'samlIDPMetaDataOptionsCheckSSOMessageSignature' => 0,
'samlIDPMetaDataOptionsEncryptionMode' => 'none',
'samlIDPMetaDataOptionsForceAuthn' => 0,
'samlIDPMetaDataOptionsForceUTF8' => 0,
'samlIDPMetaDataOptionsIsPassive' => 0,
'samlIDPMetaDataOptionsNameIDFormat' => '',
'samlIDPMetaDataOptionsRequestedAuthnContext' => '',
'samlIDPMetaDataOptionsSignSLOMessage' => -1,
'samlIDPMetaDataOptionsSignSSOMessage' => -1,
'samlIDPMetaDataOptionsSSOBinding' => '',
'samlIdPResolveCookie' => 'lemonldapidp',
'samlIDPSSODescriptorArtifactResolutionServiceArtifact' =>
'1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact',
'samlIDPSSODescriptorSingleLogoutServiceHTTPPost' =>
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/singleLogout;#PORTAL#/saml/singleLogoutReturn',
'samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect' =>
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect;#PORTAL#/saml/singleLogout;#PORTAL#/saml/singleLogoutReturn',
'samlIDPSSODescriptorSingleLogoutServiceSOAP' =>
'urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/singleLogoutSOAP;',
'samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact' =>
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact;#PORTAL#/saml/singleSignOnArtifact;',
'samlIDPSSODescriptorSingleSignOnServiceHTTPPost' =>
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/singleSignOn;',
'samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect' =>
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect;#PORTAL#/saml/singleSignOn;',
'samlIDPSSODescriptorSingleSignOnServiceSOAP' =>
'urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/singleSignOnSOAP;',
'samlIDPSSODescriptorWantAuthnRequestsSigned' => 1,
'samlMetadataForceUTF8' => 1,
'samlNameIDFormatMapEmail' => 'mail',
'samlNameIDFormatMapKerberos' => 'uid',
'samlNameIDFormatMapWindows' => 'uid',
'samlNameIDFormatMapX509' => 'mail',
'samlOrganizationDisplayName' => 'Example',
'samlOrganizationName' => 'Example',
'samlOrganizationURL' => 'http://www.example.com',
'samlRelayStateTimeout' => 600,
'samlServicePrivateKeyEnc' => '',
'samlServicePrivateKeySig' => '',
'samlServicePrivateKeySigPwd' => '',
'samlServicePublicKeyEnc' => '',
'samlServicePublicKeySig' => '',
'samlSPMetaDataExportedAttributes' => ';;;',
'samlSPMetaDataOptionsCheckSLOMessageSignature' => 0,
'samlSPMetaDataOptionsCheckSSOMessageSignature' => 0,
'samlSPMetaDataOptionsEnableIDPInitiatedURL' => 0,
'samlSPMetaDataOptionsEncryptionMode' => 'none',
'samlSPMetaDataOptionsNameIDFormat' => '',
'samlSPMetaDataOptionsNotOnOrAfterTimeout' => 72000,
'samlSPMetaDataOptionsOneTimeUse' => 0,
'samlSPMetaDataOptionsSessionNotOnOrAfterTimeout' => 72000,
'samlSPMetaDataOptionsSignSLOMessage' => -1,
'samlSPMetaDataOptionsSignSSOMessage' => -1,
'samlSPSSODescriptorArtifactResolutionServiceArtifact' =>
'1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact',
'samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact' =>
'1;0;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact;#PORTAL#/saml/proxySingleSignOnArtifact',
'samlSPSSODescriptorAssertionConsumerServiceHTTPPost' =>
'0;1;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/proxySingleSignOnPost',
'samlSPSSODescriptorAuthnRequestsSigned' => 1,
'samlSPSSODescriptorSingleLogoutServiceHTTPPost' =>
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/proxySingleLogout;#PORTAL#/saml/proxySingleLogoutReturn',
'samlSPSSODescriptorSingleLogoutServiceHTTPRedirect' =>
'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect;#PORTAL#/saml/proxySingleLogout;#PORTAL#/saml/proxySingleLogoutReturn',
'samlSPSSODescriptorSingleLogoutServiceSOAP' =>
'urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/proxySingleLogoutSOAP;',
'samlSPSSODescriptorWantAssertionsSigned' => 1,
'samlUseQueryStringSpecific' => 0,
'securedCookie' => 0,
'secureTokenAllowOnError' => 1,
'secureTokenAttribute' => 'uid',
'secureTokenExpiration' => 60,
'secureTokenHeader' => 'Auth-Token',
'secureTokenMemcachedServers' => '127.0.0.1:11211',
'secureTokenUrls' => '.*',
'singleIP' => 0,
'singleSession' => 0,
'singleSessionUserByIP' => 0,
'singleUserByIP' => 0,
'slaveAuthnLevel' => 2,
'slaveExportedVars' => {},
'SMTPServer' => '',
'Soap' => 0,
'SSLAuthnLevel' => 5,
'storePassword' => 0,
'successLoginNumber' => 5,
'syslog' => '',
'timeout' => 72000,
'timeoutActivity' => 0,
'trustedProxies' => '',
'twitterAuthnLevel' => 1,
'userControl' => '^[\\w\\.\\-@]+$',
'userDB' => 'Demo',
'useRedirectOnError' => 1,
'useRedirectOnForbidden' => 0,
'useSafeJail' => 1,
'vhostHttps' => -1,
'vhostMaintenance' => 0,
'vhostPort' => -1,
'webIDAuthnLevel' => 1,
'webIDExportedVars' => {},
'whatToTrace' => 'uid',
'yubikeyAuthnLevel' => 3,
'yubikeyPublicIDSize' => 12,
'zimbraBy' => ''
};
}
1;

View File

@ -2,12 +2,30 @@ package Lemonldap::NG::Common::Conf::File;
use strict;
use Lemonldap::NG::Common::Conf::Constants; #inherits
use Lemonldap::NG::Common::Conf::Serializer;
our $VERSION = '1.4.0';
our $initDone;
sub Lemonldap::NG::Common::Conf::_lock {
my ( $self, $cfgNum ) = splice @_;
return "$self->{dirName}/lmConf.lock";
}
sub Lemonldap::NG::Common::Conf::_file {
my ( $self, $cfgNum ) = splice @_;
return "$self->{dirName}/lmConf-$cfgNum.js";
}
sub prereq {
my $self = shift;
unless ($initDone) {
eval "use JSON";
if ($@) {
$Lemonldap::NG::Common::Conf::msg .= "Unable to load JSON: $@\n";
return 0;
}
$initDone++;
}
unless ( $self->{dirName} ) {
$Lemonldap::NG::Common::Conf::msg .=
'"dirName" is required in "File" configuration type ! \n';
@ -26,7 +44,9 @@ sub available {
opendir D, $self->{dirName};
my @conf = readdir(D);
closedir D;
@conf = sort { $a <=> $b } map { /lmConf-(\d+)/ ? $1 : () } @conf;
@conf =
sort { $a <=> $b }
map { /lmConf-(\d+)(?:\.js)?/ ? ( $1 + 0 ) : () } @conf;
return @conf;
}
@ -42,9 +62,9 @@ sub lock {
sleep 2;
return 0 if ( $self->isLocked );
}
unless ( open F, ">" . $self->{dirName} . "/lmConf.lock" ) {
unless ( open F, ">" . $self->_lock ) {
$Lemonldap::NG::Common::Conf::msg .=
"Unable to lock (" . $self->{dirName} . "/lmConf.lock) \n";
"Unable to lock (" . $self->_lock . ") \n";
return 0;
}
print F $$;
@ -54,30 +74,25 @@ sub lock {
sub isLocked {
my $self = shift;
-e $self->{dirName} . "/lmConf.lock";
-e $self->_lock;
}
sub unlock {
my $self = shift;
unlink $self->{dirName} . "/lmConf.lock";
unlink $self->_lock;
1;
}
sub store {
my ( $self, $fields ) = @_;
$fields = $self->serialize($fields);
my $mask = umask;
umask( oct('0027') );
unless ( open FILE,
'>' . $self->{dirName} . "/lmConf-" . $fields->{cfgNum} )
{
unless ( open FILE, ">" . $self->_file( $fields->{cfgNum} ) ) {
$Lemonldap::NG::Common::Conf::msg .= "Open file failed: $! \n";
$self->unlock;
return UNKNOWN_ERROR;
}
foreach my $k ( sort keys %$fields ) {
print FILE "$k\n\t$fields->{$k}\n\n";
}
print FILE JSON->new->canonical(1)->encode($fields);
close FILE;
umask($mask);
return $fields->{cfgNum};
@ -86,29 +101,59 @@ sub store {
sub load {
my ( $self, $cfgNum, $fields ) = @_;
my $f;
local $/ = "";
unless ( open FILE, $self->{dirName} . "/lmConf-$cfgNum" ) {
$Lemonldap::NG::Common::Conf::msg .= "Open file failed: $! \n";
if ( -e $self->_file($cfgNum) ) {
local $/ = '';
open FILE, $self->_file($cfgNum) or die "$!$@";
$f = join( '', <FILE> );
close FILE;
my $ret = eval { decode_json($f); };
die "Unable to load conf: $@\n" if ($@);
return $ret;
}
# Old format
elsif ( -e "$self->{dirName}/lmConf-$cfgNum" ) {
open FILE, "$self->{dirName}/lmConf-$cfgNum" or die "$!$@";
local $/ = "";
unless ( open FILE, $self->{dirName} . "/lmConf-$cfgNum" ) {
$Lemonldap::NG::Common::Conf::msg .= "Open file failed: $! \n";
return undef;
}
while (<FILE>) {
my ( $k, $v ) = split /\n\s+/;
chomp $k;
$v =~ s/\n*$//;
if ($fields) {
$f->{$k} = $v if ( grep { $_ eq $k } @$fields );
}
else {
$f->{$k} = $v;
}
}
close FILE;
require Lemonldap::NG::Common::Conf::Serializer;
return $self->unserialize($f);
}
else {
$Lemonldap::NG::Common::Conf::msg .=
"Unable to find configuration file";
return undef;
}
while (<FILE>) {
my ( $k, $v ) = split /\n\s+/;
chomp $k;
$v =~ s/\n*$//;
if ($fields) {
$f->{$k} = $v if ( grep { $_ eq $k } @$fields );
}
else {
$f->{$k} = $v;
}
}
close FILE;
return $self->unserialize($f);
}
sub delete {
my ( $self, $cfgNum ) = @_;
unlink( $self->{dirName} . "/lmConf-$cfgNum" );
my $file = $self->_file($cfgNum);
if ( -e $file ) {
my $res = unlink($file);
$Lemonldap::NG::Common::Conf::msg .= $! unless ($res);
return $res;
}
else {
$Lemonldap::NG::Common::Conf::msg .=
"Unable to delete conf $cfgNum, no such file";
return 0;
}
}
1;

View File

@ -1,110 +1,9 @@
# Now, File.pm is a mix of the old File.pm and JSONFile.pm. So this file is
# just set for compatibility
package Lemonldap::NG::Common::Conf::JSONFile;
use strict;
use Lemonldap::NG::Common::Conf::Constants; #inherits
our $VERSION = '1.4.0';
our $initDone;
sub prereq {
my $self = shift;
unless ($initDone) {
eval "use JSON::Any";
if ($@) {
$Lemonldap::NG::Common::Conf::msg .=
"Unable to load JSON::Any: $@\n";
return 0;
}
$initDone++;
}
unless ( $self->{dirName} ) {
$Lemonldap::NG::Common::Conf::msg .=
'"dirName" is required in "JSONFile" configuration type ! \n';
return 0;
}
unless ( -d $self->{dirName} ) {
$Lemonldap::NG::Common::Conf::msg .=
"Directory \"$self->{dirName}\" does not exist ! \n";
return 0;
}
1;
}
sub available {
my $self = shift;
opendir D, $self->{dirName};
my @conf = readdir(D);
closedir D;
@conf = sort { $a <=> $b } map { /lmConf-(\d+)\.js/ ? $1 : () } @conf;
return @conf;
}
sub lastCfg {
my $self = shift;
my @avail = $self->available;
return $avail[$#avail];
}
sub lock {
my $self = shift;
if ( $self->isLocked ) {
sleep 2;
return 0 if ( $self->isLocked );
}
unless ( open F, ">" . $self->{dirName} . "/lmConf.lock" ) {
$Lemonldap::NG::Common::Conf::msg .=
"Unable to lock (" . $self->{dirName} . "/lmConf.lock) \n";
return 0;
}
print F $$;
close F;
return 1;
}
sub isLocked {
my $self = shift;
-e $self->{dirName} . "/lmConf.lock";
}
sub unlock {
my $self = shift;
unlink $self->{dirName} . "/lmConf.lock";
1;
}
sub store {
my ( $self, $fields ) = @_;
my $mask = umask;
umask( oct('0027') );
unless ( open FILE, ">$self->{dirName}/lmConf-$fields->{cfgNum}.js" ) {
$Lemonldap::NG::Common::Conf::msg .= "Open file failed: $! \n";
$self->unlock;
return UNKNOWN_ERROR;
}
print FILE JSON::Any->objToJson($fields);
close FILE;
umask($mask);
return $fields->{cfgNum};
}
sub load {
my ( $self, $cfgNum, $fields ) = @_;
my $f = '';
open FILE, "$self->{dirName}/lmConf-$cfgNum.js" or die "$!$@";
while (<FILE>) {
$f .= $_;
}
close FILE;
my $ret;
eval { $ret = JSON::Any->jsonToObj($f); };
die "Unable to load conf: $@\n" if ($@);
return $ret;
}
sub delete {
my ( $self, $cfgNum ) = @_;
unlink( $self->{dirName} . "/lmConf-$cfgNum.js" );
}
use Lemonldap::NG::Common::Conf::File;
our @ISA = qw(Lemonldap::NG::Common::Conf::File);
1;
__END__

View File

@ -0,0 +1,151 @@
package Lemonldap::NG::Common::PSGI;
use 5.10.0;
use Mouse;
use JSON;
use Lemonldap::NG::Common::PSGI::Constants;
use Lemonldap::NG::Common::PSGI::Request;
our $VERSION = '1.5.99';
our $_json = JSON->new->allow_nonref;
has error => ( is => 'rw', default => '' );
has languages => ( is => 'rw', isa => 'Str', default => 'en' );
has logLevel => ( is => 'rw', isa => 'Str' );
has staticPrefix => ( is => 'rw', isa => 'Str' );
has templateDir => ( is => 'rw', isa => 'Str' );
has links => ( is => 'rw', isa => 'ArrayRef' );
sub lmLog {
my ( $self, $msg, $level ) = splice @_;
my $levels = {
emerg => 7,
alert => 6,
crit => 5,
error => 4,
warn => 3,
notice => 2,
info => 1,
debug => 0
};
my $l = $levels->{$level} || 1;
return if ( ref($self) and $l < $levels->{ $self->{logLevel} } );
print STDERR "[$level] " . ( $l ? '' : (caller)[0] . ': ' ) . " $msg\n";
}
# Responses methods
sub sendJSONresponse {
my ( $self, $req, $j, %args ) = splice @_;
$args{code} ||= 200;
my $type = 'text/json';
if ( ref $j ) {
if ( $args{forceJSON} or $req->accept =~ m|application/json| ) {
$j = $_json->encode($j);
}
else {
# TODO: escape keys in hash values
eval {
require XML::Simple;
$j = XML::Simple::XMLout($j);
$type = 'text/xml';
};
}
}
return [ $args{code}, [ 'Content-Type', $type ], [$j] ];
}
sub sendError {
my ( $self, $req, $err, $code ) = splice @_;
$err ||= $req->error;
$code ||= 500;
return $self->sendJSONresponse( $req, { error => $err }, code => $code );
}
sub abort {
my ( $self, $err ) = splice @_;
$self->lmLog( $err, 'error' );
return sub {
$self->sendError( Lemonldap::NG::Common::PSGI::Request->new( $_[0] ),
$err, 500 );
};
}
sub _mustBeDefined {
my $name = ( caller(1) )[3];
$name =~ s/^.*:://;
my $call = ( caller(1) )[0];
my $ref = ref( $_[0] ) || $call;
die "$name() method must be implemented (probably in $ref)";
}
sub init { 1 }
sub router { _mustBeDefined(@_) }
sub sendHtml {
my ( $self, $req, $template ) = splice @_;
my $htpl;
$template = $self->templateDir . "$template.tpl";
return $self->sendError( $req, "Unable to read $template", 500 )
unless ( -r $template and -f $template );
eval {
$self->lmLog( "Starting HTML generation using $template", 'debug' );
require HTML::Template;
$htpl = HTML::Template->new(
filehandle => IO::File->new($template),
path => $self->templateDir,
die_on_bad_params => 1,
die_on_missing_include => 1,
cache => 0,
);
# TODO: replace app
# TODO: warn if STATICPREFIX does not end with '/'
my $sp = $self->staticPrefix;
$sp =~ s/\/*$/\//;
$htpl->param(
SCRIPT_NAME => $req->scriptname,
STATIC_PREFIX => $sp,
AVAILABLE_LANGUAGES => $self->languages,
LINKS => $self->links ? encode_json( $self->links ) : '""',
);
};
if ($@) {
return $self->sendError( $req, "Unable to load template: $@", 500 );
}
$self->lmLog(
'For more performance, store the result of this as static file',
'info' );
# Set headers
my $hdrs = [ 'Content-Type' => 'text/html' ];
unless ( $self->logLevel eq 'debug' ) {
push @$hdrs,
ETag => "LMNG-manager-$VERSION",
'Cache-Control' => 'private, max-age=2592000';
}
$self->lmLog( "Sending $template", 'debug' );
return [ 200, $hdrs, [ $htpl->output() ] ];
}
###############
# Main method #
###############
sub run {
my ( $self, $args ) = splice @_;
$self = $self->new($args) unless ref($self);
return $self->abort( $self->error ) unless ( $self->init($args) );
return $self->_run;
}
sub _run {
my $self = shift;
return sub {
$self->router( Lemonldap::NG::Common::PSGI::Request->new( $_[0] ) );
};
}
1;

View File

@ -0,0 +1,25 @@
package Lemonldap::NG::Common::PSGI::Constants;
use strict;
use Exporter 'import';
use base qw(Exporter);
our $VERSION = '1.5.99';
# CONSTANTS
use constant {
DEBUG => 4,
INFO => 3,
WARN => 2,
NOTICE => 1,
ERROR => 0,
};
our $no = qr/^(?:off|no|0)?$/i;
our %EXPORT_TAGS = ( 'all' => [qw(DEBUG INFO WARN ERROR $no)] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = ( @{ $EXPORT_TAGS{'all'} } );
1;

View File

@ -0,0 +1,140 @@
package Lemonldap::NG::Common::PSGI::Request;
use strict;
use Mouse;
use JSON;
use URI::Escape;
our $VERSION = '1.5.99';
# http :// server / path ? query # fragment
# m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;
has HTTP_ACCEPT => ( is => 'ro', reader => 'accept' );
has HTTP_ACCEPT_ENCODING => ( is => 'ro', reader => 'encodings' );
has HTTP_ACCEPT_LANGUAGE => ( is => 'ro', reader => 'languages' );
has HTTP_COOKIE => ( is => 'ro', reader => 'cookies' );
has HTTP_HOST => ( is => 'ro', reader => 'hostname' );
has REMOTE_ADDR => ( is => 'ro', isa => 'Str', reader => 'remote_ip' );
has REMOTE_PORT => ( is => 'ro', isa => 'Int', reader => 'port' );
has REQUEST_METHOD => ( is => 'ro', isa => 'Str', reader => 'method' );
has SCRIPT_NAME => ( is => 'ro', isa => 'Str', reader => 'scriptname' );
has SERVER_PORT => ( is => 'ro', isa => 'Int', reader => 'get_server_port' );
has PATH_INFO => (
is => 'ro',
reader => 'path',
lazy => 1,
default => '',
trigger => sub {
$_[0]->{REQUEST_URI} = uri_unescape( $_[0]->{REQUEST_URI} );
$_[0]->{REQUEST_URI} =~ s|//+|/|;
},
);
has REQUEST_URI => (
is => 'ro',
reader => 'uri',
trigger => sub {
$_[0]->{unparsed_uri} = $_[0]->{REQUEST_URI};
$_[0]->{REQUEST_URI} = uri_unescape( $_[0]->{REQUEST_URI} );
},
);
has unparsed_uri => ( is => 'rw', isa => 'Str' );
has 'psgi.errors' => ( is => 'rw', reader => 'stderr' );
# Authentication
has REMOTE_USER => (
is => 'ro',
isa => 'Int',
reader => 'user',
trigger => sub {
$_[0]->{userData} = { _whatToTrace => $_[0]->{REMOTE_USER}, };
},
);
has userData => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
# Query parameters
has _params => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
has QUERY_STRING => (
is => 'ro',
reader => 'query',
trigger => sub {
my $self = shift;
$self->{QUERY_STRING} = uri_unescape( $self->{QUERY_STRING} );
my @tmp =
$self->{QUERY_STRING}
? split /&/, $self->{QUERY_STRING}
: ();
foreach my $s (@tmp) {
if ( $s =~ /^(.+?)=(.+)$/ ) { $self->{_params}->{$1} = $2; }
else { $self->{_params}->{$s} = 1; }
}
},
);
sub params {
my ( $self, $key, $value ) = splice @_;
return $self->_params unless ($key);
$self->_params->{$key} = $value if ($value);
return $self->_params->{$key};
}
# POST management
#
# When CONTENT_LENGTH is set, store body in memory in `body` key
has 'psgix.input.buffered' => ( is => 'ro', reader => '_psgixBuffered', );
has 'psgi.input' => ( is => 'ro', reader => '_psgiInput', );
has body => ( is => 'rw', isa => 'Str', default => '' );
has CONTENT_TYPE => ( is => 'ro', isa => 'Str', reader => 'contentType', );
has CONTENT_LENGTH => (
is => 'ro',
isa => 'Int',
reader => 'contentLength',
lazy => 1,
default => 0,
trigger => sub {
my $self = shift;
if ( $self->method eq 'GET' ) { $self->{body} = undef; }
elsif ( $self->method =~ /^(?:POST|PUT)$/ ) {
$self->{body} = '';
if ( $self->_psgixBuffered ) {
my $length = $self->{CONTENT_LENGTH};
while ( $length > 0 ) {
my $buffer;
$self->_psgiInput->read( $buffer,
( $length < 8192 ) ? $length : 8192 );
$length -= length($buffer);
$self->{body} .= $buffer;
}
}
else {
$self->_psgiInput->read( $self->{body},
$self->{CONTENT_LENGTH}, 0 );
}
}
}
);
has error => ( is => 'rw', isa => 'Str', default => '' );
# JSON parser
sub jsonBodyToObj {
my $self = shift;
unless ( $self->contentType =~ /application\/json/ ) {
$self->error('Data is not JSON');
return undef;
}
unless ( $self->body ) {
$self->error('No data');
return undef;
}
return $self->body if ( ref( $self->body ) );
my $j = eval { decode_json( $self->body ) };
if ( $@ or $! ) {
$self->error("$@$!");
return undef;
}
return $self->{body} = $j;
}
1;

View File

@ -0,0 +1,152 @@
package Lemonldap::NG::Common::PSGI::Router;
use Mouse;
use Lemonldap::NG::Common::PSGI;
use Lemonldap::NG::Common::PSGI::Constants;
our $VERSION = '1.5.99';
extends 'Lemonldap::NG::Common::PSGI';
# Properties
has 'routes' => (
is => 'rw',
isa => 'HashRef',
default => sub { { GET => {}, POST => {}, PUT => {}, DELETE => {} } }
);
has 'defaultRoute' => ( is => 'rw', default => 'index.html' );
# Routes initialization
sub addRoute {
my ( $self, $word, $dest, $methods ) = splice(@_);
$methods ||= [qw(GET POST PUT DELETE)];
foreach my $method (@$methods) {
$self->genRoute( $self->routes->{$method}, $word, $dest );
}
return $self;
}
sub genRoute {
my ( $self, $routes, $word, $dest ) = splice @_;
if ( ref $word eq 'ARRAY' ) {
foreach my $w (@$word) {
$self->genRoute( $routes, $w, $dest );
}
}
else {
if ( $word =~ /^:(.*)$/ ) {
$routes->{'#'} = $1;
die "Target required for $word" unless ($dest);
$word = ':';
}
else {
$dest ||= $word;
}
if ( my $t = ref $dest ) {
if ( $t eq 'CODE' ) {
$routes->{$word} = $dest;
}
elsif ( $t eq 'HASH' ) {
$routes->{$word} ||= {};
foreach my $w ( keys %$dest ) {
$self->genRoute( $routes->{$word}, $w, $dest->{$w} );
}
}
elsif ( $t eq 'ARRAY' ) {
$routes->{$word} ||= {};
foreach my $w ( @{$dest} ) {
$self->genRoute( $routes->{$word}, $w );
}
}
else {
die "Type $t unauthorizated in routes";
}
}
elsif ( $dest =~ /^(.+)\.html$/ ) {
my $tpl = $1 or die;
$routes->{$word} = sub { $self->sendHtml( $_[1], $tpl ) };
}
elsif ( $self->can($dest) ) {
$routes->{$word} = sub { shift; $self->$dest(@_) };
}
else {
die "$dest() isn't a method";
}
$self->lmLog( "route $word added", 'debug' );
}
}
sub abort {
my ( $self, $path, $msg ) = splice @_;
delete $self->routes->{$path};
$self->addRoute(
$path => sub {
my ( $self, $req ) = splice @_;
return $self->sendError( $req, $msg, 500 );
}
);
}
# Methods that dispatch requests
sub router {
my ( $self, $req ) = splice @_;
#print STDERR Dumper($self->routes);use Data::Dumper;
# Reinitialize configuration message
$Lemonldap::NG::Common::Conf::msg = '';
# Launch reqInit() if exists
if ( $self->can('reqInit') ) {
$self->reqInit($req);
}
# Only words are taken in path
my @path = grep { $_ =~ /^[\.\w]+/ } split /\//, $req->path();
$self->lmLog( "Start routing " . ( $path[0] // 'default route' ), 'debug' );
unless (@path) {
push @path, $self->defaultRoute;
# TODO: E-Tag, Expires,...
#
## NB: this is not HTTP compliant: host and protocol are required !
#my $url = '/' . $self->defaultRoute;
#return [
# 302,
# [ 'Content-Type' => 'text/plain', 'Location' => $url ],
# ['Document has moved here: $url']
#];
}
return $self->followPath( $req, $self->routes->{ $req->method }, \@path );
}
sub followPath {
my ( $self, $req, $routes, $path ) = splice @_;
if ( $path->[0] and defined $routes->{ $path->[0] } ) {
my $w = shift @$path;
if ( ref( $routes->{$w} ) eq 'CODE' ) {
return $routes->{$w}->( $self, $req, @$path );
}
return $self->followPath( $req, $routes->{$w}, $path );
}
elsif ( $routes->{':'} ) {
my $v = shift @$path;
$req->params->{ $routes->{'#'} } = $v;
if ( ref( $routes->{':'} ) eq 'CODE' ) {
return $routes->{':'}->( $self, $req, @$path );
}
return $self->followPath( $req, $routes->{':'}, $path );
}
elsif ( my $sub = $routes->{'*'} ) {
return $self->$sub( $req, @$path );
}
else {
$self->lmLog( 'Bad request received (' . $req->path . ')', 'warn' );
return $self->sendError( $req, 'Bad request', 400 );
}
}
1;

View File

@ -40,9 +40,10 @@ my $mp = $ENV{MOD_PERL_API_VERSION};
my $mode =
$gi && $gi =~ /^CGI/ ? "CGI"
: $mp && $mp >= 2 ? "ApacheMP2"
: $mp ? "ApacheMP1"
: $main::{'nginx::'} ? "Nginx"
: "CGI";
: $mp ? "ApacheMP1"
: $main::{'nginx::'} ? "Nginx"
: ( caller(6) )[0] eq 'Lemonldap::NG::Handler::PSGI' ? "PSGI"
: "CGI";
# Load API functions and constants
eval "use Lemonldap::NG::Handler::API::$mode (':httpCodes', ':functions');

View File

@ -0,0 +1,186 @@
package Lemonldap::NG::Handler::API::PSGI;
use Exporter 'import';
our $VERSION = '1.4.0';
our ( %EXPORT_TAGS, @EXPORT_OK, @EXPORT );
BEGIN {
%EXPORT_TAGS = (
httpCodes => [
qw( OK REDIRECT FORBIDDEN DONE DECLINED SERVER_ERROR AUTH_REQUIRED MAINTENANCE $logLevel )
],
functions => [
qw( &hostname &remote_ip &uri &uri_with_args
&unparsed_uri &args &method &header_in )
]
);
push( @EXPORT_OK, @{ $EXPORT_TAGS{$_} } ) foreach ( keys %EXPORT_TAGS );
$EXPORT_TAGS{all} = \@EXPORT_OK;
}
# Specific modules and constants for Test or CGI
use constant FORBIDDEN => 403;
use constant REDIRECT => 302;
use constant OK => 0;
use constant DECLINED => 0;
use constant DONE => 0;
use constant SERVER_ERROR => 500;
use constant AUTH_REQUIRED => 401;
use constant MAINTENANCE => 503;
my $request;
## @method void thread_share(string $variable)
# share or not the variable (if authorized by specific module)
# @param $variable the name of the variable to share
sub thread_share {
# nothing to do in PSGI
}
sub newRequest {
my ( $class, $r ) = @_;
$request = $r;
}
## @method void lmLog(string $msg, string $level)
# logs message $msg to STDERR with level $level
# set Env Var lmLogLevel to set loglevel; set to "info" by default
# @param $msg string message to log
# @param $level string loglevel
*lmLog = *Lemonldap::NG::Common::PSGI::lmLog;
## @method void set_user(string user)
# sets remote_user
# @param user string username
sub set_user {
my ( $class, $user ) = splice @_;
# TODO
}
## @method string header_in(string header)
# returns request header value
# @param header string request header
# @return request header value
sub header_in {
my ( $class, $header ) = @_;
$header ||= $class; # to use header_in as a method or as a function
return $request->{ cgiName($header) };
}
## @method void set_header_in(hash headers)
# sets or modifies request headers
# @param headers hash containing header names => header value
sub set_header_in {
my ( $class, %headers ) = @_;
while ( my ( $h, $v ) = each %headers ) {
$request->{ cgiName($h) } = $v;
}
}
## @method void unset_header_in(array headers)
# removes request headers
# @param headers array with header names to remove
sub unset_header_in {
my ( $class, @headers ) = @_;
foreach my $h (@headers) {
delete $request->{ cgiName($h) };
}
}
## @method void set_header_out(hash headers)
# sets response headers
# @param headers hash containing header names => header value
sub set_header_out {
my ( $class, %headers ) = @_;
while ( my ( $h, $v ) = each %headers ) {
$request->{respHeaders}->{$h} = $v;
}
}
## @method string hostname
# returns host, as set by full URI or Host header
# @return host string Host value
sub hostname {
my $h = $request->hostname;
$h =~ s/:\d+//;
return $h;
}
## @method string remote_ip
# returns client IP address
# @return IP_Addr string client IP
sub remote_ip {
return $request->remote_ip;
}
## @method boolean is_initial_req
# always returns true
# @return is_initial_req boolean
sub is_initial_req {
return 1;
}
## @method string args(string args)
# gets the query string
# @return args string Query string
sub args {
return $request->query;
}
## @method string uri
# returns the path portion of the URI, normalized, i.e. :
# * URL decoded (characters encoded as %XX are decoded,
# except ? in order not to merge path and query string)
# * references to relative path components "." and ".." are resolved
# * two or more adjacent slashes are merged into a single slash
# @return path portion of the URI, normalized
sub uri {
return $request->uri;
}
## @method string uri_with_args
# returns the URI, with arguments and with path portion normalized
# @return URI with normalized path portion
sub uri_with_args {
return $request->uri;
}
## @method string unparsed_uri
# returns the full original request URI, with arguments
# @return full original request URI, with arguments
sub unparsed_uri {
return $request->unparsed_uri;
}
## @method string get_server_port
# returns the port the server is receiving the current request on
# @return port string server port
sub get_server_port {
return $request->get_server_port;
}
## @method string method
# returns the request method
# @return port string server port
sub method {
return $request->method;
}
## @method void print(string data)
# write data in HTTP response body
# @param data Text to add in response body
sub print {
my ( $class, $data ) = @_;
$request->{respBody} .= $data;
}
sub cgiName {
my $h = uc(shift);
$h =~ s/-/_/g;
return "HTTP_$h";
}
1;

View File

@ -26,7 +26,7 @@ BEGIN {
sub logLevelInit {
my ( $class, $level ) = @_;
$logLevel = $level || $Lemonldap::NG::Handler::API::logLevel || "debug";
$logLevel = $logLevels->{$logLevel};
$logLevel = $logLevels->{$logLevel} || 0;
}
## @rmethod void lmLog(string msg, string level)

View File

@ -0,0 +1,71 @@
package Lemonldap::NG::Handler::PSGI;
use 5.10.0;
use Mouse;
use Lemonldap::NG::Handler::SharedConf qw(:tsv :variables);
extends 'Lemonldap::NG::Common::PSGI::Router';
our $VERSION = 1.5.99;
around init => sub {
my ( $method, $self, $args ) = splice @_;
Lemonldap::NG::Handler::SharedConf->init( $self );
return $self->$method($args);
};
sub _run {
my $self = shift;
my $rule = $self->{protection} || $localConfig->{protection};
if ( $rule ne 'none' ) {
$rule =
$rule eq "authenticate" ? "accept" : $rule eq "manager" ? "" : $rule;
return sub {
my $req = Lemonldap::NG::Common::PSGI::Request->new( $_[0] );
Lemonldap::NG::Handler::API->newRequest($req);
my $res = Lemonldap::NG::Handler::SharedConf->run($rule);
# TODO: Userdata
#print STDERR Dumper( \@_, $res ); use Data::Dumper;
if ( $res == 403 ) {
return [
403,
[ 'Content-Type' => 'text/plain' ],
["You don't have rights to access this page"]
];
}
# Ajax hook: Ajax requests can not understand 30x responses. This
# is not really HTTP compliant but nothing in this
# protocol can do this. Our javascript understand that
# it has to prompt user with the URL
elsif (
( $res == 302 or $res == 303 )
and ( $req->accept =~ m|application/json|
or $req->contentType =~ m|application/json| )
)
{
return [
401, [ Authorization => $req->{respHeaders}->{Location} ],
['']
];
}
elsif ($res) {
return [ $res, [ %{ $req->{respHeaders} } ], [''] ];
}
else {
return $self->router($req);
}
};
}
else {
eval { Lemonldap::NG::Handler::SharedConf->checkConf() } unless (%$tsv);
$self->lmLog( $@, 'error' ) if ($@);
return sub {
#print STDERR Dumper(\@_);use Data::Dumper;
$self->router( Lemonldap::NG::Common::PSGI::Request->new( $_[0] ) );
};
}
}
1;

View File

@ -0,0 +1,31 @@
# Lemonldap::NG::Manager kinematic
## Initialization
PSGI file
|
+-> Common::PSGI::run() (Manager inheritance)
|
+-> Common::PSGI::new() unless(defined $self)
|
+-> Manager::init()
|
+-> Manager::<modules>::addRoutes()
(module can be one of `Conf`, `Sessions`, `Notifications`
|
+-> Common::PSGI::Router::addRoute()
_Common::PSGI::run()_ returns a subroutine
## HTTP responses
PSGI system launch the previous sub
sub
|
+-> Common::PSGI::Router::router ( Lemonldap::NG::Common::PSGI::Request->new() )
|
+-> Common::PSGI::Router::followPath()
|
+-> Launch the corresponding Manager::<module> subroutine declared with addRoutes()

View File

@ -0,0 +1,42 @@
# angular-lemonldap-ng-manager
This is just a POC to build an angular based manager for
Lemonldap::NG.
See [LemonLDAP::NG website](http://lemonldap-ng.org/).
## Install
git clone https://github.com/guimard/angular-lemonldap-ng-manager.git
cd angular-lemonldap-ng-manager
npm install
## Start servers
npm run perlserver
npm start
## MVC
* The view is managed by :
* `index.html` for HTML building
* _some other html files for forms ?_
* `struct.json` who gives the tree position for each configuration element and
requests to do
* translate.json (which will be delivered by a CGI to choose current language)
* The controller is splitted in 2 pieces :
* client side in `js/manager.js`, based on ANgularJS, it provides the link
between the DOM and the CGI. It manages:
* downloads of JSON datas
* translations
* form display depending on data types
* server side, based on PSGI, it provides the link between network and
configuration. It will be able to respond to 3 types of _rest_ queries:
* key values
* hash keys for this type of nodes
* hash content
* The model (datas) is:
* the current configuration
* the modified datas _(client side only or both to be able to notify changes
to other administrators ?)_

View File

@ -0,0 +1,65 @@
# Lemonldap::NG::Manager REST API
## Configurations
* List of available configuration: `/confs`
* Last configuration number: `/confs/latest/cfgNum`
* Configuration metadatas: `/confs/<cfgNum|latest>`
* Key value: `/confs/<cfgNum|latest>/<key>`
* Full configuration (for saving): `/confs/<cfgNum|latest>?full`
Examples:
* `/confs/latest/portal`
* `/confs/184/portal`
* `/confs/184/virtualHosts/test1.example.com/locationRules`
### Available verbs:
* `GET`: see above
* `POST /confs`: push a new configuration (or a saved one)
`POST /confs?force=yes`: push a new configuration even if another has been
posted before
* _`DELETE /confs/<cfgNum>`: not allowed_, administrator has to push an older
with `?force=yes`
**And perhaps:**
* `PUT /confs/prepared/<key>`: modify a value in the future configuration
* `DELETE /confs/prepared/<path>/<key>`: delete a hash entry (virtual host for
example)
* `GET /confs/prepared/<key>`: get value from prepared configuration if exists,
get current value otherwise
## Sessions
* Sessions list: `/sessions`
* Session: `/sessions/<hash>`
* **TODO**: Session key: `/sessions/<hash>/<key>`
* Delete session: `DELETE /sessions/<hash>`
* Filters:
* All connected users which username start by a letter:
`/sessions?_whatToTrace=<letter>*&groupBy=_whatToTrace`
* User's sessions: `/sessions?_whatToTrace=foo.bar`
* IP's sessions: `/sessions?ip=1.2.3.4`
* Double sessions by IP: `/sessions?doubleIP`
* Group by:
* First letter of Connected users: `/sessions?groupBy=substr(_whatToTrace,1)`
* Order:
* Sessions sorted by user: `/sessions?orderBy=_whatToTrace`
Note that sessions are grouped automaticaly.
## Notifications
* Notifications list: `/notifications/actives`
* Notification: `/notifications/actives/<notif_id>`
* Notified elements list: `/notifications/done`
* Notified element: `/notifications/done/<notif_id>`
* New session: `POST /notifications`
* Filters:
* All notifications for users which name starts by a letter:
`/notifications?_whatToTrace=<letter>*&groupBy=_whatToTrace`
* User's notifications: `/notifications/(actives|done)?_whatToTrace=foo.bar`
* Mark as notified: `PUT /notifications/actives/<notif_id> done=1`
* Delete notofication: `DELETE /notifications/done/<notif_id>`

View File

@ -0,0 +1,58 @@
# Lemonldap::NG::Manager TODO list
* Check for eval with SAML
* userInfo && userWarn
* Help interface
## Configuration management
* `currentConf` => `$req` instead of `$self`
* PSGI: improve log system (syslog,...)
* Forms:
* issuers resume
### Struct & datas
* Tests for new confs
* default values: TODO, deliver a "0" conf when no conf is available
* Forms:
* file: load from URL + download
* Grant session rule
* OpenID white/black list
* oidcOpMetadata ?
* import from JSON
### REST API:
### PSGI authentication
* JQuery module to add `$._llngAjax`
* Angular module to add $llngHttp
### Help system
## Sessions explorer
## Optimization
* Create modules to get needed values for a new conf without using
`Common::Conf::Attributes`
* Then delete essential default values in running modules: they have to be
provided by any configuration
* Use JSON to store datas:
* configuration: the new `File` will look at the first character. If not `{`,
it will call old `File` functions
* sessions: new Apache::Session::Serialize::JSON module
## Doc
* Wiki doc
* Developer corner:
* adding a configurationkey
* adding a data type
## Question more
* Phonegap
* Ionic

View File

@ -0,0 +1,15 @@
{
"name": "angular-lemonldap-ng-manager",
"description": "Lemonldap::NG manager with AngularJS",
"version": "0.0.0",
"homepage": "https://github.com/guimard/angular-lemonldap-ng-manager",
"license": "GPL2",
"private": true,
"dependencies": {
"angular": "1.3.x",
"angular-route": "1.x",
"angular-ui-tree": "2.1.5",
"bootstrap": "~3.1.1",
"jquery": "~2.1.1"
}
}

View File

@ -0,0 +1,5 @@
#!/usr/bin/env plackup -I pl/lib
use Lemonldap::NG::Manager;
Lemonldap::NG::Manager->run({});

View File

@ -1,54 +0,0 @@
#!/usr/bin/perl
use strict;
use Lemonldap::NG::Manager;
use HTML::Template;
my $manager = new Lemonldap::NG::Manager(
{
# ACCESS TO CONFIGURATION
# By default, Lemonldap::NG uses the default storage.conf file to know
# where to find is configuration
# (generaly /etc/lemonldap-ng/storage.conf)
# You can specify by yourself this file :
#configStorage => { confFile => '/path/to/my/file' },
# You can also specify directly the configuration
# (see Lemonldap::NG::Handler::SharedConf(3))
#configStorage => {
# type => 'File',
# directory => '/usr/local/lemonldap-ng/conf/'
#},
}
) or Lemonldap::NG::Common::CGI->abort('Unable to start manager');
our $skin = $manager->{managerSkin};
our $skin_dir = 'skins';
our $main_dir = $manager->getApacheHtdocsPath;
my $template = HTML::Template->new(
filename => "$main_dir/$skin_dir/$skin/manager.tpl",
die_on_bad_params => 0,
cache => 0,
filter => sub { $manager->translate_template(@_) },
);
$template->param( SCRIPT_NAME => $ENV{SCRIPT_NAME} );
$template->param( MENU => $manager->menu() );
$template->param( DIR => "$skin_dir/$skin" );
$template->param( CFGNUM => $manager->{cfgNum} );
$template->param( TREE_AUTOCLOSE => $manager->{managerTreeAutoClose} );
$template->param( TREE_JQUERYCSS => $manager->{managerTreeJqueryCss} );
$template->param( CSS => $manager->{managerCss} );
$template->param( CSS_THEME => $manager->{managerCssTheme} );
$template->param( VERSION => $Lemonldap::NG::Manager::VERSION );
$template->param( LANG => shift @{ $manager->{lang} } );
$template->param( PORTAL_URL => $manager->{portal} );
$template->param( LI_CLASS_CONFIGURATION => "active" );
$template->param( LI_CLASS_SESSION => "" );
$template->param( LI_CLASS_NOTIFICATION => "" );
print $manager->header('text/html; charset=utf-8');
print $template->output;

View File

@ -1,46 +0,0 @@
#!/usr/bin/perl
use strict;
use LWP::UserAgent;
my($host, $url, $type1, $type2) = @ARGV;
die("Usage: $0 host url data-type")unless($host and $url and $type1);
my $ua = LWP::UserAgent->new();
$ua->timeout(10);
my ( $method, $vhost, $uri ) = ( $url =~ /^(https?):\/\/([^\/]+)(.*)$/ );
unless ($vhost) {
$vhost = $host;
$uri = $url;
}
my $r = HTTP::Request->new( 'GET', "$method://$host$uri", HTTP::Headers->new( Host => $vhost ) );
my $response = $ua->request($r);
if ( $response->code != 200 ) {
print STDERR "$host: ".join( ' ', &txt_error, ":", $response->code, $response->message, "</li>");
return 1;
}
my $tot=0;
my $res;
foreach (split(/\n/s, $response->content)) {
$tot++ if(/<div id="total">/);
$tot=0 if(/<\/div>/);
if($tot) {
/^(\w+)\s*:\s*(\d+)/ or next;
$res->{$1} = $2;
}
$res->{localCache} = $1 if(/^Local Cache\s*:\s*(\d+)/i);
$res->{up} = $1 if(/^Server up for\s*:\s*(\d+d\s+\d+h\s+\d+mn)/);
}
foreach(keys %$res) {
print "$res->{$_}\n" if(/^$type1$/i);
}
if($type2) {
foreach(keys %$res) {
print "$res->{$_}\n" if(/^$type2$/i);
}
}
print "$res->{up}\n$host";

View File

@ -1,30 +0,0 @@
######################################################################
# Multi Router Traffic Grapher -- Sample Configuration File
######################################################################
# This file is for use with mrtg-2.5.4c
# Global configuration
WorkDir: /var/www/mrtg
WriteExpires: Yes
Title[^]: Traffic Analysis for
# 128K leased line
# ----------------
#Title[leased]: a 128K leased line
#PageTop[leased]: <H1>Our 128K link to the outside world</H1>
#Target[leased]: 1:public@router.localnet
#MaxBytes[leased]: 16000
Target[test.example.com]: `/etc/mrtg/lmng-mrtg 172.16.1.2 https://test.example.com/status OK OK`
Options[test.example.com]: nopercent, growright, nobanner, perminute
PageTop[test.example.com]: <h1>Requests OK from test.example.com</h1>
MaxBytes[test.example.com]: 1000000
YLegend[test.example.com]: hits/minute
ShortLegend[test.example.com]: &nbsp; hits/mn
LegendO[test.example.com]: Hits:
LegendI[test.example.com]: Hits:
Legend2[test.example.com]: Hits per minute
Legend4[test.example.com]: Hits max per minute
Title[test.example.com]: Hits per minute
WithPeak[test.example.com]: wmy

View File

@ -1,9 +0,0 @@
<html>
<head>
<title>Page not found</title>
</head>
<body style="background:#FFF;text-align:center;">
<h1>Page not found</h1>
<h2>Please install documentation package to get offline doc</h2>
</body>
</html>

View File

@ -1,10 +0,0 @@
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Page non trouvée</title>
</head>
<body style="background:#FFF;text-align:center;">
<h1>Page non trouvée</h1>
<h2>Merci d'installer le paquet contenant la documentation française</h2>
</body>
</html>

View File

@ -1,58 +0,0 @@
#!/usr/bin/perl
use strict;
use Lemonldap::NG::Manager;
use Lemonldap::NG::Manager::Notifications;
use HTML::Template;
my $cgi = Lemonldap::NG::Manager::Notifications->new(
{
# SESSION EXPLORER CUSTOMIZATION
#managerSkin => 'default',
# ACCESS TO CONFIGURATION
# By default, Lemonldap::NG uses the default storage.conf file to know
# where to find is configuration
# (generaly /etc/lemonldap-ng/storage.conf)
# You can specify by yourself this file :
#configStorage => { type => 'File', dirName => '/path/to/my/file' },
# You can also specify directly the configuration
# (see Lemonldap::NG::Handler::SharedConf(3))
#configStorage => {
# type => 'File',
# directory => '/usr/local/lemonlda-ng/conf/'
#},
}
)
or
Lemonldap::NG::Common::CGI->abort('Unable to start notifications explorer');
my $skin = $cgi->{managerSkin} or $cgi->abort('managerSkin is not defined');
my $css = 'tree.css';
my $css_theme = 'ui-lightness';
my $skin_dir = 'skins';
my $main_dir = $cgi->getApacheHtdocsPath;
my $template = HTML::Template->new(
filename => "$main_dir/$skin_dir/$skin/notifications.tpl",
die_on_bad_params => 0,
cache => 0,
filter => sub { $cgi->translate_template(@_) },
);
$template->param( SCRIPT_NAME => $ENV{SCRIPT_NAME} );
$template->param( TREE => $cgi->tree() );
$template->param( DIR => "$skin_dir/$skin" );
$template->param( CSS => $css );
$template->param( CSS_THEME => $css_theme );
$template->param( VERSION => $Lemonldap::NG::Manager::VERSION );
$template->param( LANG => shift @{ $cgi->{lang} } );
$template->param( PORTAL_URL => $cgi->{portal} );
$template->param( LI_CLASS_CONFIGURATION => "" );
$template->param( LI_CLASS_SESSION => "" );
$template->param( LI_CLASS_NOTIFICATION => "active" );
print $cgi->header('text/html; charset=utf-8');
print $template->output;

View File

@ -1,110 +0,0 @@
#!/usr/bin/perl -w
use Lemonldap::NG::Manager::Cli;
use POSIX qw(setuid setgid);
use strict;
sub giveUpPrivileges {
my ( $user, $group ) = @_;
$user = "nobody" unless defined($user);
$group = "nobody" unless defined($group);
# become $user:$group and give up root privileges
setgid( ( getgrnam($group) )[2] );
setuid( ( getpwnam($user) )[2] );
# if we are still root
if ( $> == 0 ) {
print STDERR
"$0 must not be launched as root since local cache can be corrupted.\n";
print STDERR "Continue (y/N)? ";
my $res = <STDIN>;
exit 1 unless ( $res =~ /^y/i );
}
}
## main program
if ( !@ARGV ) {
print STDERR "Usage: $0 <action> <params>\n";
print STDERR "- help: list available actions\n";
print STDERR "- info: view current configuration information\n";
exit 1;
}
giveUpPrivileges( "__APACHEUSER__", "__APACHEGROUP__" );
my ( $cli, $action, $method, $ret );
$cli = new Lemonldap::NG::Manager::Cli;
# Do not increment configuration by default
$cli->{confAccess}->{cfgNumFixed} = 1;
$action = shift(@ARGV);
$method = $cli->determineMethod($action);
unless ( $cli->can($method) ) {
print STDERR "Action $action unknown\n";
print STDERR "Enter $0 help to get more information\n";
exit 1;
}
# The config is stored in ASCII
foreach(@ARGV){ utf8::decode $_; }
binmode(STDOUT, ':utf8');
@ARGV ? $cli->run( $method, @ARGV ) : $cli->run($method);
# Display error if any
if ( $cli->getError() ) {
print $cli->getError() . "\n";
exit 1;
}
# Save configuration if modified
if ( $cli->{confModified} ) {
$ret = $cli->saveConf();
print "Configuration $ret saved\n";
}
exit 0;
__END__
=head1 NAME
=encoding utf8
lemonldap-ng-cli - Command Line Interface to edit LemonLDAP::NG configuration.
=head1 SYNOPSIS
Do lemonldap-ng-cli help to get list of all commands
=head1 DESCRIPTION
lemonldap-ng-cli allow user to edit the configuration of LemonLDAP::NG via the
command line.
=head1 SEE ALSO
L<Lemonldap::NG::Manager::Cli>, L<http://lemonldap-ng.org/>
=head1 AUTHOR
David Delassus E<lt>david.jose.delassus@gmail.comE<gt>
Sandro Cazzaniga E<lt>cazzaniga.sandro@gmail.comE<gt>
Clement Oudot E<lt>clem.oudot@gmail.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2012, by David Delassus
Copyright (C) 2013, by Sandro Cazzaniga
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
=cut

View File

@ -1,92 +0,0 @@
#!/usr/bin/perl
use Lemonldap::NG::Common::Conf;
use Lemonldap::NG::Common::Conf::Constants;
use Data::Dumper;
use English qw(-no_match_vars);
use File::Temp;
use POSIX qw(setuid setgid);
use strict;
eval {
setgid( ( getgrnam('__APACHEGROUP__') )[2] );
setuid( ( getpwnam('__APACHEUSER__') )[2] );
print STDERR "Running as uid $EUID and gid $EGID\n";
};
if ( $EUID == 0 ) {
print STDERR
"$0 must not be launched as root since local cache can be corrupted\n"
. "Continue (y/N)? ";
my $res = <STDIN>;
exit 1 unless ( $res =~ /^y/i );
}
my $conf = Lemonldap::NG::Common::Conf->new();
unless ($conf) {
print STDERR $Lemonldap::NG::Common::Conf::msg;
exit 1;
}
my $tmp = $conf->getConf();
delete $tmp->{reVHosts};
delete $tmp->{cipher};
delete $tmp->{cfgAuthor};
delete $tmp->{cfgAuthorIP};
delete $tmp->{cfgDate};
$tmp = Dumper($tmp);
my $refFile = File::Temp->new( UNLINK => 1 );
my $editFile = File::Temp->new( UNLINK => 1 );
print $refFile $tmp;
print $editFile $tmp;
close $refFile;
close $editFile;
system "editor $editFile";
if (`diff $refFile $editFile`) {
my $VAR1;
my $buf;
# Check if the new configuration hash is valid
open F1, $editFile->filename();
while (<F1>) {
$buf .= $_;
}
eval $buf;
die $EVAL_ERROR if $EVAL_ERROR;
# Update author and date
$VAR1->{cfgAuthor} = "lmConfigEditor";
$VAR1->{cfgAuthorIP} = "localhost";
$VAR1->{cfgDate} = time();
# Store new configuration
my $res = $conf->saveConf($VAR1);
if ( $res > 0 ) {
print STDERR "Configuration $res saved\n";
}
else {
print STDERR "Configuration was not saved:\n ";
if ( $res == CONFIG_WAS_CHANGED ) {
print STDERR "Configuration has changed\n";
}
elsif ( $res == DATABASE_LOCKED ) {
print STDERR "Configuration database is or can nor be locked\n";
}
elsif ( $res == UPLOAD_DENIED ) {
print STDERR "You're not authorized to save this configuration\n";
}
elsif ( $res == SYNTAX_ERROR ) {
print STDERR "Syntax error in your configuration\n";
}
elsif ( $res == UNKNOWN_ERROR ) {
print STDERR "Unknown error\n";
}
}
}
else {
print STDERR "Configuration not changed\n";
}

View File

@ -1,56 +0,0 @@
#!/usr/bin/perl
use strict;
use Lemonldap::NG::Manager;
use Lemonldap::NG::Manager::Sessions;
use HTML::Template;
my $cgi = Lemonldap::NG::Manager::Sessions->new(
{
# SESSION EXPLORER CUSTOMIZATION
#managerSkin => 'default',
# ACCESS TO CONFIGURATION
# By default, Lemonldap::NG uses the default storage.conf file to know
# where to find is configuration
# (generaly /etc/lemonldap-ng/storage.conf)
# You can specify by yourself this file :
#configStorage => { type => 'File', dirName => '/path/to/my/file' },
# You can also specify directly the configuration
# (see Lemonldap::NG::Handler::SharedConf(3))
#configStorage => {
# type => 'File',
# directory => '/usr/local/lemonlda-ng/conf/'
#},
}
) or Lemonldap::NG::Common::CGI->abort('Unable to start sessions explorer');
my $skin = $cgi->{managerSkin} or $cgi->abort('managerSkin is not defined');
my $css = 'tree.css';
my $css_theme = 'ui-lightness';
my $skin_dir = 'skins';
my $main_dir = $cgi->getApacheHtdocsPath;
my $template = HTML::Template->new(
filename => "$main_dir/$skin_dir/$skin/sessions.tpl",
die_on_bad_params => 0,
cache => 0,
filter => sub { $cgi->translate_template(@_) },
);
$template->param( SCRIPT_NAME => $ENV{SCRIPT_NAME} );
$template->param( TREE => $cgi->tree() );
$template->param( DIR => "$skin_dir/$skin" );
$template->param( CSS => $css );
$template->param( CSS_THEME => $css_theme );
$template->param( VERSION => $Lemonldap::NG::Manager::VERSION );
$template->param( LANG => shift @{ $cgi->{lang} } );
$template->param( PORTAL_URL => $cgi->{portal} );
$template->param( LI_CLASS_CONFIGURATION => "" );
$template->param( LI_CLASS_SESSION => "active" );
$template->param( LI_CLASS_NOTIFICATION => "" );
print $cgi->header('text/html; charset=utf-8');
print $template->output;

View File

@ -1,76 +0,0 @@
/*
* Lemonldap::NG styles
* Lightness theme for Manager
*/
@import url(manager.css);
/* jQuery Simple Tree */
.simpleTree
{
margin:0;
padding:0;
}
.simpleTree ul
{
text-align:center;
}
.simpleTree li
{
list-style:none;
margin:0;
padding:0 5px;
}
.simpleTree li span
{
display:block;
padding:5px 25px;
}
.simpleTree li.doc span, .simpleTree li.doc-last span
{
color:#444;
padding:5px;
}
.simpleTree ul
{
margin:0;
padding:0;
}
.simpleTree .root
{
cursor:pointer;
text-align:center;
}
.simpleTree .line
{
line-height:3px;
height:3px;
font-size:3px;
}
.simpleTree .ajax
{
background: url(../images/spinner.gif) no-repeat center 10px;
height:30px;
display:none;
}
.simpleTree .ajax li
{
display:none;
margin:0;
padding:0;
}
.simpleTree .trigger {
position:relative;
top:6px;
left:8px;
}

View File

@ -1,442 +0,0 @@
/*!
* Bootstrap v3.2.0 (http://getbootstrap.com)
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-default:disabled,
.btn-default[disabled] {
background-color: #e0e0e0;
background-image: none;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2));
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #2b669a;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #2d6ca2;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #2d6ca2;
border-color: #2b669a;
}
.btn-primary:disabled,
.btn-primary[disabled] {
background-color: #2d6ca2;
background-image: none;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
background-color: #419641;
background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
background-color: #419641;
border-color: #3e8f3e;
}
.btn-success:disabled,
.btn-success[disabled] {
background-color: #419641;
background-image: none;
}
.btn-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
background-color: #2aabd2;
background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
background-color: #2aabd2;
border-color: #28a4c9;
}
.btn-info:disabled,
.btn-info[disabled] {
background-color: #2aabd2;
background-image: none;
}
.btn-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
background-color: #eb9316;
background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
background-color: #eb9316;
border-color: #e38d13;
}
.btn-warning:disabled,
.btn-warning[disabled] {
background-color: #eb9316;
background-image: none;
}
.btn-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
background-color: #c12e2a;
background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
background-color: #c12e2a;
border-color: #b92c28;
}
.btn-danger:disabled,
.btn-danger[disabled] {
background-color: #c12e2a;
background-image: none;
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: #e8e8e8;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-color: #357ebd;
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
background-repeat: repeat-x;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
}
.navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
background-image: -o-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f3f3f3));
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
}
.navbar-inverse .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
background-image: -o-linear-gradient(top, #222 0%, #282828 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#222), to(#282828));
background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
border-radius: 0;
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
background-repeat: repeat-x;
border-color: #b2dba1;
}
.alert-info {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #9acfea;
}
.alert-warning {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
background-repeat: repeat-x;
border-color: #f5e79e;
}
.alert-danger {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
background-repeat: repeat-x;
border-color: #dca7a7;
}
.progress {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9));
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-striped {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
text-shadow: 0 -1px 0 #3071a9;
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3));
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
background-repeat: repeat-x;
border-color: #3278b3;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
background-repeat: repeat-x;
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
background-repeat: repeat-x;
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
background-repeat: repeat-x;
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
background-repeat: repeat-x;
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
background-repeat: repeat-x;
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +0,0 @@
/*
* Lemonldap::NG styles
* Commin styles for Manager
*
* Coding rules:
* selector
* {
* property:value;
* }
*/
/* Main */
html,body
{
margin:0;
padding:0;
height:100%;
min-height:100%;
background: rgb(0,0,0);
}
body
{
padding-top: 60px;
}
img.brand
{
height:25px;
}
ul
{
text-align: left;
list-style-position:inside;
list-style-image:url("../images/bullet_orange.png");
}
/* Buttons, Inputs*/
.buttons
{
margin: 10px 0;
}
input, select, textarea
{
font-weight:bold;
}
textarea.elastic {
max-height: 8em;
font:bold 9pt sans-serif;
}
textarea#filearea
{
font-size:8pt;
font-family:monospace;
background-color:#ddd;
}
input#text, input#int, input#password, select
{
text-align:center;
}
div.int
{
width: 200px;
margin: auto;
}
input#applicationListApplicationLogo
{
height: 56px;
}
input#skinText
{
height: 153px;
}
input#authOptions
{
margin: 10px 0;
}
option
{
margin:5px;
}
/* Divs */
#menu, #data
{
overflow-x:hidden;
overflow-y:auto;
}
#buttons, #edition, #help
{
text-align:center;
}
#help_content
{
padding:5px;
overflow:hidden;
text-align:center;
}
#help_content iframe
{
width:100%;
height:100%;
}
#query-switch
{
padding:0;
margin:10px 0;
}
/* Popup */
#popup h3
{
text-align:center;
letter-spacing:2px;
border-bottom:1px solid #aaa;
padding:5px;
margin:5px 50px;
}
#popup ul
{
list-style-position:inside;
list-style-image:url("../images/bullet_green.png");
margin:0;
padding:0;
}
#popup ul.warning {
list-style-image:url("../images/bullet_orange.png");
}
#popup ul.error {
list-style-image:url("../images/bullet_red.png");
}
.ui-dialog {
border:1px solid #000;
box-shadow:1px 1px 15px #555;
-moz-box-shadow:1px 1px 15px #555;
-webkit-box-shadow:1px 1px 15px #555;
}
/* Skin selection */
input#skinText {
text-align: center;
}
#content_skin img, #skinImagePicker img, #content_applicationListApplication img, #appsLogoPicker img {
margin: 5px;
}
#skinImagePicker, #appsLogoPicker, #css-switch {
text-align: center;
}

View File

@ -1,200 +0,0 @@
/*
* Lemonldap::NG styles
* Default theme for Manager
*/
@import url(manager.css);
.simpleTree
{
overflow:auto;
margin:0;
padding:0;
}
.simpleTree li
{
list-style: none;
margin:0;
padding:0 0 0 34px;
line-height: 14px;
}
.simpleTree li span
{
display:inline;
clear: left;
white-space: nowrap;
cursor:pointer;
}
.simpleTree ul
{
margin:0;
padding:0;
}
.simpleTree .root
{
margin-left:-16px;
background: url(../images/tree/root.gif) no-repeat 16px 0 transparent;
/*background-position: -84px -1646px;width:16px*/
}
.simpleTree .line
{
margin:0 0 0 -16px;
padding:0;
line-height: 3px;
height:3px;
font-size:3px;
background: url(../images/tree/tree.png) 0 0 no-repeat transparent;
background-position: -84px -1322px;
}
.simpleTree .line-last
{
margin:0 0 0 -16px;
padding:0;
line-height: 3px;
height:3px;
font-size:3px;
background: url(../images/tree/tree.png) 0 0 no-repeat transparent;
background-position: -84px -1712px;
}
.simpleTree .line-over
{
margin:0 0 0 -16px;
padding:0;
line-height: 3px;
height:3px;
font-size:3px;
background: url(../images/tree/tree.png) 0 0 no-repeat transparent;
background-position: -84px -1392px;
}
.simpleTree .line-over-last
{
margin:0 0 0 -16px;
padding:0;
line-height: 3px;
height:3px;
font-size:3px;
background: url(../images/tree/tree.png) 0 0 no-repeat transparent;
background-position: -84px -1462px;
}
.simpleTree .folder-open
{
margin-left:-16px;
background: url(../images/tree/tree.png) 0 -2px no-repeat transparent;
background-position: 0 -72px;width: 34px;
}
.simpleTree .folder-open-last
{
margin-left:-16px;
background: url(../images/tree/tree.png) 0 -2px no-repeat transparent;
background-position: 0 -72px; width: 34px;
}
.simpleTree .folder-close
{
margin-left:-16px;
background: url(../images/tree/tree.png) 0 -2px no-repeat transparent;
background-position: 0 -1394px; width: 34px;height:14px;
}
.simpleTree .folder-close-last
{
margin-left:-16px;
background: url(../images/tree/tree.png) 0 -2px no-repeat transparent;
background-position: 0 -1322px; width: 34px;height:16px;
}
.simpleTree .folder-hidden, .simpleTree .folder-hidden-last
{
display:none;
}
.simpleTree .doc
{
margin-left:-16px;
background: url(../images/tree/tree.png) 0 -1px no-repeat transparent;
background-position: -84px -72px; width: 32px;height:16px;
}
.simpleTree .doc-last
{
margin-left:-16px;
background: url(../images/tree/tree.png) 0 -1px no-repeat transparent;
background-position: -84px 0; width: 32px;height:16px;
}
.simpleTree .ajax
{
background: url(../images/spinner.gif) no-repeat 0 0 transparent;
height: 16px;
display:none;
}
.simpleTree .ajax li
{
display:none;
margin:0;
padding:0;
}
.simpleTree .trigger
{
display:inline;
margin-left:-32px;
width: 28px;
height: 11px;
cursor:pointer;
}
.simpleTree .text
{
}
.simpleTree .active
{
background-color:#F7BE77;
padding:0px 2px;
border: 1px dashed #444;
}
#drag_container
{
background:transparent;
color:#000;
font: normal 11px arial, tahoma, helvetica, sans-serif;
border: 1px dashed #767676;
}
#drag_container ul
{
list-style: none;
padding:0;
margin:0;
}
#drag_container li
{
list-style: none;
background-color:transparent;
line-height:18px;
white-space: nowrap;
padding:1px 1px 0px 16px;
margin:0;
}
#drag_container li span
{
padding:0;
}
#drag_container li.doc, #drag_container li.doc-last
{
background: url(../images/tree/tree.png) no-repeat -17px 0 transparent;
background-position: -84px -72px;width:32px;
}
#drag_container .folder-close, #drag_container .folder-close-last
{
background: url(../images/tree/tree.png) no-repeat -17px 0 transparent;
background-position: 0 -1394px; width: 34px;
}
#drag_container .folder-open, #drag_container .folder-open-last
{
background: url(../images/tree/tree.png) no-repeat -17px 0 transparent;
background-position: 0 -72px; width: 34px;
}
.content
{
display: block;
}
.hidden
{
display: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 675 B

View File

@ -1,13 +0,0 @@
/* LemonLDAP::NG project */
Icons of this folder are taken from Crystal project:
TITLE: Crystal Project Icons
AUTHOR: Everaldo Coelho
SITE: http://www.everaldo.com
CONTACT: everaldo@everaldo.com
Copyright (c) 2006-2007 Everaldo Coelho.
They are released under GPL license

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,173 +0,0 @@
/*
* Open source library released under licence used by JQuery.
* http://plugins.jquery.com/project/ajaxFileUpload
*/
jQuery.extend({
createUploadIframe:function(id,uri){
var frameId='jUploadFrame' + id;
if(window.ActiveXObject){
var io=document.createElement('<iframe id="'+frameId+'" name="'+frameId+'" />');
if(typeof uri=='boolean'){
io.src='javascript:false';
}else if(typeof uri=='string'){
io.src=uri;
}
}else{
var io=document.createElement('iframe');
io.id=frameId;
io.name=frameId;
}
io.style.position='absolute';
io.style.top='-1000px';
io.style.left='-1000px';
document.body.appendChild(io);
return io;
},
createUploadForm:function(id,fileElementId){
// Create form
var formId = 'jUploadForm' + id;
var fileId = 'jUploadFile' + id;
var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
var oldElement = $('#' + fileElementId);
var newElement = $(oldElement).clone();
$(oldElement).attr('id', fileId);
$(oldElement).before(newElement);
$(oldElement).appendTo(form);
// Set CSS attributes
$(form).css('position', 'absolute');
$(form).css('top', '-1200px');
$(form).css('left', '-1200px');
$(form).appendTo('body');
return form;
},
ajaxFileUpload:function(s){
// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
s = jQuery.extend({}, jQuery.ajaxSettings, s);
var id = new Date().getTime();
var form = jQuery.createUploadForm(id,s.fileElementId);
var io = jQuery.createUploadIframe(id,s.secureuri);
var frameId = 'jUploadFrame' + id;
var formId = 'jUploadForm' + id;
// Watch for a new set of requests
if(s.global && !jQuery.active++){
jQuery.event.trigger( "ajaxStart" );
}
var requestDone = false;
// Create the request object
var xml = {}
if(s.global){
jQuery.event.trigger("ajaxSend", [xml, s]);
}
// Wait for a response to come back
var uploadCallback = function(isTimeout){
var io = document.getElementById(frameId);
try{
if(io.contentWindow){
xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
}else if(io.contentDocument){
xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;
xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;
}
}catch(e){
jQuery.handleError(s,xml,null,e);
}
if(xml || isTimeout=="timeout"){
requestDone = true;
var status;
try{
status = isTimeout != "timeout" ? "success" : "error";
// Make sure that the request was successful or notmodified
if(status != "error"){
// process the data (runs the xml through httpData regardless of callback)
var data = jQuery.uploadHttpData(xml,s.dataType);
// If a local callback was specified, fire it and pass it the data
if(s.success){
s.success( data, status );
}
// Fire the global callback
if(s.global){
jQuery.event.trigger("ajaxSuccess",[xml,s]);
}
}else{
jQuery.handleError(s,xml,status);
}
}catch(e){
status = "error";
jQuery.handleError(s,xml,status,e);
}
// The request was completed
if(s.global){
jQuery.event.trigger("ajaxComplete",[xml,s]);
}
// Handle the global AJAX counter
if(s.global && !--jQuery.active){
jQuery.event.trigger("ajaxStop");
}
// Process result
if(s.complete){
s.complete(xml, status);
}
jQuery(io).unbind();
setTimeout(function(){
try{
$(io).remove();
$(form).remove();
}catch(e){
jQuery.handleError(s, xml, null, e);
}
},100);
xml = null;
}
}
// Timeout checker
if(s.timeout>0){
setTimeout(function(){
// Check to see if the request is still happening
if(!requestDone) uploadCallback("timeout");
},s.timeout);
}
try{
// var io = $('#' + frameId);
var form = $('#' + formId);
$(form).attr('action', s.url);
$(form).attr('method', 'POST');
$(form).attr('target', frameId);
if(form.encoding){
form.encoding = 'multipart/form-data';
}else{
form.enctype = 'multipart/form-data';
}
$(form).submit();
}catch(e){
jQuery.handleError(s,xml,null,e);
}
if(window.attachEvent){
document.getElementById(frameId).attachEvent('onload', uploadCallback);
}else{
document.getElementById(frameId).addEventListener('load', uploadCallback, false);
}
return {abort:function(){}};
},
uploadHttpData:function(r,type){
var data = !type;
data = type == "xml" || data ? r.responseXML : r.responseText;
// If the type is "script", eval it in global context
if(type=="script"){
jQuery.globalEval(data);
}
// Get the JavaScript object, if JSON is used.
if(type=="json"){
eval("data = "+data);
}
// evaluate scripts within html
if(type=="html"){
jQuery("<div>").html(data).evalScripts();
}
//alert($('param', data).each(function(){alert($(this).attr('value'));}));
return data;
}
})

View File

@ -1,96 +0,0 @@
/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
* used when the cookie was set.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie and will not be retained
* when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
* require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// CAUTION: Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
};

View File

@ -1,164 +0,0 @@
/**
* @name Elastic
* @descripton Elastic is jQuery plugin that grow and shrink your textareas automatically
* @version 1.6.11 customized
* @requires jQuery 1.2.6+
*
* @author Jan Jarfalk - customized by FX Deltombe
* @author-email jan.jarfalk@unwrongest.com
* @author-website http://www.unwrongest.com
*
* @licence MIT License - http://www.opensource.org/licenses/mit-license.php
*/
(function($){
jQuery.fn.extend({
elastic: function() {
// We will create a div clone of the textarea
// by copying these attributes from the textarea to the div.
var mimics = [
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'fontSize',
'lineHeight',
'fontFamily',
'width',
'fontWeight',
'border-top-width',
'border-right-width',
'border-bottom-width',
'border-left-width',
'borderTopStyle',
'borderTopColor',
'borderRightStyle',
'borderRightColor',
'borderBottomStyle',
'borderBottomColor',
'borderLeftStyle',
'borderLeftColor'
];
return this.each( function() {
// Elastic only works on textareas
if ( this.type !== 'textarea' ) {
return false;
}
var $textarea = jQuery(this),
$twin = jQuery('<div />').css({
'position' : 'absolute',
'display' : 'none',
'word-wrap' : 'break-word',
'white-space' :'pre-wrap'
}),
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
// modified by FX Deltombe: try to set minheight from textarea rows instead of textarea css height,
minheight = lineHeight * parseInt($textarea.attr('rows'), 10) || parseInt($textarea.css('height'),10) || lineHeight*3,
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
goalheight = 0;
// Opera returns max-height of -1 if not set
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
// Append the twin to the DOM
// We are going to meassure the height of this, not the textarea.
$twin.appendTo($textarea.parent());
// Copy the essential styles (mimics) from the textarea to the twin
var i = mimics.length;
while(i--){
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
}
// Updates the width of the twin. (solution for textareas with widths in percent)
function setTwinWidth(){
var curatedWidth = Math.floor(parseInt($textarea.width(),10));
if($twin.width() !== curatedWidth){
$twin.css({'width': curatedWidth + 'px'});
// Update height of textarea
update(true);
}
}
// Sets a given height and overflow state on the textarea
function setHeightAndOverflow(height, overflow){
var curratedHeight = Math.floor(parseInt(height,10));
if($textarea.height() !== curratedHeight){
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
}
}
// This function will update the height of the textarea if necessary
function update(forced) {
// Get curated content from the textarea.
var textareaContent = $textarea.val().replace(/&/g,'&amp;').replace(/ {2}/g, '&nbsp;').replace(/<|>/g, '&gt;').replace(/\n/g, '<br />');
// Compare curated content with curated twin.
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
if(forced || textareaContent+'&nbsp;' !== twinContent){
// Add an extra white space so new rows are added when you are at the end of a row.
$twin.html(textareaContent+'&nbsp;');
// modified by FX Deltombe:consider twin height instead of twin height plus the height of one line
// Change textarea height if twin height differs more than 3 pixel from textarea height
if(Math.abs($twin.height() - $textarea.height()) > 3){
var goalheight = $twin.height();
if(goalheight >= maxheight) {
setHeightAndOverflow(maxheight,'auto');
} else if(goalheight <= minheight) {
setHeightAndOverflow(minheight,'hidden');
} else {
setHeightAndOverflow(goalheight,'hidden');
}
}
}
}
// Hide scrollbars
$textarea.css({'overflow':'hidden'});
// Update textarea size on keyup, change, cut and paste
$textarea.bind('keyup change cut paste', function(){
update();
});
// Update width of twin if browser or textarea is resized (solution for textareas with widths in percent)
$(window).bind('resize', setTwinWidth);
$textarea.bind('resize', setTwinWidth);
$textarea.bind('update', update);
// Compact textarea on blur
$textarea.bind('blur',function(){
if($twin.height() < maxheight){
if($twin.height() > minheight) {
$textarea.height($twin.height());
} else {
$textarea.height(minheight);
}
}
});
// And this line is to catch the browser paste event
$textarea.bind('input paste',function(e){ setTimeout( update, 250); });
// Run update once when elastic is initialized
update();
});
}
});
})(jQuery);

File diff suppressed because it is too large Load Diff

View File

@ -1,159 +0,0 @@
/* function displayNotification(string id)
* Send an AJAX request to display an active notification
* @param id concatenation of uid + '_' + ref
* @return HTML code
*/
function displayNotification(id) {
$.ajax({
type: "POST",
url: scriptname,
data: {
'notification': id
},
dataType: 'html',
success: function(data) {
$('#data').html(data);
},
error: function(xhr, ajaxOptions, thrownError) {
$('#data').html('<h3>Request failed</h3> Error code: ' + xhr.status + ', ' + thrownError);
}
});
}
/* function displayNotificationDone(string id)
* Send an AJAX request to display a done notification
* @param id internal notification reference
* @return HTML code
*/
function displayNotificationDone(id) {
$.ajax({
type: "POST",
url: scriptname,
data: {
'notificationDone': id
},
dataType: 'html',
success: function(data) {
$('#data').html(data);
},
error: function(xhr, ajaxOptions, thrownError) {
$('#data').html('<h3>Request failed</h3> Error code: ' + xhr.status + ', ' + thrownError);
}
});
}
/* function del(string id)
* Send an AJAX request to delete a notification (mark as done)
* @param id concatenation of uid + '_' + ref
* @return HTML code
*/
function del(id) {
$.ajax({
type: "POST",
url: scriptname,
data: {
'delete': id
},
dataType: 'html',
success: function(data) {
$('#data').html(data);
$('#uid_' + safeSelector(id)).remove();
},
error: function(xhr, ajaxOptions, thrownError) {
$('#data').html('<h3>Request failed</h3> Error code: ' + xhr.status + ', ' + thrownError);
}
});
}
/* function purge(string id)
* Send an AJAX request to purge a notification (remove definitely)
* @param id internal notification reference
* @return HTML code
*/
function purge(id) {
$.ajax({
type: "POST",
url: scriptname,
data: {
'purge': id
},
dataType: 'html',
success: function(data) {
$('#data').html(data);
$('#uid_' + safeSelector(id)).remove();
},
error: function(xhr, ajaxOptions, thrownError) {
$('#data').html('<h3>Request failed</h3> Error code: ' + xhr.status + ', ' + thrownError);
}
});
}
/* function newNotif()
* Display notification creation form
*/
function newNotif() {
var data = $("#newNotif").html();
$('#data').html(data);
$("#data input#date").datepicker({
'dateFormat': 'yy-mm-dd'
});
return;
}
/* function sendNewNotif()
* Send an AJAX request to create a notification
* @return HTML code
*/
function sendNewNotif() {
// Get data
var uid = $("input#uid").val();
var date = $("input#date").val();
var ref = $("input#ref").val();
var condition = $("input#condition").val();
var xml = $("textarea#xml").val();
// Reset CSS
$("input#uid").css('border-width', '0');
$("input#date").css('border-width', '0');
$("input#ref").css('border-width', '0');
$("textarea#xml").css('border-width', '0');
// Check data
if (!uid) {
$("input#uid").css('border-color', 'red').css('border-width', '2px').focus();
return false;
}
if (!date) {
$("input#date").css('border-color', 'red').css('border-width', '2px').focus();
return false;
}
if (!ref) {
$("input#ref").css('border-color', 'red').css('border-width', '2px').focus();
return false;
}
if (!xml) {
$("textarea#xml").css('border-color', 'red').css('border-width', '2px').focus();
return false;
}
// Send AJAX request
$.ajax({
type: "POST",
url: scriptname,
data: {
'newNotif': {
'uid': uid,
'date': date,
'ref': ref,
'condition': condition,
'xml': xml
}
},
dataType: 'html',
success: function(data) {
$('#data').html(data);
},
error: function(xhr, ajaxOptions, thrownError) {
$('#data').html('<h3>Request failed</h3> Error code: ' + xhr.status + ', ' + thrownError);
}
});
}

View File

@ -1,35 +0,0 @@
function displaySession(id) {
$.ajax({
type: "POST",
url: scriptname,
data: {
'session': id
},
dataType: 'html',
success: function(data) {
$('#data').html(data);
},
error: function(xhr, ajaxOptions, thrownError) {
$('#data').html('<h3>Request failed</h3> Error code: ' + xhr.status + ', ' + thrownError);
}
});
}
function del(id) {
$.ajax({
type: "POST",
url: scriptname,
data: {
'delete': id
},
dataType: 'html',
success: function(data) {
$('#data').html(data);
// Delete session from tree
$('#uid' + id).remove();
$('#ip' + id).remove();
},
error: function(xhr, ajaxOptions, thrownError) {
$('#data').html('<h3>Request failed</h3> Error code: ' + xhr.status + ', ' + thrownError);
}
});
}

View File

@ -1,545 +0,0 @@
/*
* jQuery SimpleTree Drag&Drop plugin
* Update on 22th May 2008
* Version 0.3
*
* Licensed under BSD <http://en.wikipedia.org/wiki/BSD_License>
* Copyright (c) 2008, Peter Panov <panov\@elcat.kg>, IKEEN Group http://www.ikeen.com
* All rights reserved.
*
* Modified by Xavier Guimard <x.guimard@free.fr> for Lemonldap::NG:
* * Manage Ajax errors
* Modified by Clement Oudot <clem.oudot@gmail.com> for Lemonldap::NG:
* * Add useClickToToggle option
* * Add afterCloseNearby trigger
* * Add afterNewNode trigger
* * Add and remove 'active' class instead of erasing all class values
* * Add afterSetTrigger trigger
* * Correct a bug if ajax call return no data
* * Automatically open the node if a subnode is added
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Peter Panov, IKEEN Group nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Peter Panov, IKEEN Group ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Peter Panov, IKEEN Group BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
$.fn.simpleTree = function(opt) {
return this.each(function() {
var TREE = this;
var ROOT = $('.root', this);
var mousePressed = false;
var mouseMoved = false;
var dragMoveType = false;
var dragNode_destination = false;
var dragNode_source = false;
var dragDropTimer = false;
var ajaxCache = Array();
TREE.option = {
drag: true,
animate: false,
autoclose: false,
speed: 'fast',
afterAjax: false,
afterMove: false,
afterClick: false,
afterDblClick: false,
// added by Erik Dohmen (2BinBusiness.nl) to make context menu cliks available
afterContextMenu: false,
docToFolderConvert: false,
useClickToToggle: false,
afterCloseNearby: false,
afterNewNode: false,
afterSetTrigger: false
};
TREE.option = $.extend(TREE.option, opt);
$.extend(this, {
getSelected: function() {
return $('span.active', this).parent();
}
});
TREE.closeNearby = function(obj) {
$(obj).siblings().filter('.folder-open, .folder-open-last').each(function() {
var childUl = $('>ul', this);
var className = this.className;
this.className = className.replace('open', 'close');
if (TREE.option.animate) {
childUl.animate({
height: "toggle"
},
TREE.option.speed);
} else {
childUl.hide();
}
if (typeof TREE.option.afterCloseNearby == 'function') {
TREE.option.afterCloseNearby($(this).parent());
}
});
};
TREE.nodeToggle = function(obj) {
var childUl = $('>ul', obj);
if (obj.className.match('open')) {
obj.className = obj.className.replace('open', 'close');
if (TREE.option.animate) {
childUl.animate({
height: "toggle"
},
TREE.option.speed);
} else {
childUl.hide();
}
} else {
obj.className = obj.className.replace('close', 'open');
if (TREE.option.animate) {
childUl.animate({
height: "toggle"
},
TREE.option.speed, function() {
if (TREE.option.autoclose) TREE.closeNearby(obj);
if (childUl.is('.ajax')) TREE.setAjaxNodes(childUl, obj.id);
});
} else {
childUl.show();
if (TREE.option.autoclose) TREE.closeNearby(obj);
if (childUl.is('.ajax')) TREE.setAjaxNodes(childUl, obj.id);
}
}
};
TREE.setAjaxNodes = function(node, parentId, callback) {
if ($.inArray(parentId, ajaxCache) == -1) {
ajaxCache[ajaxCache.length] = parentId;
var url = $.trim($('>li', node).text());
if (url && url.indexOf('url:')) {
url = $.trim(url.replace(/.*\{url:(.*)\}/i, '$1'));
var js = '';
var call = '';
if (url.indexOf(',js:')) {
call = url.match(/.*,call:(.*)/i);
if (call == null) {
call = '';
} else {
call = call[1].replace(/,call.*$/, '');
}
js = url.match(/.*,js:(.*)/i);
if (js == null) {
js = '';
} else {
js = js[1].replace(/,call.*$/, '');
}
url = $.trim(url.replace(/,(?:js|call):.*/i, ''));
}
$.ajax({
type: "GET",
url: url,
contentType: 'html',
cache: false,
success: function(response) {
node.removeAttr('class');
if (response.length > 0) {
node.html(response);
$.extend(node, {
url: url
});
TREE.setTreeNodes(node, true);
} else {
$("li.line", node).remove();
$("li.doc-last", node).remove();
}
if (typeof TREE.option.afterAjax == 'function') {
TREE.option.afterAjax(node);
}
if (typeof callback == 'function') {
callback(node);
}
if (js.length) {
if (!js.match(/\(/)) js += '()';
$('>span', node.parent()).click(function() {
eval(js)
});
}
if (call.length) {
if (!call.match(/\(/)) call += '()';
eval(call);
}
},
error: function(xhr, ajaxOptions, thrownError) {
TREE.closeNearby(node);
alert('Failed to get remote datas. Error code: ' + xhr.status + ', ' + thrownError);
}
});
}
}
};
TREE.setTreeNodes = function(obj, useParent) {
obj = useParent ? obj.parent() : obj;
$('li>span', obj).addClass('text').bind('selectstart', function() {
return false;
}).click(function() {
// Remove all active classes and add the text class
$('.active', TREE).toggleClass('active').addClass('text');
if (this.className.match('text')) {
this.className = this.className.replace('text', 'active');
}
if (TREE.option.useClickToToggle) {
TREE.nodeToggle($(this).parent().get(0));
}
if (typeof TREE.option.afterClick == 'function') {
TREE.option.afterClick($(this).parent());
}
return false;
}).dblclick(function() {
mousePressed = false;
if (!TREE.option.useClickToToggle) {
TREE.nodeToggle($(this).parent().get(0));
}
if (typeof TREE.option.afterDblClick == 'function') {
TREE.option.afterDblClick($(this).parent());
}
return false;
// added by Erik Dohmen (2BinBusiness.nl) to make context menu actions
// available
}).bind("contextmenu", function() {
$('.active', TREE).toggleClass('active').addClass('text');
if (this.className.match('text')) {
this.className = this.className.replace('text', 'active');
}
if (typeof TREE.option.afterContextMenu == 'function') {
TREE.option.afterContextMenu($(this).parent());
}
return false;
}).mousedown(function(event) {
mousePressed = true;
cloneNode = $(this).parent().clone();
var LI = $(this).parent();
if (TREE.option.drag) {
$('>ul', cloneNode).hide();
$('body').append('<div id="drag_container"><ul></ul></div>');
$('#drag_container').hide().css({
opacity: '0.8'
});
$('#drag_container >ul').append(cloneNode);
$("<img>").attr({
id: "tree_plus",
src: imagepath + "tree/plus.gif"
}).css({
width: "7px",
display: "block",
position: "absolute",
left: "5px",
top: "5px",
display: 'none'
}).appendTo("body");
$(document).bind("mousemove", {
LI: LI
},
TREE.dragStart).bind("mouseup", TREE.dragEnd);
}
return false;
}).mouseup(function() {
if (mousePressed && mouseMoved && dragNode_source) {
TREE.moveNodeToFolder($(this).parent());
}
TREE.eventDestroy();
});
$('li', obj).each(function(i) {
var className = this.className;
var open = false;
var cloneNode = false;
var LI = this;
var childNode = $('>ul', this);
if (childNode.size() > 0) {
var setClassName = 'folder-';
if (className && className.indexOf('hidden') >= 0) {
setClassName = setClassName + 'hidden';
} else if (className && className.indexOf('open') >= 0) {
setClassName = setClassName + 'open';
open = true;
} else {
setClassName = setClassName + 'close';
}
this.className = setClassName + ($(this).is(':last-child') ? '-last' : '');
if (!open || className.indexOf('ajax') >= 0) childNode.hide();
TREE.setTrigger(this);
} else {
var setClassName = 'doc';
this.className = setClassName + ($(this).is(':last-child') ? '-last' : '');
}
}).before('<li class="line">&nbsp;</li>').filter(':last-child').after('<li class="line-last"></li>');
TREE.setEventLine($('.line, .line-last', obj));
};
TREE.setTrigger = function(node) {
$('>span', node).before('<img class="trigger" src="' + imagepath + 'tree/spacer.gif" border=0>');
var trigger = $('>.trigger', node);
trigger.click(function(event) {
TREE.nodeToggle(node);
});
trigger.css('float', 'left');
if (typeof TREE.option.afterSetTrigger == 'function') {
TREE.option.afterSetTrigger(node);
}
};
TREE.dragStart = function(event) {
var LI = $(event.data.LI);
if (mousePressed) {
mouseMoved = true;
if (dragDropTimer) clearTimeout(dragDropTimer);
if ($('#drag_container:not(:visible)')) {
$('#drag_container').show();
LI.prev('.line').hide();
dragNode_source = LI;
}
$('#drag_container').css({
position: 'absolute',
"left": (event.pageX + 5),
"top": (event.pageY + 15)
});
if (LI.is(':visible')) LI.hide();
var temp_move = false;
if (event.target.tagName.toLowerCase() == 'span' && $.inArray(event.target.className, Array('text', 'active', 'trigger')) != -1) {
var parent = event.target.parentNode;
var offs = $(parent).offset({
scroll: false
});
var screenScroll = {
x: (offs.left - 3),
y: event.pageY - offs.top
};
var isrc = $("#tree_plus").attr('src');
var ajaxChildSize = $('>ul.ajax', parent).size();
var ajaxChild = $('>ul.ajax', parent);
screenScroll.x += 19;
screenScroll.y = event.pageY - screenScroll.y + 5;
if (parent.className.indexOf('folder-close') >= 0 && ajaxChildSize == 0) {
if (isrc.indexOf('minus') != -1) $("#tree_plus").attr('src', imagepath + 'tree/plus.gif');
$("#tree_plus").css({
"left": screenScroll.x,
"top": screenScroll.y
}).show();
dragDropTimer = setTimeout(function() {
parent.className = parent.className.replace('close', 'open');
$('>ul', parent).show();
},
700);
} else if (parent.className.indexOf('folder') >= 0 && ajaxChildSize == 0) {
if (isrc.indexOf('minus') != -1) $("#tree_plus").attr('src', imagepath + 'tree/plus.gif');
$("#tree_plus").css({
"left": screenScroll.x,
"top": screenScroll.y
}).show();
} else if (parent.className.indexOf('folder-close') >= 0 && ajaxChildSize > 0) {
mouseMoved = false;
$("#tree_plus").attr('src', imagepath + 'tree/minus.gif');
$("#tree_plus").css({
"left": screenScroll.x,
"top": screenScroll.y
}).show();
$('>ul', parent).show();
/*
Thanks for the idea of Erik Dohmen
*/
TREE.setAjaxNodes(ajaxChild, parent.id, function() {
parent.className = parent.className.replace('close', 'open');
mouseMoved = true;
$("#tree_plus").attr('src', imagepath + 'tree/plus.gif');
$("#tree_plus").css({
"left": screenScroll.x,
"top": screenScroll.y
}).show();
});
} else {
if (TREE.option.docToFolderConvert) {
$("#tree_plus").css({
"left": screenScroll.x,
"top": screenScroll.y
}).show();
} else {
$("#tree_plus").hide();
}
}
} else {
$("#tree_plus").hide();
}
return false;
}
return true;
};
TREE.dragEnd = function() {
if (dragDropTimer) clearTimeout(dragDropTimer);
TREE.eventDestroy();
};
TREE.setEventLine = function(obj) {
obj.mouseover(function() {
if (this.className.indexOf('over') < 0 && mousePressed && mouseMoved) {
this.className = this.className.replace('line', 'line-over');
}
}).mouseout(function() {
if (this.className.indexOf('over') >= 0) {
this.className = this.className.replace('-over', '');
}
}).mouseup(function() {
if (mousePressed && dragNode_source && mouseMoved) {
dragNode_destination = $(this).parents('li:first');
TREE.moveNodeToLine(this);
TREE.eventDestroy();
}
});
};
TREE.checkNodeIsLast = function(node) {
if (node.className.indexOf('last') >= 0) {
var prev_source = dragNode_source.prev().prev();
if (prev_source.size() > 0) {
prev_source[0].className += '-last';
}
node.className = node.className.replace('-last', '');
}
};
TREE.checkLineIsLast = function(line) {
if (line.className.indexOf('last') >= 0) {
var prev = $(line).prev();
if (prev.size() > 0) {
prev[0].className = prev[0].className.replace('-last', '');
}
dragNode_source[0].className += '-last';
}
};
TREE.eventDestroy = function() {
// added by Erik Dohmen (2BinBusiness.nl), the unbind mousemove TREE.dragStart action
// like this other mousemove actions binded through other actions ain't removed (use it myself
// to determine location for context menu)
$(document).unbind('mousemove', TREE.dragStart).unbind('mouseup').unbind('mousedown');
$('#drag_container, #tree_plus').remove();
if (dragNode_source) {
$(dragNode_source).show().prev('.line').show();
}
dragNode_destination = dragNode_source = mousePressed = mouseMoved = false;
//ajaxCache = Array();
};
TREE.convertToFolder = function(node) {
node[0].className = node[0].className.replace('doc', 'folder-open');
node.append('<ul><li class="line-last"></li></ul>');
TREE.setTrigger(node[0]);
TREE.setEventLine($('.line, .line-last', node));
};
TREE.convertToDoc = function(node) {
$('>ul', node).remove();
$('img', node).remove();
node[0].className = node[0].className.replace(/folder-(open|close)/gi, 'doc');
};
TREE.moveNodeToFolder = function(node) {
// Open node if it's closed
if (node[0].className.match('close')) {
TREE.nodeToggle(node[0]);
}
if (!TREE.option.docToFolderConvert && node[0].className.indexOf('doc') != -1) {
return true;
} else if (TREE.option.docToFolderConvert && node[0].className.indexOf('doc') != -1) {
TREE.convertToFolder(node);
}
TREE.checkNodeIsLast(dragNode_source[0]);
var lastLine = $('>ul >.line-last', node);
if (lastLine.size() > 0) {
TREE.moveNodeToLine(lastLine[0]);
}
};
TREE.moveNodeToLine = function(node) {
TREE.checkNodeIsLast(dragNode_source[0]);
TREE.checkLineIsLast(node);
var parent = $(dragNode_source).parents('li:first');
var line = $(dragNode_source).prev('.line');
$(node).before(dragNode_source);
$(dragNode_source).before(line);
node.className = node.className.replace('-over', '');
var nodeSize = $('>ul >li', parent).not('.line, .line-last').filter(':visible').size();
if (TREE.option.docToFolderConvert && nodeSize == 0) {
TREE.convertToDoc(parent);
} else if (nodeSize == 0) {
parent[0].className = parent[0].className.replace('open', 'close');
$('>ul', parent).hide();
}
// added by Erik Dohmen (2BinBusiness.nl) select node
if ($('span:first', dragNode_source).attr('class') == 'text') {
$('.active', TREE).toggleClass('active').addClass('text');
$('span:first', dragNode_source).toggleClass('text').addClass('active');
}
if (typeof(TREE.option.afterMove) == 'function') {
var pos = $(dragNode_source).prevAll(':not(.line)').size();
TREE.option.afterMove($(node).parents('li:first'), $(dragNode_source), pos);
}
};
TREE.addNode = function(id, text, callback) {
TREE.newNodeIn(TREE.getSelected(), id, text, callback);
};
TREE.newNodeIn = function(node, id, text, callback) {
var temp_node = $('<li><ul><li id="' + id + '"><span>' + text + '</span></li></ul></li>');
TREE.setTreeNodes(temp_node, false);
destination = node;
dragNode_source = $('.doc-last', temp_node);
TREE.moveNodeToFolder(destination);
temp_node.remove();
if (typeof TREE.option.afterNewNode == 'function') {
TREE.option.afterNewNode(node);
}
if (typeof(callback) == 'function') {
callback(dragNode_destination, dragNode_source);
}
};
TREE.newNodeAfter = function(id, text, callback) {
TREE.newNodeIn(TREE.getSelected().parent().parent(), id, text, callback);
};
TREE.newAjaxNodeIn = function(node, id, text, url, callback) {
var temp_node = $('<li><ul><li id="' + id + '"><span>' + text + '</span><ul class="ajax"><li id="new">.{url:' + url + '}</li></ul></li></ul></li>');
TREE.setTreeNodes(temp_node, false);
destination = node;
dragNode_source = $('.folder-close-last', temp_node);
TREE.moveNodeToFolder(destination);
temp_node.remove();
if (typeof TREE.option.afterNewNode == 'function') {
TREE.option.afterNewNode(node);
}
if (typeof(callback) == 'function') {
callback(dragNode_destination, dragNode_source);
}
};
TREE.delNode = function(callback) {
dragNode_source = TREE.getSelected();
TREE.checkNodeIsLast(dragNode_source[0]);
dragNode_source.prev().remove();
dragNode_source.remove();
if (typeof(callback) == 'function') {
callback(dragNode_destination);
}
};
TREE.init = function(obj) {
TREE.setTreeNodes(obj, false);
};
TREE.init(ROOT);
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,895 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>LemonLDAP::NG Manager</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="cache-control" content="no-cache" />
<link href="<TMPL_VAR NAME="DIR">/lemonldap-ng.ico" rel="icon" type="image/x-icon" />
<link href="<TMPL_VAR NAME="DIR">/lemonldap-ng.ico" rel="shortcut icon" />
<!-- Offline doc CSS -->
<link rel="stylesheet" type="text/css" href="/doc/css/screen.css" />
<!-- jQuery UI CSS -->
<link rel="stylesheet" type="text/css" id="csstheme" href="<TMPL_VAR NAME="DIR">/<TMPL_VAR NAME="CSS_THEME">/jquery-ui-1.10.3.custom.min.css" />
<!-- Bootstrap CSS -->
<link href="<TMPL_VAR NAME="DIR">/css/bootstrap.css" rel="stylesheet">
<link href="<TMPL_VAR NAME="DIR">/css/bootstrap-theme.css" rel="stylesheet">
<!-- Manager CSS -->
<link rel="stylesheet" type="text/css" id="cssmenu" href="<TMPL_VAR NAME="DIR">/css/<TMPL_VAR NAME="CSS">" />
<script src="<TMPL_VAR NAME="DIR">/js/jquery-1.10.2.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/bootstrap.js"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery-ui-1.10.3.custom.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery.cookie.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery.ajaxfileupload.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery.elastic.source.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/tree.js" type="text/JavaScript"></script>
<script type="text/JavaScript">//<![CDATA[
var scriptname='<TMPL_VAR NAME="SCRIPT_NAME">';
var imagepath='<TMPL_VAR NAME="DIR">/images/';
var csspath='<TMPL_VAR NAME="DIR">/css/';
var jqueryuiversion='1.10.3';
var css_menu='<TMPL_VAR NAME="CSS">';
var css_theme='<TMPL_VAR NAME="CSS_THEME">';
var themepath='<TMPL_VAR NAME="DIR">/';
var treeautoclose='<TMPL_VAR NAME="TREE_AUTOCLOSE">';
var treejquerycss='<TMPL_VAR NAME="TREE_JQUERYCSS">';
var text4newKey='<lang en="Key" fr="Clé" />';
var value4newKey='<lang en="Value" fr="Valeur" />';
var value4newSamlAttribute='<lang en="Value" fr="Valeur" />';
var text4newVhost='<lang en="Virtual host name" fr="Nom de l\'hôte virtuel" />';
var text4newSamlMetaData='<lang en="SAML Metadatas name" fr="Nom des métadatas SAML" />';
var text4newSamlAttribute='<lang en="Attribute name" fr="Nom de l\'attribut" />';
var text4newFilename='<lang en="Filename" fr="Nom du fichier" />';
var text4securedCookie0='<lang en="Non secured cookie" fr="Cookie non sécurisé"/>';
var text4securedCookie1='<lang en="Secured cookie (HTTPS)" fr="Cookie sécurisé (HTTPS)"/>';
var text4securedCookie2='<lang en="Double cookie (HTTP and HTTPS)" fr="Double cookie (HTTP et HTTPS)"/>';
var text4securedCookie3='<lang en="Double cookie for single session" fr="Double cookie pour une seule session"/>';
var text4newGeneratedFile='<lang en="Password (optional)" fr="Mot de passe (optionnel)" />';
var text4edit='<lang en="Edit" fr="Éditer" />';
var text4protect='<lang en="Protect" fr="Protéger" />';
var text4newCategory='<lang en="Category identifier" fr="Identifiant de la catégorie" />';
var text4newApplication='<lang en="Application identifier" fr="Identifiant de l\'application" />';
var text4newCondition='<lang en="New Condition" fr="Nouvelle Condition" />';
var lang='<TMPL_VAR NAME="LANG">';
var text4newOidcOp='<lang en="Provider name" fr="Nom du fournisseur" />';
var text4newOidcRp='<lang en="Relying party name" fr="Nom du relai" />';
//]]></script>
<script src="<TMPL_VAR NAME="DIR">/js/manager.js" type="text/JavaScript"></script>
</head>
<body>
<!-- Popup -->
<div id="popup" title="<lang en="Command result" fr="Résultat de la commande" />">
</div>
<!-- Skin picker-->
<div id="skinImagePicker" title="<lang en="Choose a skin" fr="Choisir un thème" />">
<button><img src="<TMPL_VAR NAME="DIR">/images/portal-skins/bootstrap.png" alt="Bootstrap" title="bootstrap" width="200px" height="129px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/portal-skins/pastel.png" alt="Pastel" title="pastel" width="200px" height="129px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/portal-skins/impact.png" alt="Impact" title="impact" width="200px" height="129px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/portal-skins/dark.png" alt="Dark" title="dark" width="200px" height="129px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/portal-skins/custom.png" alt="Custom" title="custom" width="200px" height="129px" /></button>
</div>
<!-- logo picker-->
<div id="appsLogoPicker" title="<lang en="Choose a logo" fr="Choisir un logo" />">
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/attach.png" title="attach" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/bell.png" title="bell" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/bookmark.png" title="bookmark" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/configure.png" title="configure" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/database.png" title="database" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/demo.png" title="demo" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/folder.png" title="folder" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/gear.png" title="gear" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/help.png" title="help" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/mailappt.png" title="mailappt" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/money.png" title="money" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/network.png" title="network" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/terminal.png" title="terminal" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/thumbnail.png" title="thumbnail" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/tux.png" title="tux" width="32px" height="32px" /></button>
<button><img src="<TMPL_VAR NAME="DIR">/images/apps-logos/custom.png" title="custom" width="32px" height="32px" /></button>
</div>
<TMPL_INCLUDE NAME="top.tpl">
<!-- Container -->
<div class="container-fluid">
<div class="row">
<div class="col-sm-3">
<!-- Menu (tree) -->
<div id="menu" class="panel panel-default panel-body">
<TMPL_VAR NAME="MENU">
</div>
</div>
<div class="col-sm-9">
<!-- Buttons -->
<div id="buttons" class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title">
<lang en="Available actions" fr="Actions disponibles" />
</h1>
</div>
<div id="buttons_content" class="panel-body">
<button id="bsave" onclick="uploadConf()" class="btn btn-info">
<i class=" glyphicon glyphicon-floppy-disk"></i>
<lang en="Save" fr="Sauver" />
</button>
<button id="bnewvh" style="display:none;" onclick="newVh();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New virtual host" fr="Nouvel hôte virtuel" />
</button>
<button id="bdelvh" style="display:none;" onclick="delvh(currentId);" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete virtual host" fr="Supprimer l'hôte virtuel" />
</button>
<button id="newkbr" style="display:none;" onclick="newKeyR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New key" fr="Nouvelle clef" />
</button>
<button id="newrbr" style="display:none;" onclick="newRuleR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New rule" fr="Nouvelle règle" />
</button>
<button id="newgsrbr" style="display:none;" onclick="newGrantSessionRuleR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New condition" fr="Nouvelle condition" />
</button>
<button id="newkb" style="display:none;" onclick="newKey();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New key" fr="Nouvelle clef" />
</button>
<button id="newrb" style="display:none;" onclick="newRule();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New rule" fr="Nouvelle règle" />
</button>
<button id="newgsrb" style="display:none;" onclick="newGrantSessionRule();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New condition" fr="Nouvelle condition" />
</button>
<button id="delkb" style="display:none;" onclick="delKey();return false;" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete key" fr="Effacer la clef" />
</button>
<button id="newidpsamlmetadatab" style="display:none;" onclick="newIdpSamlMetaData();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New identity provider" fr="Nouveau fournisseur d'identité" />
</button>
<button id="delidpsamlmetadatab" style="display:none;" onclick="delIdpSamlMetaData(currentId);" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete identity provider" fr="Supprimer le fournisseur d'identité" />
</button>
<button id="newspsamlmetadatab" style="display:none;" onclick="newSpSamlMetaData();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New service provider" fr="Nouveau fournisseur de service" />
</button>
<button id="delspsamlmetadatab" style="display:none;" onclick="delSpSamlMetaData(currentId);" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete service provider" fr="Supprimer le fournisseur de service" />
</button>
<button id="newsamlattributeb" style="display:none;" onclick="newSamlAttribute();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New attribute" fr="Nouvel attribut" />
</button>
<button id="newsamlattributebr" style="display:none;" onclick="newSamlAttributeR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New attribute" fr="Nouvel attribut" />
</button>
<button id="delsamlattributeb" style="display:none;" onclick="delSamlAttribute();return false;" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete attribute" fr="Supprimer l'attribut" />
</button>
<button id="newchoice" style="display:none;" onclick="newChoice();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New choice" fr="Nouveau choix" />
</button>
<button id="newchoicer" style="display:none;" onclick="newChoiceR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New choice" fr="Nouveau choix" />
</button>
<button id="delchoice" style="display:none;" onclick="delChoice();return false;" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete choice" fr="Supprimer le choix" />
</button>
<button id="newcategoryr" style="display:none;" onclick="newCategoryR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New category" fr="Nouvelle catégorie" />
</button>
<button id="delcategory" style="display:none;" onclick="delCategory();return false;" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete category" fr="Supprimer la catégorie" />
</button>
<button id="newapplicationr" style="display:none;" onclick="newApplicationR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New application" fr="Nouvelle application" />
</button>
<button id="delapplication" style="display:none;" onclick="delApplication();return false;" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete application" fr="Supprimer l'application" />
</button>
<button id="newpostr" style="display:none;" onclick="newPostR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New form" fr="Nouveau formulaire" />
</button>
<button id="delpost" style="display:none;" onclick="delPost();return false;" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete form" fr="Supprimer le formulaire" />
</button>
<button id="newpostdatar" style="display:none;" onclick="newPostDataR();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New POST data" fr="Nouvelle donnée POST" />
</button>
<button id="delpostdata" style="display:none;" onclick="delPostData();return false;" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete POST data" fr="Supprimer la donnée POST" />
</button>
<button id="newoidcopb" style="display:none;" onclick="newOidcOp();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New provider" fr="Nouveau fournisseur" />
</button>
<button id="deloidcopb" style="display:none;" onclick="delOidcOp(currentId);" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete provider" fr="Supprimer le fournisseur" />
</button>
<button id="newoidcrpb" style="display:none;" onclick="newOidcRp();return false;" class="btn btn-success">
<i class=" glyphicon glyphicon-plus-sign"></i>
<lang en="New relying party" fr="Nouveau relai" />
</button>
<button id="deloidcrpb" style="display:none;" onclick="delOidcRp(currentId);" class="btn btn-danger">
<i class=" glyphicon glyphicon-minus-sign"></i>
<lang en="Delete relying party" fr="Supprimer le relai" />
</button>
</div>
<!-- Buttons -->
</div>
<!-- Edition -->
<div id="edition" class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title">
<lang en="Edit key " fr="Édition de la clé " /><span id="content_title">&nbsp;</span>
</h1>
</div>
<form action="#" onsubmit="return false"i role="form">
<!-- Edition content -->
<div id="content" class="panel-body">
<!-- Default text -->
<div id="content_default" class="content">
<lang en="No value" fr="Pas de valeur" />
</div>
<!-- Configuration datas -->
<div id="content_cfgDatas" class="hidden">
<ul>
<li><strong><lang en="Configuration number" fr="Numéro de configuration "/></strong>: <span id="cfgNum"><TMPL_VAR NAME="CFGNUM"></span></li>
<li><strong><lang en="Author" fr="Auteur "/></strong>: <span id="cfgAuthor"></span></li>
<li><strong><lang en="IP Address" fr="Adresse IP "/></strong>: <span id="cfgAuthorIP"></span></li>
<li><strong><lang en="Date" fr="Date "/></strong>: <span id="cfgDate"></span></li>
</ul>
</div>
<!-- Simple text -->
<div id="content_text" class="hidden">
<input type="text" id="text" class="form-control" />
<br />
<button onclick="setlminputdata(currentId,text);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
<!-- Password -->
<div id="content_password" class="hidden">
<input type="password" id="password" class="form-control" />
<br />
<button onclick="setlminputdata(currentId,password);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
<!-- Simple textarea -->
<div id="content_textarea" class="hidden">
<textarea id="textarea" cols="80" rows="10" class="form-control"></textarea>
<br />
<button onclick="setlminputdata(currentId,textarea);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
<!-- File textarea -->
<div id="content_filearea" class="hidden">
<textarea readonly="readonly" id="filearea" cols="80" rows="10" class="form-control"></textarea>
<div class="buttons">
<button id="downloadfile" onclick="downloadFile(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-floppy-save"></i>
<lang en="Download this file" fr="T&eacute;l&eacute;charger ce fichier" />
</button>
<button id="generatefile" onclick="generateFile(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-flash"></i>
<lang en="Generate" fr="G&eacute;n&eacute;rer" />
</button>
<button id="switchreadonly" onclick="switchReadonly('#filearea');return false;" class="btn btn-info">
<i class="glyphicon glyphicon-lock"></i>
<span></span>
</button>
<button onclick="setlminputdata(currentId,filearea);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
<span class="loadimg"><img class="hidden" id="button-loadimg" src="<TMPL_VAR NAME="DIR">/images/spinner.gif" width="16px" height="16px" /></span>
</div>
<table class="table">
<tr id="fileinput">
<th><lang en="Load from a file" fr="Charger depuis un fichier" /> :</th>
<td>
<input type="file" name="file" id="file" size="30" />
</td>
<td>
<button onclick="setlmfile(currentId,file);return false;" class="btn btn-info"><i class="glyphicon glyphicon-floppy-open"></i> <lang en="Load" fr="Charger" /></button>
<span class="loadimg"><img class="hidden" id="file-loadimg" src="<TMPL_VAR NAME="DIR">/images/spinner.gif" width="16px" height="16px" /></span>
</td>
</tr>
<tr id="urlinput">
<th><lang en="Load from a URL" fr="Charger depuis une URL" /> :</th>
<td>
<input type="text" name="url" id="url" size="40" class="form-control"/>
</td>
<td>
<button onclick="setlmfile(currentId,url);return false;" class="btn btn-info"><i class="glyphicon glyphicon-cloud-upload"></i> <lang en="Load" fr="Charger" /></button>
<span class="loadimg"><img class="hidden" id="url-loadimg" src="<TMPL_VAR NAME="DIR">/images/spinner.gif" width="16px" height="16px" /></span>
</td>
</tr>
</table>
</div>
<!-- Select -->
<div id="content_select" class="hidden">
<select id="select" onchange="setlmdata(currentId,this.value);return false;" class="form-control"></select>
</div>
<!-- Integer -->
<div id="content_int" class="hidden">
<div class="input-group int">
<span class="input-group-btn">
<button onclick="decrease();return false;" class="btn btn-warning"><i class="glyphicon glyphicon-minus"></i></button>
</span>
<input type="text" id="int" class="form-control" />
<span class="input-group-btn">
<button onclick="increase();return false;" class="btn btn-warning"><i class="glyphicon glyphicon-plus"></i></button>
</span>
</div>
<div class="buttons text-center">
<button onclick="setlminputdata(currentId,int);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- Boolean -->
<div id="content_bool" class="hidden">
<div class="btn-group" data-toggle="buttons">
<label id="On" class="btn btn-info" onclick="setlmdata(currentId,1)">
<input type="radio" name="boolean" autocomplete="off" /><lang en="On" fr="Activé"/>
</label>
<label id="Off" class="btn btn-info" onclick="setlmdata(currentId,0)">
<input type="radio" name="boolean" autocomplete="off" /><lang en="Off" fr="Désactivé"/>
</label>
</div>
</div>
<!-- Troolean -->
<div id="content_trool" class="hidden">
<div class="btn-group" data-toggle="buttons">
<label id="TrOn" class="btn btn-info" onclick="setlmdata(currentId,1)">
<input type="radio" name="troolean" autocomplete="off" /><lang en="On" fr="Activé"/>
</label>
<label id="TrOff" class="btn btn-info" onclick="setlmdata(currentId,0)">
<input type="radio" name="troolean" autocomplete="off" /><lang en="Off" fr="Désactivé"/>
</label>
<label id="TrDefault" class="btn btn-info" onclick="setlmdata(currentId,-1)">
<input type="radio" name="troolean" autocomplete="off" /><lang en="Default" fr="Par défaut"/>
</label>
</div>
</div>
<!-- Boolean or Perl Expr -->
<div id="content_boolOrPerlExpr" class="hidden">
<div class="btn-group buttons" data-toggle="buttons">
<label id="bopeOn" class="btn btn-info" onclick="setlmdata(currentId,1);$('#bopeValue').hide();">
<input type="radio" name="bope" autocomplete="off" /><lang en="On" fr="Activé"/>
</label>
<label id="bopeOff" class="btn btn-info" onclick="setlmdata(currentId,0);$('#bopeValue').hide();">
<input type="radio" name="bope" autocomplete="off" /><lang en="Off" fr="Désactivé"/>
</label>
<label id="bopeExpr" class="btn btn-info" onclick="$('#bopeValue').show();">
<input type="radio" name="bope" autocomplete="off" /><lang en="Specific rule" fr="Règle spécifique"/>
</label>
</div>
<textarea id="bopeValue" cols="30" rows="2" class="form-control"></textarea>
<div class="buttons text-center">
<button onclick="setlmbope(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<div id="content_btext" class="hidden">
<div class="row">
<div class="col-sm-4">
<textarea class="elastic form-control" id="btextKey" rows="1" cols="25"></textarea>
</div>
<div class="col-sm-8">
<textarea class="elastic form-control" id="btextValue" rows="1" cols="40"></textarea>
</div>
</div>
<div class="buttons text-center">
<button onclick="setlminputtext(currentId,btextKey);setlminputdata(currentId,btextValue);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- Rule -->
<div id="content_rules" class="hidden">
<table class="table">
<tr>
<th><lang en="Comment" fr="Commentaire" /></th>
<td><textarea class="elastic form-control" id="rulComment" rows="1" cols="30"></textarea></td>
</tr>
<tr>
<th><lang en="Expression" fr="Expression" /></th>
<td><textarea class="elastic form-control" id="rulKey" rows="1" cols="30"></textarea></td>
</tr>
<tr>
<th><lang en="Rule" fr="Règle" /></th>
<td><textarea class="elastic form-control" id="rulValue" rows="3" cols="50"></textarea></td>
</tr>
</table>
<div class="buttons text-center">
<button onclick="setlmrule(currentId,rulComment,rulKey,rulValue);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- Grant session rule -->
<div id="content_grantSessionRules" class="hidden">
<table class="table">
<tr>
<th><lang en="Comment" fr="Commentaire" /></th>
<td><textarea class="elastic form-control" id="grantSessionRulComment" rows="1" cols="30"></textarea></td>
</tr>
<tr>
<th><lang en="Condition" fr="Condition" /></th>
<td><textarea class="elastic form-control" id="grantSessionRulKey" cols="30" rows="1"></textarea></td>
</tr>
<tr>
<th><lang en="Message" fr="Message" /></th>
<td><textarea class="elastic form-control" id="grantSessionRulValue" cols="50" rows="1"></textarea></td>
</tr>
</table>
<div class="buttons text-center">
<button onclick="setlmgrantsessionrule(currentId,grantSessionRulComment,grantSessionRulKey,grantSessionRulValue);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- authParams -->
<div id="content_authParams" class="hidden">
<select id="authText" class="form-control"></select>
<input type="text" id="authOptions" class="form-control" size="30" />
<div class="buttons text-center">
<button onclick="reloadAuthParams();return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- Skin -->
<div id="content_skin" class="hidden">
<div class="input-group">
<span class="input-group-btn">
<button class="current btn btn-default" role="button"><img src="" alt="" class="current" /></button>
</span>
<input id="skinText" type="text" readonly="readonly" class="form-control"/>
</div>
<div class="buttons">
<button onclick="setlminputdata(currentId,skinText);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- Vhost -->
<div id="content_vhost" class="hidden">
<input type="text" id="vhost" size="30" class="form-control"/>
<div class="buttons">
<button onclick="setlminputtext(currentId,vhost);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- samlIdpMetaData -->
<div id="content_samlIdpMetaData" class="hidden">
<input type="text" id="samlIdpMetaData" size="30" class="form-control"/>
<div class="buttons">
<button onclick="setlminputtext(currentId,samlIdpMetaData);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- samlSpMetaData -->
<div id="content_samlSpMetaData" class="hidden">
<input type="text" id="samlSpMetaData" size="30" class="form-control"/>
<div class="buttons">
<button onclick="setlminputtext(currentId,samlSpMetaData);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- samlAttribute -->
<div id="content_samlAttribute" class="hidden">
<table class="table">
<tr>
<th><lang en="Key name" fr="Nom de la clef"/></th>
<td><input type="text" id="samlAttributeKey" class="form-control"/></td>
</tr>
<tr>
<th><lang en="Name" fr="Nom"/></th>
<td><input type="text" id="samlAttributeName" class="form-control"/></td>
<th><lang en="Mandatory" fr="Obligatoire"/></th>
<td>
<div class="btn-group" data-toggle="buttons">
<label id="samlAttributeMandatoryOn" class="btn btn-info" name="samlAttributeMandatoryBoolean">
<input type="radio" value="1" /><lang en="On" fr="Activé"/>
</label>
<label id="samlAttributeMandatoryOff" class="btn btn-info" name="samlAttributeMandatoryBoolean">
<input type="radio" value="0" /><lang en="Off" fr="Désactivé"/>
</label>
</div>
</td>
</tr>
<tr>
<th><lang en="Friendly name" fr="Nom alternatif"/></th>
<td><input type="text" id="samlAttributeFriendlyName" class="form-control"/></td>
<th><lang en="Format" fr="Format"/></th>
<td><select id="samlAttributeFormat" class="form-control"></select></td>
</tr>
</table>
<div class="buttons">
<button onclick="setlmsamlattribute(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- samlAssertion -->
<div id="content_samlAssertion" class="hidden">
<table class="table">
<tr>
<th><lang en="Default" fr="Par défaut"/></th>
<td>
<div class="btn-group" data-toggle="buttons">
<label id="samlAssertionDefaultOn" class="btn btn-info" name="samlAssertionDefaultBoolean">
<input type="radio" value="1" /><lang en="On" fr="Activé"/>
</label>
<label id="samlAssertionDefaultOff" class="btn btn-info" name="samlAssertionDefaultBoolean">
<input type="radio" value="0" /><lang en="Off" fr="Désactivé"/>
</label>
</div>
</td>
</tr>
<tr class="hidden">
<th><lang en="Index" fr="Index"/></th>
<td><input type="text" size="50" id="samlAssertionIndex" class="form-control"/></td>
</tr>
<tr>
<th><lang en="Binding" fr="Binding"/></th>
<td><select disabled="disabled" id="samlAssertionBinding" class="form-control"></select></td>
</tr>
<tr>
<th><lang en="Location" fr="URL"/></th>
<td><input type="text" size="50" id="samlAssertionLocation" class="form-control"/></td>
</tr>
</table>
<div class="buttons">
<button onclick="setlmsamlassertion(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- samlService -->
<div id="content_samlService" class="hidden">
<table class="table">
<tr>
<th><lang en="Binding" fr="Binding"/></th>
<td><select disabled="disabled" id="samlServiceBinding" class="form-control"></select></td>
</tr>
<tr>
<th><lang en="Location" fr="URL"/></th>
<td><input type="text" size="50" id="samlServiceLocation" class="form-control"/></td>
</tr>
<tr>
<th><lang en="Response Location" fr="URL de retour"/></th>
<td><input type="text" size="50" id="samlServiceResponseLocation" class="form-control"/></td>
</tr>
</table>
<div class="buttons">
<button onclick="setlmsamlservice(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- OpenID black/white lists -->
<div id="content_openid_serverlist" class="hidden">
<table class="table">
<tr>
<th><lang en="List type" fr="Type de liste"/></th>
<td>
<div class="btn-group" data-toggle="buttons">
<label id="openid_serverlist_black" class="btn btn-info" name="openIdServerlistBoolean">
<input type="radio" autocomplete="off" value="0" /><lang en="Black list" fr="Liste noire"/>
</label>
<label id="openid_serverlist_white" class="btn btn-info" name="openIdServerlistBoolean">
<input type="radio" autocomplete="off" value="1" /><lang en="White list" fr="Liste blanche"/>
</label>
</div>
</td>
</tr>
<tr>
<th><lang en="List" fr="Liste"/></th>
<td><input type="text" size="50" id="openid_serverlist_text" class="form-control"/></td>
</tr>
</table>
<div class="buttons text-center">
<button onclick="setopenididplist(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- authChoice -->
<div id="content_authChoice" class="hidden">
<table class="table">
<tr>
<th><lang en="Key name" fr="Nom de la clef"/></th>
<td><input type="text" id="authChoiceKey" class="form-control"/></td>
</tr>
<tr>
<th><lang en="Authentication module" fr="Module d'authentification"/></th>
<td><select id="authChoiceAuth" class="form-control"></select></td>
</tr>
<tr>
<th><lang en="User module" fr="Module d'utilisateurs"/></th>
<td><select id="authChoiceUser" class="form-control"></select></td>
</tr>
<tr>
<th><lang en="Password module" fr="Module de mots de passe"/></th>
<td><select id="authChoicePassword" class="form-control"></select></td>
</tr>
<tr>
<th><lang en="URL" fr="URL"/></th>
<td><input type="text" id="authChoiceURL" class="form-control"/></td>
</tr>
</table>
<div class="buttons text-center">
<button onclick="setlmauthchoice(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- applicationList Category-->
<div id="content_applicationListCategory" class="hidden">
<table class="table">
<tr>
<th><lang en="Key" fr="Nom de la clef"/></th>
<td><input type="text" id="applicationListCategoryKey" class="form-control"/></td>
</tr>
<tr>
<th><lang en="Display name" fr="Nom à afficher"/></th>
<td><input type="text" id="applicationListCategoryName" class="form-control"/></td>
</tr>
</table>
<div class="buttons text-center">
<button onclick="setlminputtext(currentId,'#applicationListCategoryKey');setlminputdata(currentId,'#applicationListCategoryName');return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- applicationList Application-->
<div id="content_applicationListApplication" class="hidden">
<table class="table">
<tr>
<th><lang en="Key" fr="Nom de la clef"/></th>
<td><input type="text" id="applicationListApplicationKey" class="form-control"/></td>
<th><lang en="Display name" fr="Nom à afficher"/></th>
<td><input type="text" id="applicationListApplicationName" class="form-control"/></td>
</tr>
<tr>
<th><lang en="Address" fr="Adresse"/></th>
<td><input type="text" id="applicationListApplicationURL" class="form-control"/></td>
<th><lang en="Display mode" fr="Mode d'affichage"/></th>
<td><select id="applicationListApplicationDisplay" class="form-control"></select></td>
</tr>
<tr>
<th><lang en="Description" fr="Description"/></th>
<td><textarea id="applicationListApplicationDescription" class="form-control"/></textarea></td>
<th><lang en="Logo" fr="Logo"/></th>
<td>
<div class="input-group">
<span class="input-group-btn">
<button class="current btn btn-default" role="button"><img src="" alt="" class="current" /></button>
</span>
<input type="text" id="applicationListApplicationLogo" readonly="readonly" class="form-control"/>
</div>
</td>
</tr>
</table>
<div class="buttons text-center">
<button onclick="setlmapplication(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- Post -->
<div id="content_post" class="hidden">
<table class="table">
<tr>
<th><lang en="Form URL" fr="URL du formulaire"/></th>
<td><input type="text" id="postKey" size="20" class="form-control"/></td>
<th><lang en="jQuery form selector (optional)" fr="Sélecteur jQuery du formulaire (optionnel)"/></th>
<td><input type="text" id="formSelector" size="20" class="form-control"/></td>
</tr>
<tr>
<th><lang en="Target URL (optional)" fr="URL cible (optionnelle)"/></th>
<td><input type="text" id="postUrl" size="20" class="form-control"/></td>
<th><lang en="jQuery button selector (optional)" fr="Sélecteur jQuery du bouton (optionnel)"/></th>
<td><input type="text" id="buttonSelector" size="20" class="form-control"/></td>
</tr>
<tr>
<th><lang en="jQuery URL (optional)" fr="URL de jQuery (optionnelle)"/></th>
<td colspan="3"><input type="text" id="jqueryUrl" size="60" class="form-control"/></td>
</tr>
</table>
<div class="buttons text-center">
<button onclick="setlminputtext(currentId,postKey);setlmpostform(currentId);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<div id="content_postdata" class="hidden">
<div class="row">
<div class="col-sm-4">
<input type="text" id="postDataKey" class="form-control"/>
</div>
<div class="col-sm-8">
<input type="text" id="postDataValue" class="form-control"/>
</div>
</div>
<div class="buttons text-center">
<button onclick="setlminputtext(currentId,postDataKey,'postdata:');setlminputdata(currentId,postDataValue);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
<!-- oidcOPMetaData -->
<div id="content_oidcOPMetaData" class="hidden">
<input type="text" id="oidcOPMetaData" size="30" class="form-control"/>
<div class="buttons">
<button onclick="setlminputtext(currentId,oidcOPMetaData);return false;" class="btn btn-info">
<i class="glyphicon glyphicon-ok"></i>
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div>
</div>
</form>
<!-- Edition -->
</div>
<!-- Help -->
<div id="help" class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title">
<lang en="Help" fr="Aide"/>
</h1>
</div>
<div id="help_content" class="panel-body">
<!-- AJAX content -->
<lang en="Click on the configuration tree to edit parameters" fr="Cliquer sur l'arbre de configuration pour éditer les paramètres" />
</div>
<!-- Help -->
</div>
<!-- Container -->
</div>
</div>
</div>
</body>
</html>

View File

@ -1,117 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title><lang en="LemonLDAP::NG notification explorer" fr="Explorateur de notifications LemonLDAP::NG"/></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="cache-control" content="no-cache" />
<link href="<TMPL_VAR NAME="DIR">/lemonldap-ng.ico" rel="icon" type="image/x-icon" />
<link href="<TMPL_VAR NAME="DIR">/lemonldap-ng.ico" rel="shortcut icon" />
<!-- jQuery UI CSS -->
<link rel="stylesheet" type="text/css" id="csstheme" href="<TMPL_VAR NAME="DIR">/<TMPL_VAR NAME="CSS_THEME">/jquery-ui-1.10.3.custom.min.css" />
<!-- Bootstrap CSS -->
<link href="<TMPL_VAR NAME="DIR">/css/bootstrap.css" rel="stylesheet">
<link href="<TMPL_VAR NAME="DIR">/css/bootstrap-theme.css" rel="stylesheet">
<!-- Manager CSS -->
<link rel="stylesheet" type="text/css" id="cssmenu" href="<TMPL_VAR NAME="DIR">/css/<TMPL_VAR NAME="CSS">" />
<script src="<TMPL_VAR NAME="DIR">/js/jquery-1.10.2.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/bootstrap.js"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery-ui-1.10.3.custom.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery.cookie.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/tree.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/notifications.js" type="text/JavaScript"></script>
<script type="text/JavaScript">//<![CDATA[
var scriptname='<TMPL_VAR NAME="SCRIPT_NAME">';
var imagepath='<TMPL_VAR NAME="DIR">/images/';
var csspath='<TMPL_VAR NAME="DIR">/css/';
var jqueryuiversion='1.10.3';
var css_menu='<TMPL_VAR NAME="CSS">';
var css_theme='<TMPL_VAR NAME="CSS_THEME">';
var themepath='<TMPL_VAR NAME="DIR">/';
var treejquerycss='false';
var treeautoclose='false';
var lang='<TMPL_VAR NAME="LANG">';
//]]></script>
<script src="<TMPL_VAR NAME="DIR">/js/manager.js" type="text/JavaScript"></script>
</head>
<body>
<TMPL_INCLUDE NAME="top.tpl">
<!-- Container -->
<div class="container-fluid">
<div class="row">
<div class="col-sm-3">
<!-- Menu (tree) -->
<div id="menu" class="panel panel-default panel-body text-center">
<!-- Query choice -->
<div id="query-switch" class="btn-group btn-group-justified" role="group">
<a href="<TMPL_VAR NAME="SCRIPT_NAME">" alt="list" class="btn btn-info"><i class="glyphicon glyphicon-eye-open"></i> <lang en="Active" fr="Actives" /></a>
<a href="<TMPL_VAR NAME="SCRIPT_NAME">?listDone=1" alt="listDone" class="btn btn-info"><i class="glyphicon glyphicon-eye-close"></i> <lang en="Done" fr="Validées" /></a>
<a alt="newNotif" onclick="newNotif()" class="btn btn-info"><i class="glyphicon glyphicon-plus-sign"></i> <lang en="Create" fr="Créer" /></a>
</div>
<hr />
<TMPL_VAR NAME="TREE">
</div>
</div>
<div class="col-sm-9">
<!-- Data -->
<div id="data" class="panel panel-default">
</div>
</div>
</div>
</div>
<!-- Form to create a new notification -->
<div id="newNotif" style="display: none">
<div class="panel-heading">
<h1 class="panel-title text-center"><lang en="New notification" fr="Nouvelle notification" /></h1>
</div>
<div class="panel-body">
<table style="width:70%;margin: 10px auto;">
<tr>
<th style="text-align:right;"><label for="uid"><lang en="User login:" fr="Identifiant de l'utilisateur :" /></label></th>
<td><input id="uid" type="text" /></td>
</tr>
<tr>
<th style="text-align:right;"><label for="date"><lang en="Date:" fr="Date :" /></label></th>
<td><input id="date" type="text" /></td>
</tr>
<tr>
<th style="text-align:right;"><label for="ref"><lang en="Reference:" fr="Référence :" /></label></th>
<td><input id="ref" type="text" /></td>
</tr>
<tr>
<th style="text-align:right;"><label for="condition">Condition <lang en="(optional):" fr="(optionnelle) :" /></label></th>
<td><input id="condition" type="text" /></td>
</tr>
<tr><td colspan="2">
<div id="newNotifHelp" class="alert alert-info">
<lang en="Set XML content here. You can use the following markups:" fr="Insérer le contenu XML ici. Vous pouvez utiliser les balises suivantes :" />
<ul>
<li><tt>&lt;title&gt;</tt><lang en="a title" fr="un titre" /><tt>&lt;/title&gt;</li>
<li><tt>&lt;subtitle&gt;</tt><lang en="a subtitle" fr="un sous-titre" /><tt>&lt;/subtitle&gt;</li>
<li><tt>&lt;text&gt;</tt><lang en="some text" fr="du texte" /><tt>&lt;/text&gt;</li>
<li><tt>&lt;check&gt;</tt><lang en="a checkbox" fr="une case à cocher" /><tt>&lt;/check&gt;</li>
</ul>
</div>
</td></tr>
<tr><td colspan="2">
<textarea rows="10" cols="80" id="xml"></textarea><br />
</td></tr>
</table>
<div class="text-center">
<a id="sendNewNotif" onclick=sendNewNotif() class="btn btn-success"><i class="glyphicon glyphicon-plus-sign"></i> <lang en="Create" fr="Créer" /></a>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,74 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title><lang en="LemonLDAP::NG session explorer" fr="Explorateur de sessions LemonLDAP::NG"/></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="cache-control" content="no-cache" />
<link href="<TMPL_VAR NAME="DIR">/lemonldap-ng.ico" rel="icon" type="image/x-icon" />
<link href="<TMPL_VAR NAME="DIR">/lemonldap-ng.ico" rel="shortcut icon" />
<!-- jQuery UI CSS -->
<link rel="stylesheet" type="text/css" id="csstheme" href="<TMPL_VAR NAME="DIR">/<TMPL_VAR NAME="CSS_THEME">/jquery-ui-1.10.3.custom.min.css" />
<!-- Bootstrap CSS -->
<link href="<TMPL_VAR NAME="DIR">/css/bootstrap.css" rel="stylesheet">
<link href="<TMPL_VAR NAME="DIR">/css/bootstrap-theme.css" rel="stylesheet">
<!-- Manager CSS -->
<link rel="stylesheet" type="text/css" id="cssmenu" href="<TMPL_VAR NAME="DIR">/css/<TMPL_VAR NAME="CSS">" />
<script src="<TMPL_VAR NAME="DIR">/js/jquery-1.10.2.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/bootstrap.js"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery-ui-1.10.3.custom.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/jquery.cookie.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/tree.js" type="text/JavaScript"></script>
<script src="<TMPL_VAR NAME="DIR">/js/sessions.js" type="text/JavaScript"></script>
<script type="text/JavaScript">//<![CDATA[
var scriptname='<TMPL_VAR NAME="SCRIPT_NAME">';
var imagepath='<TMPL_VAR NAME="DIR">/images/';
var csspath='<TMPL_VAR NAME="DIR">/css/';
var jqueryuiversion='1.10.3';
var css_menu='<TMPL_VAR NAME="CSS">';
var css_theme='<TMPL_VAR NAME="CSS_THEME">';
var themepath='<TMPL_VAR NAME="DIR">/';
var treejquerycss='false';
var treeautoclose='false';
var lang='<TMPL_VAR NAME="LANG">';
//]]></script>
<script src="<TMPL_VAR NAME="DIR">/js/manager.js" type="text/JavaScript"></script>
</head>
<body>
<TMPL_INCLUDE NAME="top.tpl">
<!-- Container -->
<div class="container-fluid">
<div class="row">
<div class="col-sm-3">
<!-- Menu (tree) -->
<div id="menu" class="panel panel-default panel-body text-center">
<!-- Query choice -->
<div id="query-switch" class="btn-group btn-group-justified" role="group">
<a href="<TMPL_VAR NAME="SCRIPT_NAME">" alt="user" class="btn btn-info"><i class="glyphicon glyphicon-user"></i> <lang en="User" fr="Utilisateur" /></a>
<a href="<TMPL_VAR NAME="SCRIPT_NAME">?ipclasses=1" alt="ip" class="btn btn-info"><i class="glyphicon glyphicon-tag"></i> <lang en="IP" fr="IP" /></a>
<a href="<TMPL_VAR NAME="SCRIPT_NAME">?doubleIp=1" alt="2ip" class="btn btn-info"><i class="glyphicon glyphicon-tags"></i> <lang en="Multi IP" fr="Multi IP" /></a>
</div>
<hr />
<TMPL_VAR NAME="TREE">
</div>
</div>
<div class="col-sm-9">
<!-- Data -->
<div id="data" class="panel panel-default">
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,39 +0,0 @@
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#manager-menu">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="<TMPL_VAR NAME="SCRIPT_NAME">">
<img src="<TMPL_VAR NAME="DIR">/images/logo_lemonldap-ng.png" alt="LemonLDAP::NG" class="brand"/>
</a>
</div>
<div class="collapse navbar-collapse" id="manager-menu">
<ul class="nav navbar-nav">
<li class="<TMPL_VAR NAME="LI_CLASS_CONFIGURATION">"><a href="index.pl"><i class="glyphicon glyphicon-cog"></i> <lang en="Configuration" fr="Configuration"/></a></li>
<li class="<TMPL_VAR NAME="LI_CLASS_SESSION">"><a href="sessions.pl"><i class="glyphicon glyphicon-user"></i> <lang en="Sessions" fr="Sessions"/></a></li>
<li class="<TMPL_VAR NAME="LI_CLASS_NOTIFICATION">"><a href="notifications.pl"><i class="glyphicon glyphicon-bell"></i> <lang en="Notifications" fr="Notifications"/></a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Menu <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li role="presentation" class="dropdown-header"><lang en="Organization" fr="Organisation" /></li>
<li><a href="#"><span class="css-switch" alt="tree"><i class="glyphicon glyphicon-list"></i> <lang en="Tree" fr="Arbre" /></span></a></li>
<li><a href="#"><span class="css-switch" alt="accordion"><i class="glyphicon glyphicon-align-justify"></i> <lang en="Accordion" fr="Accordéon" /></span></a></li>
<li role="presentation" class="divider"></li>
<li><a href="<TMPL_VAR NAME="PORTAL_URL">"><i class="glyphicon glyphicon-home"></i> <lang en="Portal" fr="Portail" /></a></li>
<li><a href="<TMPL_VAR NAME="PORTAL_URL">?logout=1"><i class="glyphicon glyphicon-off"></i> <lang en="Logout" fr="Déconnexion" /></a></li>
<TMPL_IF NAME="VERSION">
<li role="presentation" class="divider"></li>
<li role="presentation" class="dropdown-header"><i class="glyphicon glyphicon-info-sign"></i> Version <TMPL_VAR NAME="VERSION"></li>
</TMPL_IF>
</ul>
</li>
</ul>
</div>
</div>
</nav>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Some files were not shown because too many files have changed in this diff Show More