Split notifications (XML vs JSON) [#868]
This commit is contained in:
parent
f6665c2d41
commit
61fd463f45
|
@ -2,19 +2,21 @@ package Lemonldap::NG::Common::Notifications;
|
|||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use XML::LibXML;
|
||||
|
||||
our $VERSION = '2.0.0';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Module';
|
||||
|
||||
# XML parser. TODO: replace this by JSON
|
||||
has parser => (
|
||||
is => 'rw',
|
||||
builder => sub {
|
||||
return XML::LibXML->new();
|
||||
sub import {
|
||||
if ( $_[1] eq 'XML' ) {
|
||||
extends 'Lemonldap::NG::Common::Notifications::XML',
|
||||
'Lemonldap::NG::Common::Module';
|
||||
}
|
||||
else {
|
||||
extends 'Lemonldap::NG::Common::Notifications::JSON',
|
||||
'Lemonldap::NG::Common::Module';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
has notifField => (
|
||||
is => 'rw',
|
||||
|
@ -40,111 +42,4 @@ sub getNotifications {
|
|||
}
|
||||
}
|
||||
|
||||
# Check XML datas and insert new notifications.
|
||||
# @param $xml XML string containing notification
|
||||
# @return number of notifications done
|
||||
sub newNotification {
|
||||
my ( $self, $xml ) = @_;
|
||||
eval { $xml = $self->parser->parse_string($xml); };
|
||||
if ($@) {
|
||||
$self->lmLog( "Unable to read XML file : $@", 'error' );
|
||||
return 0;
|
||||
}
|
||||
my @notifs;
|
||||
my ( $version, $encoding ) = ( $xml->version(), $xml->encoding() );
|
||||
foreach
|
||||
my $notif ( $xml->documentElement->getElementsByTagName('notification') )
|
||||
{
|
||||
my @datas = ();
|
||||
|
||||
# Mandatory information
|
||||
foreach (qw(date uid reference)) {
|
||||
my $tmp;
|
||||
unless ( $tmp = $notif->getAttribute($_) ) {
|
||||
$self->lmLog( "Attribute $_ is missing", 'error' );
|
||||
return 0;
|
||||
}
|
||||
push @datas, $tmp;
|
||||
}
|
||||
|
||||
# Other information
|
||||
foreach (qw(condition)) {
|
||||
my $tmp;
|
||||
if ( $tmp = $notif->getAttribute($_) ) {
|
||||
push @datas, $tmp;
|
||||
}
|
||||
else { push @datas, ""; }
|
||||
}
|
||||
|
||||
my $result = XML::LibXML::Document->new( $version, $encoding );
|
||||
my $root = XML::LibXML::Element->new('root');
|
||||
$root->appendChild($notif);
|
||||
$result->setDocumentElement($root);
|
||||
push @notifs, [ @datas, $result ];
|
||||
}
|
||||
my $tmp = $self->{type};
|
||||
my $count;
|
||||
foreach (@notifs) {
|
||||
$count++;
|
||||
my ( $r, $err ) = $self->newNotif(@$_);
|
||||
die "$err" unless ($r);
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
## Delete notifications for the connected user
|
||||
## @param $uid of the user
|
||||
## @param $myref notification's reference
|
||||
## @return number of deleted notifications
|
||||
sub deleteNotification {
|
||||
my ( $self, $uid, $myref ) = @_;
|
||||
my @data;
|
||||
|
||||
# Check input parameters
|
||||
unless ( $uid and $myref ) {
|
||||
$self->lmLog(
|
||||
"SOAP service deleteNotification called without all parameters",
|
||||
'error' );
|
||||
return 0;
|
||||
}
|
||||
|
||||
$self->lmLog(
|
||||
"SOAP service deleteNotification called for uid $uid and reference $myref",
|
||||
'debug'
|
||||
);
|
||||
|
||||
# Get notifications
|
||||
my $user = $self->get($uid);
|
||||
|
||||
# Return 0 if no files were found
|
||||
return 0 unless ($user);
|
||||
|
||||
# Counting
|
||||
my $count = 0;
|
||||
|
||||
foreach my $ref ( keys %$user ) {
|
||||
my $xml = $self->parser->parse_string( $user->{$ref} );
|
||||
|
||||
# Browse notification in file
|
||||
foreach my $notif (
|
||||
$xml->documentElement->getElementsByTagName('notification') )
|
||||
{
|
||||
|
||||
# Get notification's data
|
||||
if ( $notif->getAttribute('reference') eq $myref ) {
|
||||
push @data, $ref;
|
||||
}
|
||||
|
||||
# Delete the notification (really)
|
||||
foreach (@data) {
|
||||
if ( $self->purge( $_, 1 ) ) {
|
||||
$self->lmLog( "Notification $_ was removed.", 'debug' );
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -14,6 +14,10 @@ use Encode;
|
|||
our $VERSION = '2.0.0';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Notifications';
|
||||
sub import {
|
||||
shift;
|
||||
return Lemonldap::NG::Common::Notifications->import(@_)
|
||||
}
|
||||
|
||||
has dbiTable => (
|
||||
is => 'ro',
|
||||
|
@ -28,7 +32,7 @@ has dbiChain => (
|
|||
has dbiUser => (
|
||||
is => 'ro',
|
||||
default => sub {
|
||||
$_[0]->p->lmLog( 'Warning: "dbiUser" parameter is not set', 'warn' );
|
||||
$_[0]->{p}->lmLog( 'Warning: "dbiUser" parameter is not set', 'warn' );
|
||||
return '';
|
||||
}
|
||||
);
|
||||
|
|
|
@ -12,6 +12,11 @@ use MIME::Base64;
|
|||
our $VERSION = '2.0.0';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Notifications';
|
||||
sub import {
|
||||
shift;
|
||||
return Lemonldap::NG::Common::Notifications->import(@_)
|
||||
}
|
||||
|
||||
|
||||
has dirName => ( is => 'ro', required => 1 );
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ use utf8;
|
|||
our $VERSION = '2.0.0';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Notifications';
|
||||
sub import {
|
||||
shift;
|
||||
return Lemonldap::NG::Common::Notifications->import(@_)
|
||||
}
|
||||
|
||||
has ldapServer => (
|
||||
is => 'ro',
|
||||
|
|
122
lemonldap-ng-common/lib/Lemonldap/NG/Common/Notifications/XML.pm
Normal file
122
lemonldap-ng-common/lib/Lemonldap/NG/Common/Notifications/XML.pm
Normal file
|
@ -0,0 +1,122 @@
|
|||
package Lemonldap::NG::Common::Notifications::XML;
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use XML::LibXML;
|
||||
|
||||
# XML parser
|
||||
has parser => (
|
||||
is => 'rw',
|
||||
builder => sub {
|
||||
return XML::LibXML->new();
|
||||
}
|
||||
);
|
||||
|
||||
# Check XML datas and insert new notifications.
|
||||
# @param $xml XML string containing notification
|
||||
# @return number of notifications done
|
||||
sub newNotification {
|
||||
my ( $self, $xml ) = @_;
|
||||
eval { $xml = $self->parser->parse_string($xml); };
|
||||
if ($@) {
|
||||
$self->lmLog( "Unable to read XML file : $@", 'error' );
|
||||
return 0;
|
||||
}
|
||||
my @notifs;
|
||||
my ( $version, $encoding ) = ( $xml->version(), $xml->encoding() );
|
||||
foreach
|
||||
my $notif ( $xml->documentElement->getElementsByTagName('notification') )
|
||||
{
|
||||
my @datas = ();
|
||||
|
||||
# Mandatory information
|
||||
foreach (qw(date uid reference)) {
|
||||
my $tmp;
|
||||
unless ( $tmp = $notif->getAttribute($_) ) {
|
||||
$self->lmLog( "Attribute $_ is missing", 'error' );
|
||||
return 0;
|
||||
}
|
||||
push @datas, $tmp;
|
||||
}
|
||||
|
||||
# Other information
|
||||
foreach (qw(condition)) {
|
||||
my $tmp;
|
||||
if ( $tmp = $notif->getAttribute($_) ) {
|
||||
push @datas, $tmp;
|
||||
}
|
||||
else { push @datas, ""; }
|
||||
}
|
||||
|
||||
my $result = XML::LibXML::Document->new( $version, $encoding );
|
||||
my $root = XML::LibXML::Element->new('root');
|
||||
$root->appendChild($notif);
|
||||
$result->setDocumentElement($root);
|
||||
push @notifs, [ @datas, $result ];
|
||||
}
|
||||
my $tmp = $self->{type};
|
||||
my $count;
|
||||
foreach (@notifs) {
|
||||
$count++;
|
||||
my ( $r, $err ) = $self->newNotif(@$_);
|
||||
die "$err" unless ($r);
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
## Delete notifications for the connected user
|
||||
## @param $uid of the user
|
||||
## @param $myref notification's reference
|
||||
## @return number of deleted notifications
|
||||
sub deleteNotification {
|
||||
my ( $self, $uid, $myref ) = @_;
|
||||
my @data;
|
||||
|
||||
# Check input parameters
|
||||
unless ( $uid and $myref ) {
|
||||
$self->lmLog(
|
||||
"SOAP service deleteNotification called without all parameters",
|
||||
'error' );
|
||||
return 0;
|
||||
}
|
||||
|
||||
$self->lmLog(
|
||||
"SOAP service deleteNotification called for uid $uid and reference $myref",
|
||||
'debug'
|
||||
);
|
||||
|
||||
# Get notifications
|
||||
my $user = $self->get($uid);
|
||||
|
||||
# Return 0 if no files were found
|
||||
return 0 unless ($user);
|
||||
|
||||
# Counting
|
||||
my $count = 0;
|
||||
|
||||
foreach my $ref ( keys %$user ) {
|
||||
my $xml = $self->parser->parse_string( $user->{$ref} );
|
||||
|
||||
# Browse notification in file
|
||||
foreach my $notif (
|
||||
$xml->documentElement->getElementsByTagName('notification') )
|
||||
{
|
||||
|
||||
# Get notification's data
|
||||
if ( $notif->getAttribute('reference') eq $myref ) {
|
||||
push @data, $ref;
|
||||
}
|
||||
|
||||
# Delete the notification (really)
|
||||
foreach (@data) {
|
||||
if ( $self->purge( $_, 1 ) ) {
|
||||
$self->lmLog( "Notification $_ was removed.", 'debug' );
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
1;
|
|
@ -31,9 +31,7 @@ sub init {
|
|||
my ( $self, $args ) = @_;
|
||||
$args ||= {};
|
||||
|
||||
my $conf = $self->confAcc;
|
||||
|
||||
if ( my $localconf = $conf->getLocalConf(MANAGERSECTION) ) {
|
||||
if ( my $localconf = $self->confAcc->getLocalConf(MANAGERSECTION) ) {
|
||||
$self->{$_} = $args->{$_} // $localconf->{$_}
|
||||
foreach ( keys %$localconf );
|
||||
}
|
||||
|
@ -57,10 +55,11 @@ sub init {
|
|||
split( /[,\s]+/, $self->{enabledModules} );
|
||||
extends 'Lemonldap::NG::Handler::PSGI::Router', @enabledModules;
|
||||
my @working;
|
||||
my $conf = $self->confAcc->getConf;
|
||||
for ( my $i = 0 ; $i < @enabledModules ; $i++ ) {
|
||||
my $mod = $enabledModules[$i];
|
||||
no strict 'refs';
|
||||
if ( &{"${mod}::addRoutes"}($self) ) {
|
||||
if ( &{"${mod}::addRoutes"}($self,$conf) ) {
|
||||
$self->lmLog( "Module $mod enabled", 'debug' );
|
||||
push @working, $mod;
|
||||
}
|
||||
|
|
|
@ -1720,6 +1720,10 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
|
|||
'oidcStorageOptions' => {
|
||||
'type' => 'keyTextContainer'
|
||||
},
|
||||
'oldNotifFormat' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'openIdAttr' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
|
|
|
@ -660,6 +660,11 @@ sub attributes {
|
|||
},
|
||||
|
||||
# Notification
|
||||
oldNotifFormat => {
|
||||
type => 'bool',
|
||||
default => 0,
|
||||
documentation => 'Use old XML format',
|
||||
},
|
||||
notificationWildcard => {
|
||||
type => 'text',
|
||||
default => 'allusers',
|
||||
|
|
|
@ -534,6 +534,7 @@ sub tree {
|
|||
help => 'notifications.html',
|
||||
nodes => [
|
||||
'notification',
|
||||
'oldNotifFormat',
|
||||
'notificationStorage',
|
||||
'notificationStorageOptions',
|
||||
'notificationWildcard',
|
||||
|
|
|
@ -27,7 +27,7 @@ our $VERSION = '2.0.0';
|
|||
use constant defaultRoute => 'manager.html';
|
||||
|
||||
sub addRoutes {
|
||||
my $self = shift;
|
||||
my($self,$conf) = @_;
|
||||
|
||||
# HTML template
|
||||
$self->addRoute( 'manager.html', undef, ['GET'] )
|
||||
|
|
|
@ -7,7 +7,7 @@ use Mouse;
|
|||
use Lemonldap::NG::Common::Conf::Constants;
|
||||
use Lemonldap::NG::Common::PSGI::Constants;
|
||||
use Lemonldap::NG::Common::Conf::ReConstants;
|
||||
use Lemonldap::NG::Common::Notifications;
|
||||
require Lemonldap::NG::Common::Notifications;
|
||||
|
||||
use feature 'state';
|
||||
|
||||
|
@ -24,7 +24,14 @@ has _notifAccess => ( is => 'rw' );
|
|||
use constant defaultRoute => 'notifications.html';
|
||||
|
||||
sub addRoutes {
|
||||
my $self = shift;
|
||||
my($self,$conf) = @_;
|
||||
|
||||
if($conf->{oldNotifFormat}) {
|
||||
Lemonldap::NG::Common::Notifications->import('XML');
|
||||
}
|
||||
else {
|
||||
Lemonldap::NG::Common::Notifications->import('JSON');
|
||||
}
|
||||
|
||||
unless ( $self->notifAccess ) {
|
||||
$self->addRoute( 'notifications.html', 'notEnabled', ['GET'] );
|
||||
|
|
|
@ -25,7 +25,7 @@ our $VERSION = '2.0.0';
|
|||
use constant defaultRoute => 'sessions.html';
|
||||
|
||||
sub addRoutes {
|
||||
my $self = shift;
|
||||
my($self,$conf) = @_;
|
||||
|
||||
# HTML template
|
||||
$self->addRoute( 'sessions.html', undef, ['GET'] )
|
||||
|
@ -39,11 +39,6 @@ sub addRoutes {
|
|||
['DELETE']
|
||||
);
|
||||
|
||||
my $conf = $self->confAcc->getConf(
|
||||
{ localPrm => $self->confAcc->getLocalConf(SESSIONSEXPLORERSECTION) } );
|
||||
#
|
||||
# Return unless configuration is available
|
||||
return 0 unless ($conf);
|
||||
$self->setTypes($conf);
|
||||
|
||||
$self->{ipField} ||= 'ipAddr';
|
||||
|
|
|
@ -461,6 +461,7 @@
|
|||
"oidcServiceAllowImplicitFlow": "Implicit Flow",
|
||||
"oidcServiceAllowHybridFlow": "Hybrid Flow",
|
||||
"ok": "OK",
|
||||
"oldNotifFormat": "Use old XML format",
|
||||
"openIdAttr": "OpenID login",
|
||||
"openIdAuthnLevel": "Authentication level",
|
||||
"openIdExportedVars": "Exported variables",
|
||||
|
|
|
@ -461,6 +461,7 @@
|
|||
"oidcServiceAllowImplicitFlow": "Implicit Flow",
|
||||
"oidcServiceAllowHybridFlow": "Hybrid Flow",
|
||||
"ok": "OK",
|
||||
"oldNotifFormat": "Utiliser l'ancien format XML",
|
||||
"openIdAttr": "Identifiant OpenID",
|
||||
"openIdAuthnLevel": "Niveau d'authentification",
|
||||
"openIdExportedVars": "Variables exportées",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -132,6 +132,7 @@
|
|||
"_whatToTrace": "$_auth eq 'SAML' ? \"$_user\\@$_idpConfKey\" : \"$_user\""
|
||||
},
|
||||
"notification": 1,
|
||||
"oldNotifFormat": 1,
|
||||
"notificationStorage": "File",
|
||||
"notificationStorageOptions": {
|
||||
"dirName": "t/notifications"
|
||||
|
|
|
@ -2454,4 +2454,8 @@
|
|||
"id": "cfgLog",
|
||||
"title": "cfgLog",
|
||||
"data": "Log"
|
||||
}, {
|
||||
"id": "oldNotifFormat",
|
||||
"title": "oldNotifFormat",
|
||||
"data": 1
|
||||
}]
|
||||
|
|
|
@ -46,6 +46,8 @@ lib/Lemonldap/NG/Portal/Lib/Choice.pm
|
|||
lib/Lemonldap/NG/Portal/Lib/DBI.pm
|
||||
lib/Lemonldap/NG/Portal/Lib/LDAP.pm
|
||||
lib/Lemonldap/NG/Portal/Lib/Net/LDAP.pm
|
||||
lib/Lemonldap/NG/Portal/Lib/Notifications/JSON.pm
|
||||
lib/Lemonldap/NG/Portal/Lib/Notifications/XML.pm
|
||||
lib/Lemonldap/NG/Portal/Lib/OneTimeToken.pm
|
||||
lib/Lemonldap/NG/Portal/Lib/OpenID/Server.pm
|
||||
lib/Lemonldap/NG/Portal/Lib/OpenID/SREG.pm
|
||||
|
@ -333,7 +335,6 @@ site/templates/pastel/yubikeyform.tpl
|
|||
t/01-AuthDemo.t
|
||||
t/02-Password-Demo.t
|
||||
t/03-XSS-protection.t
|
||||
t/04-Notification-File.t
|
||||
t/20-Auth-and-password-DBI.t
|
||||
t/21-Auth-and-password-LDAP.t
|
||||
t/22-Auth-and-password-AD.t
|
||||
|
@ -361,6 +362,7 @@ t/34-Auth-Proxy-and-SOAP-Server.t
|
|||
t/35-REST-sessions-with-REST-server.t
|
||||
t/35-SOAP-sessions-with-SOAP-server.t
|
||||
t/40-Notifications-DBI.t
|
||||
t/40-Notifications-File.t
|
||||
t/41-Captcha.t
|
||||
t/41-Token.t
|
||||
t/42-Register-Demo-with-captcha.t
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
package Lemonldap::NG::Portal::Lib::Notifications::XML;
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use XML::LibXML;
|
||||
use XML::LibXSLT;
|
||||
|
||||
our $VERSION = '2.0.0';
|
||||
|
||||
# Lemonldap::NG::Portal::Main::Plugin provides addAuthRoute() and
|
||||
# addUnauthRoute() methods in addition of Lemonldap::NG::Common::Module.
|
||||
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
||||
|
||||
# PROPERTIES
|
||||
|
||||
# XML parser
|
||||
has parser => (
|
||||
is => 'rw',
|
||||
builder => sub {
|
||||
return XML::LibXML->new();
|
||||
}
|
||||
);
|
||||
|
||||
# XSLT document
|
||||
has stylesheet => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
builder => sub {
|
||||
my $self = $_[0];
|
||||
my $xslt = XML::LibXSLT->new();
|
||||
my $styleFile = (
|
||||
(
|
||||
$self->conf->{notificationXSLTfile}
|
||||
and -e $self->conf->{notificationXSLTfile}
|
||||
)
|
||||
? $self->conf->{notificationXSLTfile}
|
||||
: $self->conf->{templatesDir} . '/common/notification.xsl'
|
||||
);
|
||||
die "$styleFile not found" unless ( -e $styleFile );
|
||||
return $xslt->parse_stylesheet( $self->parser->parse_file($styleFile) );
|
||||
}
|
||||
);
|
||||
|
||||
# Underlying notifications storage object (File, DBI, LDAP,...)
|
||||
has notifObject => ( is => 'rw' );
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
sub init {
|
||||
1;
|
||||
}
|
||||
|
||||
# Search for notifications and if any, returns HTML fragment.
|
||||
sub checkForNotifications {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
# Look for pending notifications in database
|
||||
my $uid = $req->sessionInfo->{ $self->notifObject->notifField };
|
||||
my ( $notifs, $forUser ) = $self->notifObject->getNotifications($uid);
|
||||
my $form;
|
||||
return 0 unless ($notifs);
|
||||
|
||||
# Transform notifications
|
||||
my $i = 0; #Files count
|
||||
foreach my $file ( values %$notifs ) {
|
||||
my $xml = $self->parser->parse_string($file);
|
||||
my $j = 0; #Notifications count
|
||||
LOOP: foreach my $notif (
|
||||
eval { $xml->documentElement->getElementsByTagName('notification') }
|
||||
)
|
||||
{
|
||||
|
||||
# Get the reference
|
||||
my $reference = $notif->getAttribute('reference');
|
||||
|
||||
$self->lmLog( "Get reference $reference", 'debug' );
|
||||
|
||||
# Check it in session
|
||||
if ( exists $req->{sessionInfo}->{"notification_$reference"} ) {
|
||||
|
||||
# The notification was already accepted
|
||||
$self->lmLog( "Notification $reference was already accepted",
|
||||
'debug' );
|
||||
|
||||
# Remove it from XML
|
||||
$notif->unbindNode();
|
||||
next LOOP;
|
||||
}
|
||||
|
||||
# Check condition if any
|
||||
my $condition = $notif->getAttribute('condition');
|
||||
|
||||
if ($condition) {
|
||||
|
||||
$self->lmLog( "Get condition $condition", 'debug' );
|
||||
|
||||
unless ( $self->p->HANDLER->safe->reval($condition) ) {
|
||||
$self->lmLog( "Notification condition not accepted",
|
||||
'debug' );
|
||||
|
||||
# Remove it from XML
|
||||
$notif->unbindNode();
|
||||
next LOOP;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$j++;
|
||||
}
|
||||
|
||||
# Go to next file if no notification found
|
||||
next unless $j;
|
||||
$i++;
|
||||
|
||||
# Transform XML into HTML
|
||||
my $results = $self->stylesheet->transform( $xml, start => $i );
|
||||
$form .= $self->stylesheet->output_string($results);
|
||||
}
|
||||
if ($@) {
|
||||
$self->lmLog( "Bad XML file: a notification for $uid was not done ($@)",
|
||||
'warn' );
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Stop here if nothing to display
|
||||
return 0 unless $i;
|
||||
|
||||
# Returns HTML fragment
|
||||
$req->id( $self->p->HANDLER->tsv->{cipher}->encrypt( $req->id ) );
|
||||
return $form;
|
||||
}
|
||||
|
||||
sub getNotifBack {
|
||||
my ( $self, $req, $name ) = @_;
|
||||
|
||||
# Look if all notifications have been accepted. If not, redirects to
|
||||
# portal
|
||||
|
||||
# Search for Lemonldap::NG cookie (ciphered)
|
||||
my $id;
|
||||
unless ( $id = $req->cookies->{ $self->{conf}->{cookieName} } ) {
|
||||
return $self->p->sendError( $req, 'No cookie found', 401 );
|
||||
}
|
||||
$id = $self->p->HANDLER->tsv->{cipher}->decrypt($id)
|
||||
or return $self->sendError( $req, 'Unable to decrypt', 500 );
|
||||
|
||||
# Verify that session exists
|
||||
$req->userData( $self->p->HANDLER->retrieveSession($id) )
|
||||
or return $self->sendError( $req, 'Unknown session', 401 );
|
||||
|
||||
# Restore datas
|
||||
$self->p->importHandlerDatas($req);
|
||||
my $uid = $req->sessionInfo->{ $self->notifObject->notifField };
|
||||
|
||||
my ( $notifs, $forUser ) = $self->notifObject->getNotifications($uid);
|
||||
if ($notifs) {
|
||||
|
||||
# Get accepted notifications
|
||||
my ( $refs, $checks ) = ( {}, {} );
|
||||
my $prms = $req->parameters;
|
||||
foreach ( keys %$prms ) {
|
||||
my $v = $prms->{$_};
|
||||
if (s/^reference//) {
|
||||
$refs->{$v} = $_;
|
||||
}
|
||||
elsif ( s/^check// and /^(\d+x\d+)x(\d+)$/ and $v eq 'accepted' ) {
|
||||
push @{ $checks->{$1} }, $2;
|
||||
}
|
||||
}
|
||||
|
||||
my $result = 1;
|
||||
foreach my $fileName ( keys %$notifs ) {
|
||||
my $file = $notifs->{$fileName};
|
||||
my $fileResult = 1;
|
||||
my $xml = $self->parser->parse_string($file);
|
||||
|
||||
# Get pending notifications and verify that they have been accepted
|
||||
foreach my $notif (
|
||||
$xml->documentElement->getElementsByTagName('notification') )
|
||||
{
|
||||
my $reference = $notif->getAttribute('reference');
|
||||
|
||||
# Check if this pending notification has been seen
|
||||
if ( my $refId = $refs->{$reference} ) {
|
||||
|
||||
# Verity that checkboxes have been checked
|
||||
my @toCheck = $notif->getElementsByTagName('check');
|
||||
if ( my $toCheckCount = @toCheck ) {
|
||||
unless ($checks->{$refId}
|
||||
and $toCheckCount == @{ $checks->{$refId} } )
|
||||
{
|
||||
$self->p->userNotice(
|
||||
"$uid has not accepted notification $reference"
|
||||
);
|
||||
$result = $fileResult = 0;
|
||||
next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Current pending notification has not been found in
|
||||
# request
|
||||
$result = $fileResult = 0;
|
||||
$self->lmLog(
|
||||
'Current pending notification has not been found',
|
||||
'debug' );
|
||||
next;
|
||||
}
|
||||
|
||||
# Register acceptation
|
||||
$self->p->userNotice(
|
||||
"$uid has accepted notification $reference");
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ "notification_$reference" => time() } );
|
||||
$self->lmLog(
|
||||
"Notification $reference registered in persistent session",
|
||||
'debug'
|
||||
);
|
||||
}
|
||||
|
||||
# Notifications accepted for this file, delete it unless it's a wildcard
|
||||
if ( $fileResult and exists $forUser->{$fileName} ) {
|
||||
$self->lmLog( "Notification file deleted", 'debug' );
|
||||
$self->notifObject->delete($fileName);
|
||||
}
|
||||
}
|
||||
unless ($result) {
|
||||
|
||||
# One pending notification has been found and not accepted,
|
||||
# restart process to display pending notifications
|
||||
# TODO: is it a good idea to launch all 'afterDatas' subs ?
|
||||
$self->lmLog(
|
||||
'Pending notification has been found and not accepted',
|
||||
'debug' );
|
||||
return $self->p->do( $req, $self->p->afterDatas );
|
||||
}
|
||||
|
||||
# All pending notifications have been accepted, restore cookies and
|
||||
# launch 'controlUrl' to restore "urldc" using do()
|
||||
$self->lmLog( 'All pending notifications have been accepted', 'debug' );
|
||||
$self->rebuildCookies($req);
|
||||
return $self->p->do( $req, ['controlUrl'] );
|
||||
}
|
||||
else {
|
||||
# No notifications checked here, this entry point must not be called.
|
||||
# Redirecting to portal
|
||||
$self->lmLog( 'No notifications checked', 'debug' );
|
||||
$req->mustRedirect(1);
|
||||
return $self->p->do( $req, [] );
|
||||
}
|
||||
}
|
||||
|
||||
*rebuildCookies =
|
||||
\&Lemonldap::NG::Portal::Plugins::Notifications::rebuildCookies;
|
||||
|
||||
1;
|
|
@ -13,44 +13,12 @@ package Lemonldap::NG::Portal::Plugins::Notifications;
|
|||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use XML::LibXSLT;
|
||||
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_NOTIFICATION);
|
||||
|
||||
our $VERSION = '2.0.0';
|
||||
|
||||
# Lemonldap::NG::Portal::Main::Plugin provides addAuthRoute() and
|
||||
# addUnauthRoute() methods in addition of Lemonldap::NG::Common::Module.
|
||||
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
||||
|
||||
# PROPERTIES
|
||||
|
||||
sub parser {
|
||||
return $_[0]->notifObject->parser;
|
||||
}
|
||||
|
||||
# XSLT document
|
||||
has stylesheet => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
builder => sub {
|
||||
my $self = $_[0];
|
||||
my $xslt = XML::LibXSLT->new();
|
||||
my $styleFile = (
|
||||
(
|
||||
$self->conf->{notificationXSLTfile}
|
||||
and -e $self->conf->{notificationXSLTfile}
|
||||
)
|
||||
? $self->conf->{notificationXSLTfile}
|
||||
: $self->conf->{templatesDir} . '/common/notification.xsl'
|
||||
);
|
||||
die "$styleFile not found" unless ( -e $styleFile );
|
||||
return $xslt->parse_stylesheet( $self->parser->parse_file($styleFile) );
|
||||
}
|
||||
);
|
||||
|
||||
# Underlying notifications storage object (File, DBI, LDAP,...)
|
||||
has notifObject => ( is => 'rw' );
|
||||
|
||||
# INTERFACE
|
||||
|
||||
# Declare additional process steps
|
||||
|
@ -59,6 +27,10 @@ sub afterDatas { 'checkNotifDuringAuth' }
|
|||
# For now, notifications are done only during authentication process
|
||||
#sub forAuthUser { 'checkNotifForAuthUser' }
|
||||
|
||||
# PROPERTIES
|
||||
|
||||
has module => ( is => 'rw' );
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
sub init {
|
||||
|
@ -83,6 +55,7 @@ sub init {
|
|||
"Unable to load Lemonldap::NG::Common::Notifications::$type: $@");
|
||||
return 0;
|
||||
}
|
||||
$type->import( $self->conf->{oldNotifFormat} ? 'XML' : 'JSON' );
|
||||
|
||||
# TODO: use conf database?
|
||||
|
||||
|
@ -91,7 +64,16 @@ sub init {
|
|||
p => $self->p,
|
||||
conf => $self->p->conf
|
||||
};
|
||||
unless ( eval { $self->notifObject( $type->new($prms) ); } ) {
|
||||
|
||||
if ( $self->conf->{oldNotifFormat} ) {
|
||||
$self->module( $self->p->loadModule('::Lib::Notifications::XML') )
|
||||
or return 0;
|
||||
}
|
||||
else {
|
||||
$self->module( $self->p->loadModule('::Lib::Notifications::JSON') )
|
||||
or return 0;
|
||||
}
|
||||
unless ( eval { $self->module->notifObject( $type->new($prms) ); } ) {
|
||||
$self->error($@);
|
||||
return 0;
|
||||
}
|
||||
|
@ -114,7 +96,9 @@ sub init {
|
|||
|
||||
sub checkNotifDuringAuth {
|
||||
my ( $self, $req ) = @_;
|
||||
if ( $req->{datas}->{notification} = $self->checkForNotifications($req) ) {
|
||||
if ( $req->{datas}->{notification} =
|
||||
$self->module->checkForNotifications($req) )
|
||||
{
|
||||
$self->rebuildCookies($req);
|
||||
|
||||
# Restore and cipher cookies
|
||||
|
@ -125,208 +109,9 @@ sub checkNotifDuringAuth {
|
|||
}
|
||||
}
|
||||
|
||||
# Search for notifications and if any, returns HTML fragment.
|
||||
# TODO: replace this by JSON+Ajax
|
||||
sub checkForNotifications {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
# Look for pending notifications in database
|
||||
my $uid = $req->sessionInfo->{ $self->notifObject->notifField };
|
||||
my ( $notifs, $forUser ) = $self->notifObject->getNotifications($uid);
|
||||
my $form;
|
||||
return 0 unless ($notifs);
|
||||
|
||||
# Transform notifications
|
||||
my $i = 0; #Files count
|
||||
foreach my $file ( values %$notifs ) {
|
||||
eval {
|
||||
my $xml = $self->parser->parse_string($file);
|
||||
my $j = 0; #Notifications count
|
||||
foreach my $notif (
|
||||
$xml->documentElement->getElementsByTagName('notification') )
|
||||
{
|
||||
|
||||
# Get the reference
|
||||
my $reference = $notif->getAttribute('reference');
|
||||
|
||||
$self->lmLog( "Get reference $reference", 'debug' );
|
||||
|
||||
# Check it in session
|
||||
if ( exists $req->{sessionInfo}->{"notification_$reference"} ) {
|
||||
|
||||
# The notification was already accepted
|
||||
$self->lmLog(
|
||||
"Notification $reference was already accepted",
|
||||
'debug' );
|
||||
|
||||
# Remove it from XML
|
||||
$notif->unbindNode();
|
||||
next;
|
||||
}
|
||||
|
||||
# Check condition if any
|
||||
my $condition = $notif->getAttribute('condition');
|
||||
|
||||
if ($condition) {
|
||||
|
||||
$self->lmLog( "Get condition $condition", 'debug' );
|
||||
|
||||
unless ( $self->p->HANDLER->safe->reval($condition) ) {
|
||||
$self->lmLog( "Notification condition not accepted",
|
||||
'debug' );
|
||||
|
||||
# Remove it from XML
|
||||
$notif->unbindNode();
|
||||
next;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$j++;
|
||||
}
|
||||
|
||||
# Go to next file if no notification found
|
||||
next unless $j;
|
||||
$i++;
|
||||
|
||||
# Transform XML into HTML
|
||||
my $results = $self->stylesheet->transform( $xml, start => $i );
|
||||
$form .= $self->stylesheet->output_string($results);
|
||||
};
|
||||
if ($@) {
|
||||
$self->lmLog(
|
||||
"Bad XML file: a notification for $uid was not done ($@)",
|
||||
'warn' );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Stop here if nothing to display
|
||||
return 0 unless $i;
|
||||
|
||||
# Returns HTML fragment
|
||||
$req->id( $self->p->HANDLER->tsv->{cipher}->encrypt( $req->id ) );
|
||||
return $form;
|
||||
}
|
||||
|
||||
sub getNotifBack {
|
||||
my ( $self, $req, $name ) = @_;
|
||||
|
||||
# Look if all notifications have been accepted. If not, redirects to
|
||||
# portal
|
||||
|
||||
# Search for Lemonldap::NG cookie (ciphered)
|
||||
my $id;
|
||||
unless ( $id = $req->cookies->{ $self->{conf}->{cookieName} } ) {
|
||||
return $self->p->sendError( $req, 'No cookie found', 401 );
|
||||
}
|
||||
$id = $self->p->HANDLER->tsv->{cipher}->decrypt($id)
|
||||
or return $self->sendError( $req, 'Unable to decrypt', 500 );
|
||||
|
||||
# Verify that session exists
|
||||
$req->userData( $self->p->HANDLER->retrieveSession($id) )
|
||||
or return $self->sendError( $req, 'Unknown session', 401 );
|
||||
|
||||
# Restore datas
|
||||
$self->p->importHandlerDatas($req);
|
||||
my $uid = $req->sessionInfo->{ $self->notifObject->notifField };
|
||||
|
||||
my ( $notifs, $forUser ) = $self->notifObject->getNotifications($uid);
|
||||
if ($notifs) {
|
||||
|
||||
# Get accepted notifications
|
||||
my ( $refs, $checks ) = ( {}, {} );
|
||||
my $prms = $req->parameters;
|
||||
foreach ( keys %$prms ) {
|
||||
my $v = $prms->{$_};
|
||||
if (s/^reference//) {
|
||||
$refs->{$v} = $_;
|
||||
}
|
||||
elsif ( s/^check// and /^(\d+x\d+)x(\d+)$/ and $v eq 'accepted' ) {
|
||||
push @{ $checks->{$1} }, $2;
|
||||
}
|
||||
}
|
||||
|
||||
my $result = 1;
|
||||
foreach my $fileName ( keys %$notifs ) {
|
||||
my $file = $notifs->{$fileName};
|
||||
my $fileResult = 1;
|
||||
my $xml = $self->parser->parse_string($file);
|
||||
|
||||
# Get pending notifications and verify that they have been accepted
|
||||
foreach my $notif (
|
||||
$xml->documentElement->getElementsByTagName('notification') )
|
||||
{
|
||||
my $reference = $notif->getAttribute('reference');
|
||||
|
||||
# Check if this pending notification has been seen
|
||||
if ( my $refId = $refs->{$reference} ) {
|
||||
|
||||
# Verity that checkboxes have been checked
|
||||
my @toCheck = $notif->getElementsByTagName('check');
|
||||
if ( my $toCheckCount = @toCheck ) {
|
||||
unless ($checks->{$refId}
|
||||
and $toCheckCount == @{ $checks->{$refId} } )
|
||||
{
|
||||
$self->p->userNotice(
|
||||
"$uid has not accepted notification $reference"
|
||||
);
|
||||
$result = $fileResult = 0;
|
||||
next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Current pending notification has not been found in
|
||||
# request
|
||||
$result = $fileResult = 0;
|
||||
$self->lmLog(
|
||||
'Current pending notification has not been found',
|
||||
'debug' );
|
||||
next;
|
||||
}
|
||||
|
||||
# Register acceptation
|
||||
$self->p->userNotice(
|
||||
"$uid has accepted notification $reference");
|
||||
$self->p->updatePersistentSession( $req,
|
||||
{ "notification_$reference" => time() } );
|
||||
$self->lmLog(
|
||||
"Notification $reference registered in persistent session",
|
||||
'debug'
|
||||
);
|
||||
}
|
||||
|
||||
# Notifications accepted for this file, delete it unless it's a wildcard
|
||||
if ( $fileResult and exists $forUser->{$fileName} ) {
|
||||
$self->lmLog( "Notification file deleted", 'debug' );
|
||||
$self->notifObject->delete($fileName);
|
||||
}
|
||||
}
|
||||
unless ($result) {
|
||||
|
||||
# One pending notification has been found and not accepted,
|
||||
# restart process to display pending notifications
|
||||
# TODO: is it a good idea to launch all 'afterDatas' subs ?
|
||||
$self->lmLog(
|
||||
'Pending notification has been found and not accepted',
|
||||
'debug' );
|
||||
return $self->p->do( $req, $self->p->afterDatas );
|
||||
}
|
||||
|
||||
# All pending notifications have been accepted, restore cookies and
|
||||
# launch 'controlUrl' to restore "urldc" using do()
|
||||
$self->lmLog( 'All pending notifications have been accepted', 'debug' );
|
||||
$self->rebuildCookies($req);
|
||||
$self->p->do( $req, ['controlUrl'] );
|
||||
}
|
||||
else {
|
||||
# No notifications checked here, this entry point must not be called.
|
||||
# Redirecting to portal
|
||||
$self->lmLog( 'No notifications checked', 'debug' );
|
||||
$req->mustRedirect(1);
|
||||
$self->p->do( $req, [] );
|
||||
}
|
||||
my $self = shift;
|
||||
return $self->module->getNotifBack(@_);
|
||||
}
|
||||
|
||||
sub rebuildCookies {
|
||||
|
|
|
@ -39,6 +39,7 @@ qq{INSERT INTO notifications VALUES ('dwho','testref','2016-05-30 00:00:00','<?x
|
|||
notificationStorageOptions => {
|
||||
dbiChain => "dbi:SQLite:dbname=$file",
|
||||
},
|
||||
oldNotifFormat => 1,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@ my $client = LLNG::Manager::Test->new(
|
|||
notificationStorageOptions => {
|
||||
dirName => 't'
|
||||
},
|
||||
oldNotifFormat => 1,
|
||||
}
|
||||
}
|
||||
);
|
Loading…
Reference in New Issue
Block a user