* Use HTML templates to send fancy reset password mail, with translations
* Send the new password by mail instead of diplaying it n the web page
* Remove the need to configure : the value is now set with help of {DOCUMENT_ROOT}
This commit is contained in:
Clément Oudot 2010-01-22 11:25:37 +00:00
parent f6c250207c
commit 3222021897
17 changed files with 148 additions and 55 deletions

View File

@ -310,8 +310,6 @@ install_portal_site: install_conf_dir
@cp -pR --remove-destination ${SRCPORTALDIR}/example/error.pl ${RPORTALDIR} @cp -pR --remove-destination ${SRCPORTALDIR}/example/error.pl ${RPORTALDIR}
@cp -pR --remove-destination ${SRCPORTALDIR}/example/mail.pl ${RPORTALDIR} @cp -pR --remove-destination ${SRCPORTALDIR}/example/mail.pl ${RPORTALDIR}
@cp -pR --remove-destination ${SRCPORTALDIR}/example/apps ${RPORTALDIR} @cp -pR --remove-destination ${SRCPORTALDIR}/example/apps ${RPORTALDIR}
@$(PERL) -i -pe 's#__SKINDIR__#$(PORTALDIR)/skins#; \
s#__APPSXMLFILE__#$(CONFDIR)/apps-list.xml#;' ${RPORTALDIR}/index.pl ${RPORTALDIR}/error.pl ${RPORTALDIR}/mail.pl
@cp -pR --remove-destination ${SRCPORTALDIR}/example/skins/* $(RPORTALSKINSDIR) @cp -pR --remove-destination ${SRCPORTALDIR}/example/skins/* $(RPORTALSKINSDIR)
@if [ "$(PORTALDIR)/skins/" != "$(PORTALSKINSDIR)/" ]; then \ @if [ "$(PORTALDIR)/skins/" != "$(PORTALSKINSDIR)/" ]; then \
for skin in $$(ls lemonldap-ng-portal/example/skins/); do \ for skin in $$(ls lemonldap-ng-portal/example/skins/); do \
@ -546,9 +544,9 @@ debian-diff:
@for i in $(PORTALSKINS); do \ @for i in $(PORTALSKINS); do \
$(DIFF) -x 'jquery*' lemonldap-ng-portal/example/skins/$$i /usr/share/lemonldap-ng/portal-skins/$$i; \ $(DIFF) -x 'jquery*' lemonldap-ng-portal/example/skins/$$i /usr/share/lemonldap-ng/portal-skins/$$i; \
done ||true done ||true
@$(DIFF) -I '$$skin_dir' -I '$$appsxmlfile' lemonldap-ng-portal/example/index_skin.pl /var/lib/lemonldap-ng/portal/index.pl ||true @$(DIFF) lemonldap-ng-portal/example/index_skin.pl /var/lib/lemonldap-ng/portal/index.pl ||true
@$(DIFF) -I '$$skin_dir' lemonldap-ng-portal/example/error.pl /var/lib/lemonldap-ng/portal/error.pl ||true @$(DIFF) lemonldap-ng-portal/example/error.pl /var/lib/lemonldap-ng/portal/error.pl ||true
@$(DIFF) -I '$$skin_dir' lemonldap-ng-portal/example/mail.pl /var/lib/lemonldap-ng/portal/mail.pl ||true @$(DIFF) lemonldap-ng-portal/example/mail.pl /var/lib/lemonldap-ng/portal/mail.pl ||true
@# Handler @# Handler
@$(DIFF) lemonldap-ng-handler/lib/Lemonldap/NG/Handler /usr/share/perl5/Lemonldap/NG/Handler ||true @$(DIFF) lemonldap-ng-handler/lib/Lemonldap/NG/Handler /usr/share/perl5/Lemonldap/NG/Handler ||true
@# Common @# Common
@ -570,9 +568,9 @@ default-diff:
@$(DIFF) lemonldap-ng-portal/example/scripts/purgeCentralCache $(LMPREFIX)/bin/purgeCentralCache ||true @$(DIFF) lemonldap-ng-portal/example/scripts/purgeCentralCache $(LMPREFIX)/bin/purgeCentralCache ||true
@$(DIFF) lemonldap-ng-portal/example/scripts/buildPortalWSDL $(LMPREFIX)/bin/buildPortalWSDL ||true @$(DIFF) lemonldap-ng-portal/example/scripts/buildPortalWSDL $(LMPREFIX)/bin/buildPortalWSDL ||true
@$(DIFF) lemonldap-ng-portal/example/skins $(LMPREFIX)/htdocs/portal/skins ||true @$(DIFF) lemonldap-ng-portal/example/skins $(LMPREFIX)/htdocs/portal/skins ||true
@$(DIFF) -I '$$skin_dir' -I '$$appsxmlfile' lemonldap-ng-portal/example/index_skin.pl $(LMPREFIX)/htdocs/portal/index.pl ||true @$(DIFF) lemonldap-ng-portal/example/index_skin.pl $(LMPREFIX)/htdocs/portal/index.pl ||true
@$(DIFF) -I '$$skin_dir' lemonldap-ng-portal/example/error.pl $(LMPREFIX)/htdocs/portal/error.pl ||true @$(DIFF) lemonldap-ng-portal/example/error.pl $(LMPREFIX)/htdocs/portal/error.pl ||true
@$(DIFF) -I '$$skin_dir' lemonldap-ng-portal/example/mail.pl $(LMPREFIX)/htdocs/portal/mail.pl ||true @$(DIFF) lemonldap-ng-portal/example/mail.pl $(LMPREFIX)/htdocs/portal/mail.pl ||true
@# Handler @# Handler
@$(DIFF) lemonldap-ng-handler/lib/Lemonldap/NG/Handler /usr/local/share/perl/5.10.0/Lemonldap/NG/Handler ||true @$(DIFF) lemonldap-ng-handler/lib/Lemonldap/NG/Handler /usr/local/share/perl/5.10.0/Lemonldap/NG/Handler ||true
@$(DIFF) lemonldap-ng-handler/example/MyHandler.pm $(LMPREFIX)/handler/MyHandler.pm ||true @$(DIFF) lemonldap-ng-handler/example/MyHandler.pm $(LMPREFIX)/handler/MyHandler.pm ||true

View File

@ -1,8 +1,6 @@
#!/usr/bin/perl #!/usr/bin/perl
use HTML::Template; use HTML::Template;
my $skin_dir = "__SKINDIR__";
my $portal = Lemonldap::NG::Portal::SharedConf->new( my $portal = Lemonldap::NG::Portal::SharedConf->new(
# PORTAL CUSTOMIZATION # PORTAL CUSTOMIZATION
@ -11,6 +9,7 @@ my $portal = Lemonldap::NG::Portal::SharedConf->new(
); );
my $skin = $portal->{portalSkin}; my $skin = $portal->{portalSkin};
my $skin_dir = $ENV{DOCUMENT_ROOT} . "skins";
my $portal_url = $portal->{portal}; my $portal_url = $portal->{portal};
my $logout_url = "$portal_url?logout=1"; my $logout_url = "$portal_url?logout=1";

View File

@ -4,11 +4,6 @@ use Lemonldap::NG::Portal::SharedConf;
use HTML::Template; use HTML::Template;
use strict; use strict;
# Menu configuration
my $skin_dir = "__SKINDIR__";
my $appsxmlfile = "__APPSXMLFILE__";
my $appsimgpath = "apps/";
my $portal = Lemonldap::NG::Portal::SharedConf->new( my $portal = Lemonldap::NG::Portal::SharedConf->new(
{ {
@ -149,7 +144,7 @@ my $portal = Lemonldap::NG::Portal::SharedConf->new(
# Get skin value # Get skin value
my $skin = $portal->{portalSkin}; my $skin = $portal->{portalSkin};
my $skin_dir = $ENV{DOCUMENT_ROOT} . "skins";
my ( $skinfile, %templateParams ); my ( $skinfile, %templateParams );
#################### ####################
@ -180,10 +175,6 @@ if ( $portal->process() ) {
my $menu = Lemonldap::NG::Portal::Menu->new( my $menu = Lemonldap::NG::Portal::Menu->new(
{ {
portalObject => $portal, portalObject => $portal,
apps => {
xmlfile => "$appsxmlfile",
imgpath => "$appsimgpath",
},
modules => { modules => {
appslist => $portal->{portalDisplayAppslist}, appslist => $portal->{portalDisplayAppslist},
password => $portal->{portalDisplayChangePassword}, password => $portal->{portalDisplayChangePassword},

View File

@ -4,12 +4,11 @@ use Lemonldap::NG::Portal::MailReset;
use HTML::Template; use HTML::Template;
use strict; use strict;
my $skin_dir = "__SKINDIR__";
# Load portal module # Load portal module
my $portal = Lemonldap::NG::Portal::MailReset->new(); my $portal = Lemonldap::NG::Portal::MailReset->new();
my $skin = $portal->{portalSkin}; my $skin = $portal->{portalSkin};
my $skin_dir = $ENV{DOCUMENT_ROOT} . "skins";
my $portal_url = $portal->{portal}; my $portal_url = $portal->{portal};
# Process # Process
@ -33,10 +32,6 @@ $template->param( DISPLAY_FORM => 1 )
if ( $portal->{error} == PE_MAILFORMEMPTY if ( $portal->{error} == PE_MAILFORMEMPTY
or ( $portal->{error} == PE_BADCREDENTIALS and !$portal->{mail_token} ) ); or ( $portal->{error} == PE_BADCREDENTIALS and !$portal->{mail_token} ) );
# Display password if change is OK
$template->param( NEW_PASSWORD => $portal->{reset_password} )
if ( $portal->{error} == PE_PASSWORD_OK );
print $portal->header('text/html; charset=utf8'); print $portal->header('text/html; charset=utf8');
print $template->output; print $template->output;

View File

@ -0,0 +1,11 @@
<TMPL_INCLUDE NAME="mail_header.tpl">
<p>
<lang en="Hello" fr="Bonjour" />,<br />
<br />
<a href="$url" style="text-decoration:none;color:orange;">
<lang en="Click here to reset your password" fr="Cliquez ici pour r&eacute;initialiser votre mot de passe" />
</a>
</p>
<TMPL_INCLUDE NAME="mail_footer.tpl">

View File

@ -0,0 +1,11 @@
</div>
<div id="footer" style="font-size:9pt;">
<p>
<lang en="This mail was sent automatically" fr="Ceci est un message automatique" /><br />
<lang en="The reset password request was issued from IP" fr="La demande de changement de mot de passe provient de l'IP" />
$ipAddr
</p>
</div>
</div>

View File

@ -0,0 +1,17 @@
<div id="page" style="background:#000;font-family:sans-serif;font-size:12pt;color:#fff;padding:5px 20px;">
<div id="header">
<table>
<tr>
<td style="width:30px;height:30px;background:orange;">&nbsp;</td>
<td>&nbsp;</td>
<td rowspan=2 style="font-size:20pt;padding:5px 20px;color:#fff">LemonLDAP::NG</td>
</tr>
</tr>
<td>&nbsp;</td>
<td style="width:30px;height:30px;background:orange;">&nbsp;</td>
</tr>
</table>
</div>
<div id="content" style="color:#000;background:#eee;padding:5px 10px;margin:10px 0;">

View File

@ -0,0 +1,9 @@
<TMPL_INCLUDE NAME="mail_header.tpl">
<p>
<lang en="Hello" fr="Bonjour" />,<br />
<br />
<lang en="Your new password is" fr="Votre nouveau mot de passe est" /> $password
</p>
<TMPL_INCLUDE NAME="mail_footer.tpl">

View File

@ -27,11 +27,6 @@
</TMPL_IF> </TMPL_IF>
<div class="link"> <div class="link">
<TMPL_IF NAME="NEW_PASSWORD">
<h3><lang en="Your new password is" fr="Votre nouveau mot de passe est"/> <TMPL_VAR NAME="NEW_PASSWORD"></h3>
</TMPL_IF>
<a href="<TMPL_VAR NAME="PORTAL_URL">"> <a href="<TMPL_VAR NAME="PORTAL_URL">">
<lang en="Go back to portal" fr="Retourner au portail" /> <lang en="Go back to portal" fr="Retourner au portail" />
</a> </a>

View File

@ -20,7 +20,7 @@ margin:20px;
} }
a img,:link img,:visited img { a img,:link img,:visited img {
border:none border:none;
} }
a, a:link, a:visited { a, a:link, a:visited {

View File

@ -12,6 +12,7 @@ our $VERSION = '0.1';
use Lemonldap::NG::Portal::Simple qw(:all); use Lemonldap::NG::Portal::Simple qw(:all);
use base qw(Lemonldap::NG::Portal::SharedConf Exporter); use base qw(Lemonldap::NG::Portal::SharedConf Exporter);
use HTML::Template;
*EXPORT_OK = *Lemonldap::NG::Portal::Simple::EXPORT_OK; *EXPORT_OK = *Lemonldap::NG::Portal::Simple::EXPORT_OK;
*EXPORT_TAGS = *Lemonldap::NG::Portal::Simple::EXPORT_TAGS; *EXPORT_TAGS = *Lemonldap::NG::Portal::Simple::EXPORT_TAGS;
@ -24,6 +25,7 @@ use base qw(Lemonldap::NG::Portal::SharedConf Exporter);
# - extractMailInfo # - extractMailInfo
# - storeMailSession # - storeMailSession
# - sendConfirmationMail # - sendConfirmationMail
# - sendPasswordMail
# - portal core module: # - portal core module:
# - setMacros # - setMacros
# - setLocalGroups # - setLocalGroups
@ -44,7 +46,7 @@ sub process {
$self->{error} = $self->_subProcess( $self->{error} = $self->_subProcess(
qw(smtpInit userDBInit passwordDBInit extractMailInfo qw(smtpInit userDBInit passwordDBInit extractMailInfo
getUser setSessionInfo setMacros setLocalGroups setGroups getUser setSessionInfo setMacros setLocalGroups setGroups
storeMailSession sendConfirmationMail resetPassword) storeMailSession sendConfirmationMail resetPassword sendPasswordMail)
); );
return ( return (
( (
@ -139,16 +141,71 @@ sub sendConfirmationMail {
# Build confirmation url # Build confirmation url
my $url = $self->{mailUrl} . "?mail_token=" . $self->{id}; my $url = $self->{mailUrl} . "?mail_token=" . $self->{id};
# Replace variables in mail body # Build mail content
$self->{mailBody} =~ s/\$url/$url/g; my $subject = $self->{mailConfirmSubject};
$self->{mailBody} =~ s/\$(\w+)/$self->{sessionInfo}->{$1}/g; my $body;
my $html;
if ( $self->{mailConfirmBody} ) {
# We use a specific text message, no html
$body = $self->{mailConfirmBody};
}
else {
# Use HTML template
my $template = HTML::Template->new(
filename => $ENV{DOCUMENT_ROOT} . "skins/common/mail_confirm.tpl",
filter => sub { $self->translate_template(@_) }
);
$body = $template->output();
$html = 1;
}
# Replace variables in body
$body =~ s/\$url/$url/g;
$body =~ s/\$(\w+)/$self->{sessionInfo}->{$1}/g;
# Send mail # Send mail
return PE_MAILERROR unless $self->send_mail( $self->{mail} ); return PE_MAILERROR
unless $self->send_mail( $self->{mail}, $subject, $body, $html );
PE_MAILOK; PE_MAILOK;
} }
sub sendPasswordMail {
my ($self) = @_;
# Build mail content
my $subject = $self->{mailSubject};
my $body;
my $html;
if ( $self->{mailBody} ) {
# We use a specific text message, no html
$body = $self->{mailBody};
}
else {
# Use HTML template
my $template = HTML::Template->new(
filename => $ENV{DOCUMENT_ROOT} . "skins/common/mail_password.tpl",
filter => sub { $self->translate_template(@_) }
);
$body = $template->output();
$html = 1;
}
# Replace variables in body
my $password = $self->{reset_password};
$body =~ s/\$password/$password/g;
$body =~ s/\$(\w+)/$self->{sessionInfo}->{$1}/g;
# Send mail
return PE_MAILERROR
unless $self->send_mail( $self->{mail}, $subject, $body, $html );
PE_MAILOK;
}
1; 1;
__END__ __END__

View File

@ -78,7 +78,6 @@ sub new {
#&Lemonldap::NG::Portal::Simple::getSessionInfo( $self->{portalObject} ); #&Lemonldap::NG::Portal::Simple::getSessionInfo( $self->{portalObject} );
# Default values # Default values
$self->{apps}->{xmlfile} ||= 'apps-list.xml';
$self->{apps}->{imgpath} ||= 'apps/'; $self->{apps}->{imgpath} ||= 'apps/';
$self->{modules}->{appslist} = 0 $self->{modules}->{appslist} = 0
unless defined $self->{modules}->{appslist}; unless defined $self->{modules}->{appslist};
@ -463,7 +462,7 @@ sub _isCategoryEmpty {
} }
# Test this category # Test this category
if ( $apphash->{type} eq "category" ) { if ( $apphash->{type} and $apphash->{type} eq "category" ) {
# Temporary store 'options' # Temporary store 'options'
my $tmp_options = $apphash->{options}; my $tmp_options = $apphash->{options};

View File

@ -108,10 +108,10 @@ sub resetPassword {
return PE_ERROR unless $result; return PE_ERROR unless $result;
# Store password to display it to the user # Store password to forward it to the user
$self->{reset_password} = $password; $self->{reset_password} = $password;
PE_PASSWORD_OK; PE_OK;
} }
1; 1;

View File

@ -106,10 +106,10 @@ sub resetPassword {
$self->lmLog( "pwdReset set to TRUE", 'debug' ); $self->lmLog( "pwdReset set to TRUE", 'debug' );
} }
# Store password to display it to the user # Store password to forward it to the user
$self->{reset_password} = $password; $self->{reset_password} = $password;
PE_PASSWORD_OK; PE_OK;
} }
1; 1;

View File

@ -270,6 +270,8 @@ sub getConf {
# Set default values. # Set default values.
sub setDefaultValues { sub setDefaultValues {
my $self = shift; my $self = shift;
$self->{portal} ||=
"http" . ( $ENV{HTTPS} ? 's' : '' ) . '://' . $self->server_name();
$self->{whatToTrace} ||= 'uid'; $self->{whatToTrace} ||= 'uid';
$self->{whatToTrace} =~ s/^\$//; $self->{whatToTrace} =~ s/^\$//;
$self->{httpOnly} = 1 unless ( defined( $self->{httpOnly} ) ); $self->{httpOnly} = 1 unless ( defined( $self->{httpOnly} ) );
@ -296,8 +298,9 @@ sub setDefaultValues {
$self->{mailLDAPFilter} ||= '(&(mail=$mail)(objectClass=inetOrgPerson))'; $self->{mailLDAPFilter} ||= '(&(mail=$mail)(objectClass=inetOrgPerson))';
$self->{randomPasswordRegexp} ||= '[A-Z]{3}[a-z]{5}.\d{2}'; $self->{randomPasswordRegexp} ||= '[A-Z]{3}[a-z]{5}.\d{2}';
$self->{mailFrom} ||= "noreply@" . $self->{domain}; $self->{mailFrom} ||= "noreply@" . $self->{domain};
$self->{mailSubject} ||= "[LemonLDAP::NG] Reset password confirmation"; $self->{mailSubject} ||= "[LemonLDAP::NG] Your new password";
$self->{mailBody} ||= 'Click here to reset your password: $url'; $self->{mailConfirmSubject} ||=
"[LemonLDAP::NG] Password reset confirmation";
$self->{mailSessionKey} ||= 'mail'; $self->{mailSessionKey} ||= 'mail';
$self->{mailUrl} ||= $self->{portal} . "/mail.pl"; $self->{mailUrl} ||= $self->{portal} . "/mail.pl";
$self->{issuerDB} ||= 'Null'; $self->{issuerDB} ||= 'Null';

View File

@ -25,24 +25,32 @@ sub gen_password {
## @method int send_mail() ## @method int send_mail()
# Send mail # Send mail
# @param mail mail # @param mail recipient address
# @param subject mail subject
# @param body mail body
# @param html optional set content type to HTML
# @return boolean result # @return boolean result
sub send_mail { sub send_mail {
my $self = shift; my $self = shift;
my $mail = shift; my $mail = shift;
my $subject = shift;
my $body = shift;
my $html = shift;
$self->lmLog( "SMTP From " . $self->{mailFrom}, 'debug' ); $self->lmLog( "SMTP From " . $self->{mailFrom}, 'debug' );
$self->lmLog( "SMTP To " . $mail, 'debug' ); $self->lmLog( "SMTP To " . $mail, 'debug' );
$self->lmLog( "SMTP Subject " . $self->{mailSubject}, 'debug' ); $self->lmLog( "SMTP Subject " . $subject, 'debug' );
$self->lmLog( "SMTP Body " . $self->{mailBody}, 'debug' ); $self->lmLog( "SMTP Body " . $body, 'debug' );
$self->lmLog( "SMTP HTML flag " . ($html?"on":"off"), 'debug' );
eval { eval {
my $message = MIME::Lite->new( my $message = MIME::Lite->new(
From => $self->{mailFrom}, From => $self->{mailFrom},
To => $mail, To => $mail,
Subject => $self->{mailSubject}, Subject => $subject,
Type => "TEXT", Type => "TEXT",
Data => $self->{mailBody}, Data => $body,
); );
$message->attr("content-type" => "text/html; charset=utf-8") if $html;
$self->{SMTPServer} $self->{SMTPServer}
? $message->send( "smtp", $self->{SMTPServer} ) ? $message->send( "smtp", $self->{SMTPServer} )
: $message->send(); : $message->send();

View File

@ -161,8 +161,8 @@ sub error_fr {
"Confirmation demandée", "Confirmation demandée",
"Veuillez saisir votre adresse mail", "Veuillez saisir votre adresse mail",
"La clé de confirmation est invalide ou trop ancienne", "La clé de confirmation est invalide ou trop ancienne",
"L'envoi du mail de confirmation a échoué", "L'envoi du mail a échoué",
"Un mail de confirmation vient d'être envoyé", "Un mail vous a été envoyé",
]; ];
} }
@ -217,7 +217,7 @@ sub error_en {
'Please provide your mail address', 'Please provide your mail address',
'Confirmation key is invalid or too old', 'Confirmation key is invalid or too old',
'An error occurs when sending mail', 'An error occurs when sending mail',
'Confirmation mail has been sent', 'A mail has been sent',
]; ];
} }
@ -272,8 +272,8 @@ sub error_ro {
'Confirmare necesare', 'Confirmare necesare',
'Vă rugăm să introduceţi adresa dvs. de e-mail', 'Vă rugăm să introduceţi adresa dvs. de e-mail',
'Cheie de confirmare este invalid sau prea veche', 'Cheie de confirmare este invalid sau prea veche',
'Trimiterea mail de confirmare nu a reuşit', 'Trimiterea mail nu a reuşit',
'Un e-mail de confirmare a fost trimis', 'Un e-mail a fost trimis',
]; ];
} }