Compare commits

...

7 commits

Author SHA1 Message Date
Benjamin Renard
62759330a8
LSaddon::mail: remove useless label 2024-02-22 18:52:11 +01:00
Benjamin Renard
5e9773a015
LSaddon::mail: improve CSS of templates editor view 2024-02-22 18:10:28 +01:00
Benjamin Renard
557db5d456
Fix Gitlab CI tests 2024-02-22 17:03:29 +01:00
Benjamin Renard
15f67ef00d
Improve docker image to make it smaller 2024-02-22 16:57:18 +01:00
Benjamin Renard
753f47fa97
Move mail template in LSaddon::mail and add editor view and docs 2024-02-22 16:15:00 +01:00
Benjamin Renard
89c363bd80
Fix handling mime type on serving libs's static files 2024-02-22 15:10:33 +01:00
Benjamin Renard
e59ab4a94c
Add common LStabs CSS classes to handle tabs content
Based on stuff provided by LSaccessRightsMatrixView.
2024-02-22 15:09:20 +01:00
26 changed files with 1187 additions and 542 deletions

View file

@ -7,6 +7,7 @@ require '/usr/share/php/phpseclib/autoload.php';
require 'CAS.php'; require 'CAS.php';
require 'Mail.php'; require 'Mail.php';
require 'Mail/mime.php'; require 'Mail/mime.php';
require 'Html2Text.php';
spl_autoload_register(array('LSsession', 'loadLSclass')); spl_autoload_register(array('LSsession', 'loadLSclass'));
LSsession :: initialize(); LSsession :: initialize();

2
debian/control vendored
View file

@ -7,7 +7,7 @@ Maintainer: Benjamin Renard <brenard@easter-eggs.com>
Package: ldapsaisie Package: ldapsaisie
Architecture: all Architecture: all
Depends: apache2 | httpd, php-ldap | php5-ldap, php-fpm | libapache2-mod-php5 | libapache2-mod-php | php5-cli | php-cli, smarty | smarty3, php-net-ldap2, php-console-table Depends: apache2 | httpd, php-ldap | php5-ldap, php-fpm | libapache2-mod-php5 | libapache2-mod-php | php5-cli | php-cli, smarty | smarty3, php-net-ldap2, php-console-table
Recommends: php-mbstring, php-phpseclib, php-unidecode, php-zxcvbn, php-ftp, php-mail, php-mail-mime Recommends: php-mbstring, php-phpseclib, php-unidecode, php-zxcvbn, php-ftp, php-mail, php-mail-mime, php-html2text
Description: web based interface for managing LDAP servers content Description: web based interface for managing LDAP servers content
LdapSaisie is a Web application developed to manage LDAP directory. LdapSaisie is a Web application developed to manage LDAP directory.
It has been written in PHP / JavaScript and is published under the It has been written in PHP / JavaScript and is published under the

View file

@ -1,8 +1,35 @@
# LSaddon_mail # LSaddon_mail
Cet [LSaddon](index.md#configuration-des-lsaddons) est utilisé pour gérer l'envoie de mail. Il Cet [LSaddon](index.md#configuration-des-lsaddons) est utilisé pour gérer l'envoi de courriels. Il
utilise pour cela les librairies [PEAR](http://pear.php.net/) *Mail* et *Mail_Mime* qui doivent être utilise pour cela les librairies [PEAR](http://pear.php.net/) *Mail* et *Mail_Mime* qui doivent être
installés. Cet [LSaddon](index.md#configuration-des-lsaddons) doit être configuré en éditant son installés.
Cet [LSaddon](index.md#configuration-des-lsaddons) offre aussi la possibilité d'envoyer des
courriels dont le contenu est construit à partir de modèles. Ces modèles sont enregistrés dans des
fichiers textes stockés (voir `$GLOBALS['MAIL_TEMPLATES_DIRECTORIES']`). Pour chaque modèle, vous
devez fournir trois fichiers portant le même nom mais avec des extensions différentes :
- `template.subject` : le sujet du courriel. Note : seule la première ligne du fichier est utilisé
(et passée dans la fonction `trim()`)
- `template.html` : le contenu HTML du courriel
- `template.txt`: le contenu texte du courriel
Ces trois fichiers sont utilisés en tant que modèle [Smarty](http://www.smarty.net/) et seront
construit en utilisant les variables fournies dans le contexte d'envoi des courriels. À noter que le
moteur Smarty utilisé pour la génération du contenu de ces courriels n'est pas le même que celui
utilisé par LdapSaisie pour l'affichage des pages.
Par ailleurs, cet [LSaddon](index.md#configuration-des-lsaddons) fourni une vue de gestion des
modèles de courriels existants (voir `$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS']` pour la
configuration des accès).
!!! warning
Cette vue n'est pas conçues pour être mise entre toutes les mains. La sécurisation de modèles de
courriels étant très complexe, il est fortement recommandé de n'ouvrir l'accès à cette vue
qu'aux utilisateurs avertis et de confiances.
Cet [LSaddon](index.md#configuration-des-lsaddons) doit être configuré en éditant son
fichier de configuration `config.LSaddons.mail.php`. fichier de configuration `config.LSaddons.mail.php`.
```php ```php
@ -67,10 +94,43 @@ $GLOBALS['MAIL_HEARDERS = array();
// Catch all sent emails // Catch all sent emails
$GLOBALS['MAIL_CATCH_ALL'] = array(); $GLOBALS['MAIL_CATCH_ALL'] = array();
/**
* Email templates
*
* This addon offer ability to send email by using templates. Email templates are stored in
* full-text files in configured directories (see $GLOBALS['MAIL_TEMPLATES_DIRECTORIES']). For each
* template, you have to provide three files with the same name but with different extensions:
* - template.subject: the email subject. Note: only the first line is used (and stripped)
* - template.html: the HTML content of the email
* - template.txt: the text content of the email
* All these files will be used as Smarty templates and will be computed using variables provided
* in the sending context. Note that the Smarty object used to compute the template is not the same
* as the one used by LdapSaisie to display pages.
*
* Futhermore, this addon offer a view to list and edit existing template (see
* $GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] to configured access).
*/
// List of directory paths where as stored mail templates
// Notes:
// - provided path could be absolute or relative. Relative path are relative to the root base
// sources LdapSaisie directory (commonly /usr/share/ldapsaisie or the src directory if you
// installed it from sources). On Debian installation, you can specify 'local/email_templates' to
// refer to /etc/ldapsaisie/local/email_templates directory/
// - Multiple directories could be specified, sorted so that the first ones take priority over
// the last one.
// - To allow users to edit them using the editor view, these directories must be
// writable by PHP process (commonly runed as www-data).
$GLOBALS['MAIL_TEMPLATES_DIRECTORIES'] = array('local/email_templates');
// List of granted LSprofiles to access mail templates editor view
// WARNING: Sanitizing mail templates is hell... EXPOSE THIS VIEW ONLY TO TRUSTED USERS!
$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] = array('admin');
``` ```
Cet [LSaddon](index.md#configuration-des-lsaddons) offre la possibilité d'utilisé la fonction PHP Cet [LSaddon](index.md#configuration-des-lsaddons) offre avant tout la possibilité d'envoyer des
`sendMail()` : courriels en utilisant la fonction PHP `sendMail()` :
``` ```
bool sendMail( bool sendMail(
@ -84,3 +144,16 @@ bool sendMail(
<boolean> $html <boolean> $html
); );
``` ```
Pour l'envoi de courriels en utilisant un modèle, il faut utiliser la fonction PHP
`sendMailFromTemplate()` :
```
bool sendMailFromTemplate(
<string> $tplname,
<string> $to,
<array> $variables,
<array(string)> $headers,
<array> $attachments
);
```

View file

@ -1,37 +1,55 @@
# Update/upgrade ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get upgrade -y # Update/upgrade, configure LdapSaisie APT repo and install dependencies
# Install LdapSaisie APT repository RUN apt-get update && \
RUN apt-get install -y --force-yes wget gnupg lsb-release apt-get upgrade -y && \
RUN wget -O - http://ldapsaisie.org/debian/ldapsaisie.gpg.key | apt-key add - apt-get install -y --force-yes wget gnupg lsb-release && \
RUN echo "deb http://ldapsaisie.org/debian $( lsb_release -c -s ) main" > /etc/apt/sources.list.d/ldapsaisie.list wget -O - http://ldapsaisie.org/debian/ldapsaisie.gpg.key | apt-key add - && \
RUN apt-get update echo "deb http://ldapsaisie.org/debian $( lsb_release -c -s ) main" > /etc/apt/sources.list.d/ldapsaisie.list && \
# Install dependencies apt-get update && \
RUN DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical apt-get install -y git slapd apache2 php-ldap libapache2-mod-php php-cli smarty3 php-net-ldap2 php-net-ftp php-mail php-mail-mime php-console-table ldapvi locales sed bash-completion liquidprompt vim curl jq iproute2 net-tools composer php-cas php-zxcvbn php-phpseclib php-zip apt-get install -y \
# Add fr_FR* locales git \
RUN sed -i 's/^# fr_FR/fr_FR/' /etc/locale.gen slapd \
RUN locale-gen apache2 \
# Clone sources php-ldap \
RUN git clone https://gitlab.easter-eggs.com/ee/ldapsaisie.git /var/www/ldapsaisie libapache2-mod-php \
# Fix www-data permission on temporary directory php-cli \
RUN chown www-data: -R /var/www/ldapsaisie/src/tmp/ smarty3 \
# Configure slapd and load lsexample directory php-net-ldap2 \
RUN killall slapd || echo slapd is not running php-net-ftp \
RUN /var/www/ldapsaisie/lsexample/restore_lsexample -v php-mail \
# Configure and enable ldapsaisie VirtualHost (as default) php-mail-mime \
RUN a2dissite 000-default php-html2text \
COPY apache2.conf /etc/apache2/sites-available/ldapsaisie.conf php-console-table \
RUN a2ensite ldapsaisie ldapvi \
RUN a2enmod rewrite locales \
RUN service apache2 restart sed \
# Install ldapsaisie binary (with its bash-completion config) bash-completion \
RUN ln -s /var/www/ldapsaisie/src/bin/ldapsaisie.php /usr/local/sbin/ldapsaisie liquidprompt \
RUN ln -s /var/www/ldapsaisie/debian/ldapsaisie.bash-completion /usr/share/bash-completion/completions/ldapsaisie vim \
# Install vimrc.local file curl \
COPY vimrc.local /etc/vim/vimrc.local jq \
iproute2 \
net-tools \
composer \
php-cas \
php-zxcvbn \
php-phpseclib \
php-zip && \
apt-get clean && \
rm -fr rm -rf /var/lib/apt/lists/*
COPY rootfs /
# Install LdapSaisie from sources, configure slapd and load lsexample directory
RUN git clone https://gitlab.easter-eggs.com/ee/ldapsaisie.git /var/www/ldapsaisie && \
ln -s /var/www/ldapsaisie/src/bin/ldapsaisie.php /usr/local/sbin/ldapsaisie && \
ln -s /var/www/ldapsaisie/debian/ldapsaisie.bash-completion /usr/share/bash-completion/completions/ldapsaisie && \
chown www-data: -R /var/www/ldapsaisie/src/tmp/ && \
sed -i 's/^# fr_FR/fr_FR/' /etc/locale.gen && \
locale-gen && \
a2dissite 000-default && \
a2ensite ldapsaisie && \
a2enmod rewrite && \
/var/www/ldapsaisie/lsexample/restore_lsexample -v
# Install entrypoint # Install entrypoint
COPY bashrc /root/.bashrc ENTRYPOINT /entrypoint.sh
COPY entrypoint.sh /usr/local/sbin/entrypoint.sh
RUN echo "ldapsaisie-dev" > /etc/hostname
ENTRYPOINT /usr/local/sbin/entrypoint.sh
EXPOSE 80 389 EXPOSE 80 389

12
docker/build-and-push-all.sh Normal file → Executable file
View file

@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
cd $( dirname $0 ) cd $( dirname $0 )
DIST="$1"
# Need to use Dockerfile+ (https://github.com/edrevo/dockerfile-plus) # Need to use Dockerfile+ (https://github.com/edrevo/dockerfile-plus)
export DOCKER_BUILDKIT=1 export DOCKER_BUILDKIT=1
@ -10,9 +11,12 @@ LATEST_DIST=${DISTS[0]}
for dist in ${DISTS[@]} for dist in ${DISTS[@]}
do do
docker build -t brenard/ldapsaisie:$dist -f Dockerfile.$dist . [ -n "$DIST" -a "$DIST" != "$dist" ] && continue
[ $? -eq 0 ] && docker push brenard/ldapsaisie:$dist docker build -t docker.io/brenard/ldapsaisie:$dist -f Dockerfile.$dist .
[ $? -eq 0 ] && docker push docker.io/brenard/ldapsaisie:$dist
done done
docker build -t brenard/ldapsaisie:latest -f Dockerfile.$LATEST_DIST . [ -n "$DIST" -a "$DIST" != "latest" ] && exit
[ $? -eq 0 ] && docker push brenard/ldapsaisie:latest
docker build -t docker.io/brenard/ldapsaisie:latest -f Dockerfile.$LATEST_DIST .
[ $? -eq 0 ] && docker push docker.io/brenard/ldapsaisie:latest

View file

@ -32,6 +32,9 @@ define('PEAR_MAIL','/usr/share/php/Mail.php');
// Pear :: Mail_mime // Pear :: Mail_mime
define('PEAR_MAIL_MIME','/usr/share/php/Mail/mime.php'); define('PEAR_MAIL_MIME','/usr/share/php/Mail/mime.php');
// Html2Text
define('HTML2TEXT','/usr/share/php/Html2Text.php');
/* /*
* Méthode d'envoie : * Méthode d'envoie :
* - mail : envoie avec la méthode PHP mail() * - mail : envoie avec la méthode PHP mail()
@ -82,3 +85,36 @@ $GLOBALS['MAIL_HEARDERS'] = array();
// Catch all sent emails // Catch all sent emails
$GLOBALS['MAIL_CATCH_ALL'] = array(); $GLOBALS['MAIL_CATCH_ALL'] = array();
/**
* Email templates
*
* This addon offer ability to send email by using templates. Email templates are stored in
* full-text files in configured directories (see $GLOBALS['MAIL_TEMPLATES_DIRECTORIES']). For each
* template, you have to provide three files with the same name but with different extensions:
* - template.subject: the email subject. Note: only the first line is used (and stripped)
* - template.html: the HTML content of the email
* - template.txt: the text content of the email
* All these files will be used as Smarty templates and will be computed using variables provided
* in the sending context. Note that the Smarty object used to compute the template is not the same
* as the one used by LdapSaisie to display pages.
*
* Futhermore, this addon offer a view to list and edit existing template (see
* $GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] to configured access).
*/
// List of directory paths where as stored mail templates
// Notes:
// - provided path could be absolute or relative. Relative path are relative to the root base
// sources LdapSaisie directory (commonly /usr/share/ldapsaisie or the src directory if you
// installed it from sources). On Debian installation, you can specify 'local/email_templates' to
// refer to /etc/ldapsaisie/local/email_templates directory/
// - Multiple directories could be specified, sorted so that the first ones take priority over
// the last one.
// - To allow users to edit them using the editor view, these directories must be
// writable by PHP process (commonly runed as www-data).
$GLOBALS['MAIL_TEMPLATES_DIRECTORIES'] = array('local/email_templates');
// List of granted LSprofiles to access mail templates editor view
// WARNING: Sanitizing mail templates is hell... EXPOSE THIS VIEW ONLY TO TRUSTED USERS!
$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] = array('admin');

View file

@ -125,50 +125,6 @@ span.LSaccessRightsMatrixView_inherit {
opacity: 0.3; opacity: 0.3;
} }
/*
* Tabs
*/
ul.LSaccessRightsMatrixView_tabs {
list-style-type: none;
padding: 0;
margin: 1em;
margin-bottom: 0;
display: flex;
flex-wrap: nowrap;
overflow: auto;
}
ul.LSaccessRightsMatrixView_tabs li a {
text-decoration: none;
color: #fff;
}
ul.LSaccessRightsMatrixView_tabs li {
text-decoration: none;
color: #fff;
background-color: #52BCE5;
border-radius: 3px 3px 0px 0px;
padding: 4px;
display: inline;
margin-right: 0.3rem;
}
ul.LSaccessRightsMatrixView_tabs li.LSaccessRightsMatrixView_active_tab {
color: #fff;
background-color: #0072B8;
}
div.LSaccessRightsMatrixView_tab_content {
border: 1px solid #0072B8;
margin: 1em;
padding: 0.5em;
margin-top: 0;
}
div.LSaccessRightsMatrixView_tab_content h2 {
margin: 0;
}
/* /*
* Legend * Legend
*/ */
@ -198,15 +154,6 @@ div.LSaccessRightsMatrixView_tab_content h2 {
@media (max-width: 1024px) { @media (max-width: 1024px) {
div.LSaccessRightsMatrixView_tab_content {
margin: 0;
}
ul.LSaccessRightsMatrixView_tabs {
margin: 0;
margin-top: 0.3rem;
}
#LSaccessRightsMatrixView table thead th:first-of-type, #LSaccessRightsMatrixView table tbody th { #LSaccessRightsMatrixView table thead th:first-of-type, #LSaccessRightsMatrixView table tbody th {
max-width: 25vw; max-width: 25vw;
} }

View file

@ -384,6 +384,55 @@ input[type='submit'].LSview_search, button {
margin-left: 1.2rem; margin-left: 1.2rem;
} }
/*
* Tabs
*/
ul.LStabs {
list-style-type: none;
padding: 0;
margin: 1em;
margin-bottom: 0;
display: flex;
flex-wrap: nowrap;
overflow: auto;
}
ul.LStabs li a {
text-decoration: none;
color: #fff;
}
ul.LStabs li {
text-decoration: none;
color: #fff;
background-color: #52BCE5;
border-radius: 3px 3px 0px 0px;
padding: 4px;
display: inline;
margin-right: 0.3rem;
}
ul.LStabs li.LStabs_active {
color: #fff;
background-color: #0072B8;
}
div.LStabs_content {
border: 1px solid #0072B8;
margin: 1em;
padding: 0.5em;
margin-top: 0;
display: none;
}
div.LStabs_content_active {
display: block;
}
div.LStabs_content h2 {
margin: 0;
}
/* /*
********************* *********************
* Error page * Error page
@ -483,6 +532,22 @@ input[type='submit'].LSview_search, button {
margin-right: 1vw; margin-right: 1vw;
} }
table.LStable {
margin-left: 0;
}
/*
* LStabs
*/
div.LStabs_content {
margin: 0;
}
ul.LStabs {
margin: 0;
margin-top: 0.3rem;
}
/* /*
* Manage menu toggle * Manage menu toggle
*/ */

View file

@ -0,0 +1,51 @@
div.LStabs_content form {
display: block;
width: calc(100% - 0.5em);
}
div.LStabs_content form input[type=text] {
width: 100%;
outline: none;
}
div.LStabs_content form textarea {
width: 100%;
min-height: 60vh;
}
div.LStabs_content form div.form-footer {
text-align: center;
width: 100%;
margin-top: 1em;
}
th.mail_subject, td.mail_subject {
width: 20vw;
white-space: nowrap;
overflow: hidden;
}
th.mail_content, td.mail_content {
width: 25vw;
white-space: nowrap;
overflow: hidden;
}
@media (max-width: 1024px) {
th.mail_subject, td.mail_subject {
width: auto;
max-width: 30vw;
}
th.mail_content, td.mail_content {
max-width: 12em;
}
}
@media (max-width: 500px) {
th.mail_subject, td.mail_subject {
max-width: 50vw;
}
th.mail_content, td.mail_content {
display: none;
}
}

View file

@ -253,7 +253,7 @@ td.LSobject-list, tr.LSobject-list, table.LStable tbody td, table.LStable th {
} }
} }
li.LSform_layout_active, ul.LSselect_selectable_object_types li, ul.LSaccessRightsMatrixView_tabs li { li.LSform_layout_active, ul.LSselect_selectable_object_types li, ul.LStabs li {
border-radius: 0px; border-radius: 0px;
border: none; border: none;
} }
@ -287,11 +287,11 @@ ul.LSformElement_image_actions {
/* ---- Medium ---- */ /* ---- Medium ---- */
li.LSform_layout_active, tr.LSobject-list:hover, table.LStable tr:hover, table.LStable tr.bis:hover, ul.LSaccessRightsMatrixView_tabs li, ul.LSselect_selectable_object_types li { li.LSform_layout_active, tr.LSobject-list:hover, table.LStable tr:hover, table.LStable tr.bis:hover, ul.LStabs li, ul.LSselect_selectable_object_types li {
background-color: var(--medium-color); background-color: var(--medium-color);
} }
div.loginform, div.recoverpasswordform, .loginform input[type='text'], .loginform input[type='password'], .recoverpasswordform input[type='text'], .recoverpasswordform input[type='password'], li.LSview-actions, div.LSform_layout, h1, form.LSglobal_search, div.LSformElement_image { div.loginform, div.recoverpasswordform, .loginform input[type='text'], .loginform input[type='password'], .recoverpasswordform input[type='text'], .recoverpasswordform input[type='password'], li.LSview-actions, div.LSform_layout, h1, form.LSglobal_search, div.LSformElement_image, div.LStabs_content {
border-color: var(--medium-color); border-color: var(--medium-color);
} }
@ -328,7 +328,7 @@ tr.LSobject-list-bis, table.LStable tr.bis, .LSform input[type=text], .LSform in
} }
/* ---- Dark ---- */ /* ---- Dark ---- */
li.LSform_layout_current, .LSform input[type=submit], input[type='submit'].LSview_search, button, ul.LSaccessRightsMatrixView_tabs li.LSaccessRightsMatrixView_active_tab, ul.LSselect_selectable_object_types li.current { li.LSform_layout_current, .LSform input[type=submit], input[type='submit'].LSview_search, button, ul.LStabs li.LStabs_active, ul.LSselect_selectable_object_types li.current {
background-color: var(--dark-color); background-color: var(--dark-color);
} }
@ -336,7 +336,7 @@ li.menu a, a.menu, h1 {
color: var(--dark-color); color: var(--dark-color);
} }
input[type='submit'].LSview_search, input[type='text'].LSview_search, button, div.LSaccessRightsMatrixView_tab_content, ul.LSselect_selectable_object_types { input[type='submit'].LSview_search, input[type='text'].LSview_search, button, ul.LSselect_selectable_object_types {
border-color: var(--dark-color); border-color: var(--dark-color);
} }

View file

@ -1,7 +0,0 @@
{literal}<div id='logo'><img src="data:image/png;base64,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" alt="LdapSaisie"/></div>{/literal}
<h2>Welcome {$name}!</h2>
<p>This email is just an example of an email template.</p>
<p>Regards,</p>

View file

@ -1 +0,0 @@
Welcome {$name}!

View file

@ -24,19 +24,33 @@
// Support // Support
LSerror :: defineError('MAIL_SUPPORT_01', LSerror :: defineError('MAIL_SUPPORT_01',
___("MAIL Support : Pear::MAIL is missing.") ___("MAIL Support: Pear::MAIL is missing.")
); );
LSerror :: defineError('MAIL_SUPPORT_02', LSerror :: defineError('MAIL_SUPPORT_02',
___("MAIL Support : Pear::MAIL_MIME is missing.") ___("MAIL Support: Pear::MAIL_MIME is missing.")
);
LSerror :: defineError('MAIL_SUPPORT_03',
___("MAIL Support: Html2Text\Html2Text is missing.")
); );
// Other errors // Other errors
LSerror :: defineError('MAIL_00', LSerror :: defineError('MAIL_00',
___("MAIL Error : %{msg}") ___("MAIL Error: %{msg}")
); );
LSerror :: defineError('MAIL_01', LSerror :: defineError('MAIL_01',
___("MAIL : Error sending your email") ___("MAIL: Error sending your email")
);
LSerror :: defineError('MAIL_02',
___("MAIL: Unknown template %{name}.")
);
LSerror :: defineError('MAIL_03',
___("MAIL: Template %{name} is incomplete.")
);
LSerror :: defineError('MAIL_04',
___("MAIL: No writable place to save your changes on this template.")
);
LSerror :: defineError('MAIL_05',
___("MAIL: An error occured saving your changes on this template.")
); );
/** /**
@ -64,32 +78,89 @@ function LSaddon_mail_support() {
} }
} }
if ($retval) if (!$retval)
LScli :: add_command( return false;
'test_send_mail',
'cli_test_send_mail', $GLOBALS['MAIL_LOGGER'] = LSlog :: get_logger('LSaddon_mail');
'Send a test email',
"[-s subject] [-b body] [-H] [recipient1] [...]", LScli :: add_command(
array ( 'test_send_mail',
" -s/--subject The test email subject (optional)", 'cli_test_send_mail',
" -b/--body The test email body (optional)", 'Send a test email',
" -H/--HTML Enable HTML email body mode (optional)", "[-s subject] [-b body] [-H] [recipient1] [...]",
" --header Email header using format:", array (
" header_name=header_value", " -s/--subject The test email subject (optional)",
" Multiple headers could be specified by using this", " -b/--body The test email body (optional)",
" optional argument multiple time.", " -H/--HTML Enable HTML email body mode (optional)",
" -a|--attachment Email attachment using format:", " --header Email header using format:",
" /path/to/attachment.file[:filename]", " header_name=header_value",
" The filename is optional (default: using source filename).", " Multiple headers could be specified by using this",
" Multiple attachments could be specified by using this", " optional argument multiple time.",
" optional argument multiple time.", " -a|--attachment Email attachment using format:",
" --bcc Add Blind Carbon Copy (BCC) recipient(s)", " /path/to/attachment.file[:filename]",
" --cc Add Carbon Copy (CC) recipient(s)", " The filename is optional (default: using source filename).",
" recipients The test email recipient(s) (required).", " Multiple attachments could be specified by using this",
" optional argument multiple time.",
" --bcc Add Blind Carbon Copy (BCC) recipient(s)",
" --cc Add Carbon Copy (CC) recipient(s)",
" recipients The test email recipient(s) (required).",
),
false, // This command does not need LDAP connection
'cli_test_send_mail_autocompleter'
);
// Handle mail templates stuff
LScli :: add_command(
'test_send_mail_template',
'cli_test_send_mail_template',
'Test to send an email template',
'[template] [-V var1=value] [recipient1] [recipient2]',
array(
' - Positional arguments :',
' - email template name',
' - email recipient(s)',
'',
' - Optional arguments :',
' -V|--variable Template variable using format:',
' variable_name=variable_value',
' Multiple variables could be specified by using this',
' optional argument multiple time.',
' -H|--header Email header using format:',
' header_name=header_value',
' Multiple headers could be specified by using this',
' optional argument multiple time.',
' -a|--attachment Email attachment using format:',
' /path/to/attachment.file[:filename]',
' The filename is optional (default: using source filename).',
' Multiple attachments could be specified by using this',
' optional argument multiple time.',
' --bcc Add Blind Carbon Copy (BCC) recipient(s)',
' --cc Add Carbon Copy (CC) recipient(s)',
), ),
false, // This command does not need LDAP connection false, // This command does not need LDAP connection
'cli_test_send_mail_autocompleter' 'cli_test_send_mail_from_template_autocompleter'
); );
if (
isset($GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'])
&& is_array($GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'])
&& $GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS']
&& list_mail_templates()
) {
if (!class_exists('\Html2Text\Html2Text')) {
if(!LSsession::includeFile(HTML2TEXT, true)) {
LSerror :: addErrorCode('MAIL_SUPPORT_03');
$retval = false;
}
}
if ($retval)
LSsession :: registerLSaddonView(
'mail', 'templates',
_('Email templates'),
'email_templates_view',
$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS']
);
}
return $retval; return $retval;
} }
@ -215,6 +286,295 @@ function sendMail($to, $subject, $msg, $headers=null, $attachments=null,
return true; return true;
} }
/**
* List email templates directories
* @return array<SplFileInfo>
*/
function list_mail_templates_directories() {
if (isset($GLOBALS['MAIL_TEMPLATES_DIRECTORIES_CACHE']))
return $GLOBALS['MAIL_TEMPLATES_DIRECTORIES_CACHE'];
if (
!isset($GLOBALS['MAIL_TEMPLATES_DIRECTORIES'])
|| !is_array($GLOBALS['MAIL_TEMPLATES_DIRECTORIES'])
)
return [];
$GLOBALS['MAIL_TEMPLATES_DIRECTORIES_CACHE'] = [];
foreach($GLOBALS['MAIL_TEMPLATES_DIRECTORIES'] as $directory) {
$path = new SplFileInfo(
substr($directory, 0,1) == '/'?
$directory:
LS_ROOT_DIR."/".$directory
);
if ($path && $path->isDir())
$GLOBALS['MAIL_TEMPLATES_DIRECTORIES_CACHE'][] = $path;
else
$GLOBALS['MAIL_LOGGER'] -> warning(
"list_mail_templates_directories(): directory {$directory} does not exists."
);
}
$GLOBALS['MAIL_LOGGER'] -> debug(
"list_mail_templates_directories(): directories = ".
implode(', ', $GLOBALS['MAIL_TEMPLATES_DIRECTORIES_CACHE'])
);
return $GLOBALS['MAIL_TEMPLATES_DIRECTORIES_CACHE'];
}
/**
* List exiting email templates
* @return array<string,array<string,string|null>>
* [
* '[name]' => [
* 'subject' => '/path/to/name.subject' or null,
* 'html' => '/path/to/name.html' or null,
* 'txt' => '/path/to/name.txt' or null,
* ],
* [...]
* ]
*/
function list_mail_templates() {
if (isset($GLOBALS['MAIL_TEMPLATES']) && $GLOBALS['MAIL_TEMPLATES'])
return $GLOBALS['MAIL_TEMPLATES'];
$GLOBALS['MAIL_TEMPLATES'] = [];
$expected_extensions = ['subject', 'html', 'txt'];
foreach(list_mail_templates_directories() as $directory) {
foreach (new DirectoryIterator($directory) as $fileInfo) {
if(
$fileInfo->isDot()
|| !$fileInfo->isFile()
|| !$fileInfo->isReadable()
|| !in_array($fileInfo->getExtension(), $expected_extensions)
)
continue;
$name = $fileInfo->getBasename(".".$fileInfo->getExtension());
if (!array_key_exists($name, $GLOBALS['MAIL_TEMPLATES'])) {
$GLOBALS['MAIL_TEMPLATES'][$name] = [];
foreach($expected_extensions as $ext) $GLOBALS['MAIL_TEMPLATES'][$name][$ext] = null;
}
if (!$GLOBALS['MAIL_TEMPLATES'][$name][$fileInfo->getExtension()])
$GLOBALS['MAIL_TEMPLATES'][$name][$fileInfo->getExtension()] = $fileInfo->getRealPath();
}
}
return $GLOBALS['MAIL_TEMPLATES'];
}
/**
* Search for writable path to save change of a template file
* @param string $template The template name
* @param string $extension The template file extension (subject, html or txt)
* @return string|false The path of writable template file if found, false otherwise
*/
function get_mail_template_saved_path($template, $extension) {
$templates = list_mail_templates();
if (!array_key_exists($template, $templates))
return false;
$found = false;
$first_writable = false;
foreach(list_mail_templates_directories() as $directory) {
$file_path = new SplFileInfo("$directory/$template.$extension");
if ($file_path->isFile()) {
// File exist, check is writable
if ($file_path->isWritable())
return $file_path->getRealPath();
// If we don't find previously a writable file, trigger an error
if (!$first_writable) {
$GLOBALS['MAIL_LOGGER'] -> error(
"get_mail_template_saved_path($template, $extension): file '{$file_path->getRealPath()}' ".
"is not writable, can't saved this template file."
);
return false;
}
continue;
}
else if (!$first_writable && $directory->isWritable()) {
$first_writable = strval($file_path);
}
}
// No existing writable file found
if ($first_writable) return $first_writable;
$GLOBALS['MAIL_LOGGER'] -> error(
"get_mail_template_saved_path($template, $extension): ".
"no writable path found, can't saved this template file."
);
return false;
}
/**
* Send email from template
* @param string $tplname The email template name
* @param string $to The email recipient
* @param array<string,mixed> $variables Variables to use to compute the template
* @param array<string,string>|null $headers Email headers
* @param array<string,string>|null $attachments Email attachments as an array with
* filepath as key and filename as value
* @return boolean True if the email was sent, false otherwise
*/
function sendMailFromTemplate(
$tplname, $to, $variables=null, $headers=null, $attachments=null
) {
$templates = list_mail_templates();
if (!array_key_exists($tplname, $templates)) {
LSerror :: addErrorCode('MAIL_02', $tplname);
return False;
}
$tpl = $templates[$tplname];
if (!$tpl['subject'] || !($tpl['txt'] || $tpl['html'])) {
LSerror :: addErrorCode('MAIL_03', $tplname);
return False;
}
$smarty = new Smarty();
$smarty -> setCompileDir(LS_TMP_DIR_PATH);
if (is_array($variables))
array_map([$smarty, "assign"], array_keys($variables), array_values($variables));
try {
$subject = $smarty -> fetch("file:{$tpl['subject']}");
// Multiple line from subject cause problem, trim it and only the first line
$subject = explode("\n", trim($subject))[0];
$GLOBALS['MAIL_LOGGER'] -> debug(
"sendMailFromTemplate($tplname, ".implode("|", $to)."): ".
"subject compute from '{$tpl['subject']}'."
);
if ($tpl['html']) {
$message = $smarty -> fetch("file:{$tpl['html']}");
$html = true;
$GLOBALS['MAIL_LOGGER'] -> debug(
"sendMailFromTemplate($tplname, ".implode("|", $to)."): ".
"HTML content compute from '{$tpl['html']}'."
);
}
else {
$message = $smarty -> fetch("file:{$tpl['txt']}");
$html = false;
$GLOBALS['MAIL_LOGGER'] -> debug(
"sendMailFromTemplate($tplname, ".implode("|", $to)."): ".
"text content compute from '{$tpl['txt']}'."
);
}
}
catch (Exception $e) {
$GLOBALS['MAIL_LOGGER'] -> exception(
$e, getFData(
_("An exception occured forging message from email template '%{template}'"),
$tplname
),
false
);
return false;
}
return sendMail($to, $subject, $message, $headers, $attachments, "\n", "utf8", $html);
}
/**
* Email templates management view
* @return void
*/
function email_templates_view() {
$template = isset($_REQUEST['name'])?$_REQUEST['name']:null;
$templates = [];
foreach(list_mail_templates() as $name => $tpl) {
if ($template && $template != $name)
continue;
$templates[$name] = [
'name' => $name,
'subject' => $tpl['subject']?file_get_contents($tpl['subject']):null,
'html' => $tpl['html']?file_get_contents($tpl['html']):null,
'txt' => $tpl['txt']?file_get_contents($tpl['txt']):null,
];
if ($template) continue;
if ($templates[$name]['html']) {
$Html2Text = new \Html2Text\Html2Text($templates[$name]['html']);
$templates[$name]['html'] = substr($Html2Text->getText(), 0, 70)."...";
}
if ($templates[$name]['txt']) {
$templates[$name]['txt'] = substr($templates[$name]['txt'], 0, 70)."...";
}
}
if ($template) {
if (!array_key_exists($template, $templates)) {
LSurl::redirect("addon/mail/templates");
}
LStemplate :: assign('pagetitle', getFData(_('Email template: %{name}'), $template));
$tab = isset($_REQUEST['tab'])?$_REQUEST['tab']:'subject';
$path = false;
switch ($tab) {
case 'subject':
$path = get_mail_template_saved_path($template, $tab);
if (array_key_exists('subject', $_POST)) {
if (!$path)
LSerror :: addErrorCode('MAIL_04');
elseif (file_put_contents($path, $_POST['subject']) !== false) {
LSsession :: addInfo(_("Your changes have been saved."));
LSurl::redirect("addon/mail/templates?name=".urlencode($template)."&tab=$tab");
}
else {
LSerror :: addErrorCode('MAIL_05');
$tpl['subject'] = $_POST['subject'];
}
}
break;
case 'html':
$path = get_mail_template_saved_path($template, $tab);
if (array_key_exists('html', $_POST)) {
if (!$path)
LSerror :: addErrorCode('MAIL_04');
elseif (file_put_contents($path, $_POST['html']) !== false) {
LSsession :: addInfo(_("Your changes have been saved."));
LSurl::redirect("addon/mail/templates?name=".urlencode($template)."&tab=$tab");
}
else {
LSerror :: addErrorCode('MAIL_05');
$tpl['html'] = $_POST['html'];
}
}
LStemplate :: addLibJSscript('tinymce/js/tinymce/tinymce.min.js');
LStemplate :: addJSscript('email_templates.js');
break;
case 'txt':
$path = get_mail_template_saved_path($template, $tab);
if (array_key_exists('txt', $_POST)) {
if (!$path)
LSerror :: addErrorCode('MAIL_04');
elseif (file_put_contents($path, $_POST['txt']) !== false) {
LSsession :: addInfo(_("Your changes have been saved."));
LSurl::redirect("addon/mail/templates?name=".urlencode($template)."&tab=$tab");
}
else {
LSerror :: addErrorCode('MAIL_05');
$tpl['txt'] = $_POST['txt'];
}
}
break;
default:
LSurl::redirect("addon/mail/templates?name=".urlencode($template));
}
LStemplate :: assign('template', $templates[$template]);
LStemplate :: assign('tab', $tab);
LStemplate :: assign('writable', boolval($path));
$LSview_actions = array();
$LSview_actions['return'] = array (
'label' => _('Go back'),
'url' => 'addon/mail/templates',
'action' => 'view'
);
LStemplate :: assign('LSview_actions', $LSview_actions);
LSsession :: setTemplate('email_template.tpl');
}
else {
LStemplate :: assign('pagetitle', _('Email templates'));
LStemplate :: assign('templates', $templates);
LSsession :: setTemplate('email_templates.tpl');
}
LStemplate :: addCssFile('email_templates.css');
}
if (php_sapi_name() != 'cli') if (php_sapi_name() != 'cli')
return true; return true;
@ -356,3 +716,132 @@ function cli_test_send_mail_autocompleter($comp_words, $comp_word_num, $comp_wor
); );
return LScli :: autocomplete_opts($opts, $comp_word); return LScli :: autocomplete_opts($opts, $comp_word);
} }
/**
* CLI test_send_mail_template command
*
* @param array $command_args Command arguments :
* - Positional arguments :
* - template name
* - recipient
* - Optional arguments :
* - -V|--variable: template variable (format: variable=value)
* - -H|--header: header (format: header=value)
* - -a|--attachent: (format: /path/to/file.ext:filename or just /path/to/file.ext)
* - -bcc: BCC recipient(s)
* - -cc: CC recipient(s)
*
* @return boolean True on success, false otherwise
**/
function cli_test_send_mail_template($command_args) {
$template = null;
$recipients = array();
$variables = array();
$headers = array();
$attachments = array();
for ($i=0; $i < count($command_args); $i++) {
LScli :: unquote_word($command_args[$i]);
if (in_array($command_args[$i], array('-V', '--variable'))) {
$i++;
LScli :: unquote_word($command_args[$i]);
$parts = explode('=', $command_args[$i]);
if (count($parts) != 2)
LScli :: usage('Invalid variable string ('.$command_args[$i].').');
if (array_key_exists($parts[0], $variables))
LScli :: usage('Variable "'.$parts[0].'" already specified.');
$variables[$parts[0]] = $parts[1];
}
elseif (in_array($command_args[$i], array('-H', '--header'))) {
$i++;
LScli :: unquote_word($command_args[$i]);
$parts = explode('=', $command_args[$i]);
if (count($parts) != 2)
LScli :: usage('Invalid header string ('.$command_args[$i].').');
if (array_key_exists($parts[0], $headers))
LScli :: usage('Header "'.$parts[0].'" already specified.');
$headers[$parts[0]] = $parts[1];
}
elseif (in_array($command_args[$i], array('-a', '--attachent'))) {
$i++;
LScli :: unquote_word($command_args[$i]);
$parts = explode(':', $command_args[$i]);
$path = $parts[0];
if (!is_file($path))
LScli :: usage('Invalid attachment "'.$command_args[$i].'": file not found.');
$attachments[$path] = count($parts) >= 2?$parts[1]:basename($path);
}
elseif ($command_args[$i] == '--bcc') {
$i++;
LScli :: unquote_word($command_args[$i]);
if (!checkEmail($command_args[$i]))
LScli :: usage('Invalid BCC recipient "'.$command_args[$i].'".');
$headers['BCC'] = isset($headers['BCC'])?ensureIsArray($headers['BCC']):[];
$headers['BCC'][] = $command_args[$i];
}
elseif ($command_args[$i] == '--cc') {
$i++;
LScli :: unquote_word($command_args[$i]);
if (!checkEmail($command_args[$i]))
LScli :: usage('Invalid CC recipient "'.$command_args[$i].'".');
$headers['CC'] = isset($headers['CC'])?ensureIsArray($headers['CC']):[];
$headers['CC'][] = $command_args[$i];
}
else if (is_null($template)) {
$template = $command_args[$i];
}
else if (checkEmail($command_args[$i])) {
$recipients[] = $command_args[$i];
}
else
LScli :: usage('Invalid recipient "'.$command_args[$i].'".');
}
if (is_null($template) || empty($recipients))
LScli :: usage('You must provide email template name and at least one recipient.');
return sendMailFromTemplate(
$template,
$recipients,
$variables,
$headers,
$attachments
);
}
/**
* Args autocompleter for CLI test_send_mail_from_template command
*
* @param array<string> $comp_words List of already typed words of the command
* @param int $comp_word_num The command word number to autocomplete
* @param string $comp_word The command word to autocomplete
* @param array<string> $opts List of global available options
*
* @return array<string> List of available options for the word to autocomplete
**/
function cli_test_send_mail_from_template_autocompleter(
$comp_words, $comp_word_num, $comp_word, $opts
) {
if (isset($comp_words[$comp_word_num-1]))
switch ($comp_words[$comp_word_num-1]) {
case '-v':
case '--variable':
case '-H':
case '--header':
case '-a':
case '--attachment':
case '--bcc':
case '--cc':
return array();
break;
}
$opts = array_merge(
$opts,
array (
'-v', '--variable',
'-H', '--header',
'-a', '--attachment',
'--bcc', '--cc',
)
);
return LScli :: autocomplete_opts($opts, $comp_word);
}

View file

@ -22,19 +22,6 @@
class LSmail extends LSlog_staticLoggerClass { class LSmail extends LSlog_staticLoggerClass {
/**
* Array of templates directories where file have to be search
* @var array
*/
private static $template_directories = array('local', './');
/**
* Cache of loaded templates
* @see list_templates()
* @var array<string,array<string,string|null>>
*/
private static $_templates = null;
/* /*
* Méthode chargeant les dépendances d'affichage * Méthode chargeant les dépendances d'affichage
* *
@ -94,287 +81,4 @@ class LSmail extends LSlog_staticLoggerClass {
} }
} }
/**
* List exiting email templates
* @return array<string,array<string,string|null>>
* [
* '[name]' => [
* 'subject' => '/path/to/name.subject' or null,
* 'html' => '/path/to/name.html' or null,
* 'txt' => '/path/to/name.txt' or null,
* ],
* [...]
* ]
*/
public static function list_templates() {
if (self :: $_templates)
return self :: $_templates;
self :: $_templates = [];
$expected_extensions = ['subject', 'html', 'txt'];
foreach(self :: $template_directories as $dir) {
$dir_path = realpath(LS_ROOT_DIR."/".$dir."/email_templates");
if ($dir_path === false)
// Directory not found or not accessible
continue;
foreach (new DirectoryIterator($dir_path) as $fileInfo) {
if(
$fileInfo->isDot()
|| !$fileInfo->isFile()
|| !$fileInfo->isReadable()
|| !in_array($fileInfo->getExtension(), $expected_extensions)
)
continue;
$name = $fileInfo->getBasename(".".$fileInfo->getExtension());
if (!array_key_exists($name, self :: $_templates)) {
self :: $_templates[$name] = [];
foreach($expected_extensions as $ext) self :: $_templates[$name][$ext] = null;
}
if (!self :: $_templates[$name][$fileInfo->getExtension()])
self :: $_templates[$name][$fileInfo->getExtension()] = $fileInfo->getRealPath();
}
}
return self :: $_templates;
}
/**
* Send email from template
* @param string $tplname The email template name
* @param string $to The email recipient
* @param array<string,mixed> $variables Variables to use to compute the template
* @param array<string,string>|null $headers Email headers
* @param array<string,string>|null $attachments Email attachments as an array with
* filepath as key and filename as value
* @return boolean True if the email was sent, false otherwise
*/
public static function send_mail_from_template(
$tplname, $to, $variables=null, $headers=null, $attachments=null
) {
$templates = self :: list_templates();
if (!array_key_exists($tplname, $templates)) {
LSerror :: addErrorCode('LSmail_01', $tplname);
return False;
}
$tpl = $templates[$tplname];
if (!$tpl['subject'] || !($tpl['txt'] || $tpl['html'])) {
LSerror :: addErrorCode('LSmail_02', $tplname);
return False;
}
$smarty = new Smarty();
if (is_array($variables))
array_map([$smarty, "assign"], array_keys($variables), array_values($variables));
try {
$subject = $smarty -> fetch("file:{$tpl['subject']}");
// Multiple line from subject cause problem, trim it and only the first line
$subject = explode("\n", trim($subject))[0];
self :: log_debug(
"send_mail_from_template($tplname, ".implode("|", $to)."): ".
"subject compute from '{$tpl['subject']}'."
);
if ($tpl['html']) {
$body = $smarty -> fetch("file:{$tpl['html']}");
$html = true;
self :: log_debug(
"send_mail_from_template($tplname, ".implode("|", $to)."): ".
"HTML body compute from '{$tpl['html']}'."
);
}
else {
$body = $smarty -> fetch("file:{$tpl['txt']}");
$html = false;
self :: log_debug(
"send_mail_from_template($tplname, ".implode("|", $to)."): ".
"text body compute from '{$tpl['txt']}'."
);
}
}
catch (Exception $e) {
self :: log_exception(
$e, getFData(
_("LSmail - An exception occured forging message from email template '%{template}'"),
$tplname
),
false
);
return false;
}
return sendMail($to, $subject, $body, $headers, $attachments, "\n", "utf8", $html);
}
/**
* CLI test_send_mail_template command
*
* @param array $command_args Command arguments :
* - Positional arguments :
* - template name
* - recipient
* - Optional arguments :
* - -V|--variable: template variable (format: variable=value)
* - -H|--header: header (format: header=value)
* - -a|--attachent: (format: /path/to/file.ext:filename or just /path/to/file.ext)
* - -bcc: BCC recipient(s)
* - -cc: CC recipient(s)
*
* @return boolean True on success, false otherwise
**/
public static function cli_test_send_mail_template($command_args) {
$template = null;
$recipients = array();
$variables = array();
$headers = array();
$attachments = array();
for ($i=0; $i < count($command_args); $i++) {
LScli :: unquote_word($command_args[$i]);
if (in_array($command_args[$i], array('-V', '--variable'))) {
$i++;
LScli :: unquote_word($command_args[$i]);
$parts = explode('=', $command_args[$i]);
if (count($parts) != 2)
LScli :: usage('Invalid variable string ('.$command_args[$i].').');
if (array_key_exists($parts[0], $variables))
LScli :: usage('Variable "'.$parts[0].'" already specified.');
$variables[$parts[0]] = $parts[1];
}
elseif (in_array($command_args[$i], array('-H', '--header'))) {
$i++;
LScli :: unquote_word($command_args[$i]);
$parts = explode('=', $command_args[$i]);
if (count($parts) != 2)
LScli :: usage('Invalid header string ('.$command_args[$i].').');
if (array_key_exists($parts[0], $headers))
LScli :: usage('Header "'.$parts[0].'" already specified.');
$headers[$parts[0]] = $parts[1];
}
elseif (in_array($command_args[$i], array('-a', '--attachent'))) {
$i++;
LScli :: unquote_word($command_args[$i]);
$parts = explode(':', $command_args[$i]);
$path = $parts[0];
if (!is_file($path))
LScli :: usage('Invalid attachment "'.$command_args[$i].'": file not found.');
$attachments[$path] = count($parts) >= 2?$parts[1]:basename($path);
}
elseif ($command_args[$i] == '--bcc') {
$i++;
LScli :: unquote_word($command_args[$i]);
if (!checkEmail($command_args[$i]))
LScli :: usage('Invalid BCC recipient "'.$command_args[$i].'".');
$headers['BCC'] = isset($headers['BCC'])?ensureIsArray($headers['BCC']):[];
$headers['BCC'][] = $command_args[$i];
}
elseif ($command_args[$i] == '--cc') {
$i++;
LScli :: unquote_word($command_args[$i]);
if (!checkEmail($command_args[$i]))
LScli :: usage('Invalid CC recipient "'.$command_args[$i].'".');
$headers['CC'] = isset($headers['CC'])?ensureIsArray($headers['CC']):[];
$headers['CC'][] = $command_args[$i];
}
else if (is_null($template)) {
$template = $command_args[$i];
}
else if (checkEmail($command_args[$i])) {
$recipients[] = $command_args[$i];
}
else
LScli :: usage('Invalid recipient "'.$command_args[$i].'".');
}
if (is_null($template) || empty($recipients))
LScli :: usage('You must provide email template name and at least one recipient.');
return self :: send_mail_from_template(
$template,
$recipients,
$variables,
$headers,
$attachments
);
}
/**
* Args autocompleter for CLI test_send_mail_from_template command
*
* @param array<string> $comp_words List of already typed words of the command
* @param int $comp_word_num The command word number to autocomplete
* @param string $comp_word The command word to autocomplete
* @param array<string> $opts List of global available options
*
* @return array<string> List of available options for the word to autocomplete
**/
public static function cli_test_send_mail_from_template_autocompleter(
$comp_words, $comp_word_num, $comp_word, $opts
) {
if (isset($comp_words[$comp_word_num-1]))
switch ($comp_words[$comp_word_num-1]) {
case '-v':
case '--variable':
case '-H':
case '--header':
case '-a':
case '--attachment':
case '--bcc':
case '--cc':
return array();
break;
}
$opts = array_merge(
$opts,
array (
'-v', '--variable',
'-H', '--header',
'-a', '--attachment',
'--bcc', '--cc',
)
);
return LScli :: autocomplete_opts($opts, $comp_word);
}
} }
/**
* Error Codes
*/
LSerror :: defineError('LSmail_01',
___("LSmail: Unknown template %{name}.")
);
LSerror :: defineError('LSmail_02',
___("LSmail: Template %{name} is incomplete.")
);
// LScli
LScli :: add_command(
'test_send_mail_template',
array('LSmail', 'cli_test_send_mail_template'),
'Test to send an email template',
'[template] [-V var1=value] [recipient1] [recipient2]',
array(
' - Positional arguments :',
' - email template name',
' - email recipient(s)',
'',
' - Optional arguments :',
' -V|--variable Template variable using format:',
' variable_name=variable_value',
' Multiple variables could be specified by using this',
' optional argument multiple time.',
' -H|--header Email header using format:',
' header_name=header_value',
' Multiple headers could be specified by using this',
' optional argument multiple time.',
' -a|--attachment Email attachment using format:',
' /path/to/attachment.file[:filename]',
' The filename is optional (default: using source filename).',
' Multiple attachments could be specified by using this',
' optional argument multiple time.',
' --bcc Add Blind Carbon Copy (BCC) recipient(s)',
' --cc Add Carbon Copy (CC) recipient(s)',
),
false, // This command does not need LDAP connection
array('LSmail', 'cli_test_send_mail_from_template_autocompleter')
);

View file

@ -0,0 +1,20 @@
window.addEvent(window.ie ? 'load' : 'domready', function() {
var textarea = document.getElement('textarea[name=html]');
if (!textarea) return;
var options = {};
if (textarea.disabled) {
options.readonly = 1;
options.setup = function(editor) {
editor.on('skinLoaded', function(e) {
editor.notificationManager.open({
text: textarea.get('title'),
type: 'warning'
});
});
};
}
options.target = textarea;
options.language = varLSdefault.getCurrentLang();
tinymce.init(options);
});

View file

@ -311,11 +311,12 @@ LSurl :: add_handler('#^favicon\.ico#', 'handle_favicon_ico_view', false, true,
function handle_libs_file($request) { function handle_libs_file($request) {
$path = LStemplate :: getLibFilePath($request -> file); $path = LStemplate :: getLibFilePath($request -> file);
if ($path && is_file($path)) { if ($path && is_file($path)) {
switch (strtolower(substr($path, -4))) { $info = new SplFileInfo($path);
case '.css': switch ($info -> getExtension()) {
case 'css':
$mime_type = 'text/css'; $mime_type = 'text/css';
break; break;
case '.js': case 'js':
$mime_type = 'text/javascript'; $mime_type = 'text/javascript';
break; break;
default: default:

View file

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: LdapSaisie\n" "Project-Id-Version: LdapSaisie\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: 2023-12-05 12:48+0100\n" "PO-Revision-Date: 2024-02-22 15:25+0100\n"
"Last-Translator: Benjamin Renard <brenard@easter-eggs.com>\n" "Last-Translator: Benjamin Renard <brenard@easter-eggs.com>\n"
"Language-Team: LdapSaisie <ldapsaisie-users@lists.labs.libre-entreprise." "Language-Team: LdapSaisie <ldapsaisie-users@lists.labs.libre-entreprise."
"org>\n" "org>\n"
@ -82,7 +82,7 @@ msgstr "Expiré (depuis %s)"
#, php-format #, php-format
msgid "Last password changed: %s, duration of validity: %s days" msgid "Last password changed: %s, duration of validity: %s days"
msgstr "" msgstr ""
"Dernière modification du mot de passe : %s, durée de validité : %s jours." "Dernière modification du mot de passe : %s, durée de validité : %s jours"
#: includes/addons/LSaddons.ppolicy.php:197 #: includes/addons/LSaddons.ppolicy.php:197
#, php-format #, php-format
@ -230,27 +230,55 @@ msgstr ""
"ligne CSV." "ligne CSV."
#: includes/addons/LSaddons.mail.php:27 #: includes/addons/LSaddons.mail.php:27
msgid "MAIL Support : Pear::MAIL is missing." msgid "MAIL Support: Pear::MAIL is missing."
msgstr "Support MAIL : Pear::MAIL est manquant." msgstr "Support MAIL : Pear::MAIL est manquant."
#: includes/addons/LSaddons.mail.php:30 #: includes/addons/LSaddons.mail.php:30
msgid "MAIL Support : Pear::MAIL_MIME is missing." msgid "MAIL Support: Pear::MAIL_MIME is missing."
msgstr "Support MAIL : Pear::MAIL_MIME est manquant." msgstr "Support MAIL : Pear::MAIL_MIME est manquant."
#: includes/addons/LSaddons.mail.php:35 #: includes/addons/LSaddons.mail.php:33
msgid "MAIL Error : %{msg}" msgid "MAIL Support: Html2Text\\Html2Text is missing."
msgstr "Support MAIL : Html2Text\\Html2Text est manquant."
#: includes/addons/LSaddons.mail.php:38
msgid "MAIL Error: %{msg}"
msgstr "Erreur MAIL : %{msg}" msgstr "Erreur MAIL : %{msg}"
#: includes/addons/LSaddons.mail.php:39 #: includes/addons/LSaddons.mail.php:41
msgid "MAIL : Error sending your email" msgid "MAIL: Error sending your email"
msgstr "MAIL : Erreur durant l'envoie de votre mail" msgstr "MAIL : Erreur durant l'envoi de votre mail"
#: includes/addons/LSaddons.mail.php:125 #: includes/addons/LSaddons.mail.php:44
msgid "MAIL: Unknown template %{name}."
msgstr "MAIL : Template %{name} inconnu."
#: includes/addons/LSaddons.mail.php:47
msgid "MAIL: Template %{name} is incomplete."
msgstr "MAIL : Le template %{name} est incomplet."
#: includes/addons/LSaddons.mail.php:50
msgid "MAIL: No writable place to save your changes on this template."
msgstr ""
"MAIL : Aucun emplacement accessible en écriture pour enregistrer vos "
"modifications sur ce modèle."
#: includes/addons/LSaddons.mail.php:53
msgid "MAIL: An error occured saving your changes on this template."
msgstr ""
"MAIL : Une erreur est survenue en enregistrant vos modifications sur ce "
"modèle."
#: includes/addons/LSaddons.mail.php:158 includes/addons/LSaddons.mail.php:568
msgid "Email templates"
msgstr "Modèles de courriels"
#: includes/addons/LSaddons.mail.php:206
#, php-format #, php-format
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>" msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
msgstr "</hr><p><small>Mail initialement adressé à %s.</small></p>" msgstr "</hr><p><small>Mail initialement adressé à %s.</small></p>"
#: includes/addons/LSaddons.mail.php:126 #: includes/addons/LSaddons.mail.php:207
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -263,12 +291,12 @@ msgstr ""
"\n" "\n"
"Mail initialement adressé à %s." "Mail initialement adressé à %s."
#: includes/addons/LSaddons.mail.php:156 #: includes/addons/LSaddons.mail.php:235
#, php-format #, php-format
msgid "<p><small>%s: %s</small></p>" msgid "<p><small>%s: %s</small></p>"
msgstr "<p><small>%s: %s</small></p>" msgstr "<p><small>%s: %s</small></p>"
#: includes/addons/LSaddons.mail.php:157 #: includes/addons/LSaddons.mail.php:236
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -277,6 +305,28 @@ msgstr ""
"\n" "\n"
"%s: %s" "%s: %s"
#: includes/addons/LSaddons.mail.php:458
msgid "An exception occured forging message from email template '%{template}'"
msgstr ""
"Une exception est survenue en générant le message à partir du modèle de "
"courriel '%{template}'"
#: includes/addons/LSaddons.mail.php:498
msgid "Email template: %{name}"
msgstr "Modèle de courriel : %{name}"
#: includes/addons/LSaddons.mail.php:508 includes/addons/LSaddons.mail.php:524
#: includes/addons/LSaddons.mail.php:542
msgid "Your changes have been saved."
msgstr "Vos modifications ont été enregistrées."
#: includes/addons/LSaddons.mail.php:560
#: includes/addons/LSaddons.showSupportInfo.php:78
#: includes/addons/LSaddons.accesslog.php:248
#: includes/addons/LSaddons.showTechInfo.php:117
msgid "Go back"
msgstr "Retour"
#: includes/addons/LSaddons.phpldapadmin.php:27 #: includes/addons/LSaddons.phpldapadmin.php:27
msgid "PhpLdapAdmin Support : The constant %{const} is not defined." msgid "PhpLdapAdmin Support : The constant %{const} is not defined."
msgstr "Support PhpLdapAdmin : La constante %{const} n'est pas définie." msgstr "Support PhpLdapAdmin : La constante %{const} n'est pas définie."
@ -293,12 +343,6 @@ msgstr "%{name} : Informations pour le support"
msgid "Download" msgid "Download"
msgstr "Télécharger" msgstr "Télécharger"
#: includes/addons/LSaddons.showSupportInfo.php:78
#: includes/addons/LSaddons.accesslog.php:248
#: includes/addons/LSaddons.showTechInfo.php:117
msgid "Go back"
msgstr "Retour"
#: includes/addons/LSaddons.dyngroup.php:27 #: includes/addons/LSaddons.dyngroup.php:27
msgid "Dynamic groups support: The constant %{const} is not defined." msgid "Dynamic groups support: The constant %{const} is not defined."
msgstr "" msgstr ""
@ -409,8 +453,8 @@ msgstr "Comparer"
#: includes/class/class.LSrelation.php:679 includes/class/class.LSform.php:346 #: includes/class/class.LSrelation.php:679 includes/class/class.LSform.php:346
#: includes/class/class.LSformElement_select_object.php:75 #: includes/class/class.LSformElement_select_object.php:75
#: includes/class/class.LSformElement_select_object.php:91 #: includes/class/class.LSformElement_select_object.php:91
#: includes/class/class.LSsearchEntry.php:237 includes/routes.php:1068 #: includes/class/class.LSsearchEntry.php:237 includes/routes.php:1075
#: includes/routes.php:1212 #: includes/routes.php:1219
msgid "Delete" msgid "Delete"
msgstr "Supprimer" msgstr "Supprimer"
@ -423,8 +467,8 @@ msgstr "Étendue"
#: includes/class/class.LSrelation.php:736 #: includes/class/class.LSrelation.php:736
#: includes/class/class.LSformElement_select_object.php:74 #: includes/class/class.LSformElement_select_object.php:74
#: includes/class/class.LSformElement_supannLabeledValue.php:90 #: includes/class/class.LSformElement_supannLabeledValue.php:90
#: includes/class/class.LSsearchEntry.php:221 includes/routes.php:1052 #: includes/class/class.LSsearchEntry.php:221 includes/routes.php:1059
#: includes/routes.php:1220 includes/routes.php:1305 includes/routes.php:1451 #: includes/routes.php:1227 includes/routes.php:1313 includes/routes.php:1460
msgid "Modify" msgid "Modify"
msgstr "Modifier" msgstr "Modifier"
@ -432,7 +476,7 @@ msgstr "Modifier"
msgid "Modify RDN" msgid "Modify RDN"
msgstr "Modifier le RDN" msgstr "Modifier le RDN"
#: includes/addons/LSaddons.accesslog.php:35 includes/routes.php:517 #: includes/addons/LSaddons.accesslog.php:35 includes/routes.php:521
#: templates/default/select.tpl:28 templates/default/global_search.tpl:6 #: templates/default/select.tpl:28 templates/default/global_search.tpl:6
msgid "Search" msgid "Search"
msgstr "Rechercher" msgstr "Rechercher"
@ -460,7 +504,7 @@ msgstr "Voir les modifications d'LdapSaisie"
#: includes/addons/LSaddons.accesslog.php:243 #: includes/addons/LSaddons.accesslog.php:243
#: includes/class/class.LSsession.php:1875 includes/routes.php:157 #: includes/class/class.LSsession.php:1875 includes/routes.php:157
#: includes/routes.php:474 templates/default/select.tpl:29 #: includes/routes.php:478 templates/default/select.tpl:29
msgid "Refresh" msgid "Refresh"
msgstr "Rafraîchir" msgstr "Rafraîchir"
@ -916,7 +960,7 @@ msgstr "Confirmez-vous votre choix ?"
#: includes/class/class.LSconfirmBox.php:37 #: includes/class/class.LSconfirmBox.php:37
#: includes/class/class.LSsmoothbox.php:39 includes/class/class.LSform.php:175 #: includes/class/class.LSsmoothbox.php:39 includes/class/class.LSform.php:175
#: includes/routes.php:638 includes/routes.php:1292 includes/routes.php:1438 #: includes/routes.php:645 includes/routes.php:1300 includes/routes.php:1447
#: templates/default/recoverpassword.tpl:21 #: templates/default/recoverpassword.tpl:21
msgid "Validate" msgid "Validate"
msgstr "Valider" msgstr "Valider"
@ -2265,8 +2309,8 @@ msgstr "Attention"
msgid "No object." msgid "No object."
msgstr "Aucun objet." msgstr "Aucun objet."
#: includes/class/class.LSrelation.php:747 includes/routes.php:456 #: includes/class/class.LSrelation.php:747 includes/routes.php:460
#: includes/routes.php:997 #: includes/routes.php:1004
msgid "New" msgid "New"
msgstr "Nouveau" msgstr "Nouveau"
@ -2502,13 +2546,13 @@ msgstr ""
"Une erreur est survenue en soumettant ce formulaire. Merci de ré-essayer ou " "Une erreur est survenue en soumettant ce formulaire. Merci de ré-essayer ou "
"de contacter le support." "de contacter le support."
#: includes/class/class.LSform.php:327 includes/routes.php:634 #: includes/class/class.LSform.php:327 includes/routes.php:641
msgid "Do you really want to execute custom action %{title} on this search ?" msgid "Do you really want to execute custom action %{title} on this search ?"
msgstr "" msgstr ""
"Êtes-vous vraiment sûre de vouloir exécuter l'action personnalisée %{title} " "Êtes-vous vraiment sûre de vouloir exécuter l'action personnalisée %{title} "
"sur cette recherche ?" "sur cette recherche ?"
#: includes/class/class.LSform.php:333 includes/routes.php:1432 #: includes/class/class.LSform.php:333 includes/routes.php:1441
msgid "" msgid ""
"Do you really want to execute custom action %{customAction} on " "Do you really want to execute custom action %{customAction} on "
"%{objectname} ?" "%{objectname} ?"
@ -2716,8 +2760,8 @@ msgstr "Réinitialiser le choix."
msgid "Display RSS stack." msgid "Display RSS stack."
msgstr "Afficher la file RSS." msgstr "Afficher la file RSS."
#: includes/class/class.LSattr_ldap_password.php:108 includes/routes.php:587 #: includes/class/class.LSattr_ldap_password.php:108 includes/routes.php:594
#: includes/routes.php:1379 #: includes/routes.php:1388
msgid "undefined" msgid "undefined"
msgstr "non-définie" msgstr "non-définie"
@ -3242,12 +3286,12 @@ msgstr "Erreur inconnue"
msgid "Unknown error : %{error}" msgid "Unknown error : %{error}"
msgstr "Erreur inconnue : %{error}" msgstr "Erreur inconnue : %{error}"
#: includes/class/class.LSsearchEntry.php:213 includes/routes.php:1204 #: includes/class/class.LSsearchEntry.php:213 includes/routes.php:1211
#: includes/routes.php:1297 includes/routes.php:1443 #: includes/routes.php:1305 includes/routes.php:1452
msgid "View" msgid "View"
msgstr "Voir" msgstr "Voir"
#: includes/class/class.LSsearchEntry.php:229 includes/routes.php:1060 #: includes/class/class.LSsearchEntry.php:229 includes/routes.php:1067
msgid "Copy" msgid "Copy"
msgstr "Copier" msgstr "Copier"
@ -3277,66 +3321,66 @@ msgstr "Accueil"
msgid "You must provide pattern for global search." msgid "You must provide pattern for global search."
msgstr "Vous devez fournir un mot clé pour les recherches globales." msgstr "Vous devez fournir un mot clé pour les recherches globales."
#: includes/routes.php:462 includes/routes.php:818 #: includes/routes.php:466 includes/routes.php:825
msgid "Import" msgid "Import"
msgstr "Importer" msgstr "Importer"
#: includes/routes.php:467 includes/routes.php:884 #: includes/routes.php:471 includes/routes.php:891
msgid "Export" msgid "Export"
msgstr "Exporter" msgstr "Exporter"
#: includes/routes.php:479 #: includes/routes.php:483
msgid "Reset" msgid "Reset"
msgstr "Réinitialiser" msgstr "Réinitialiser"
#: includes/routes.php:518 templates/default/select.tpl:31 #: includes/routes.php:522 templates/default/select.tpl:31
msgid "Approximative search" msgid "Approximative search"
msgstr "Recherche approximative" msgstr "Recherche approximative"
#: includes/routes.php:519 templates/default/select.tpl:32 #: includes/routes.php:523 templates/default/select.tpl:32
msgid "Recursive search" msgid "Recursive search"
msgstr "Recherche récursive" msgstr "Recherche récursive"
#: includes/routes.php:608 #: includes/routes.php:615
msgid "" msgid ""
"The custom action %{title} have been successfully execute on this search." "The custom action %{title} have been successfully execute on this search."
msgstr "" msgstr ""
"L'action personnalisée %{title} a été correctement exécutée sur cette " "L'action personnalisée %{title} a été correctement exécutée sur cette "
"recherche." "recherche."
#: includes/routes.php:956 #: includes/routes.php:963
msgid "Data entry form" msgid "Data entry form"
msgstr "Masque de saisie" msgstr "Masque de saisie"
#: includes/routes.php:962 includes/routes.php:1736 #: includes/routes.php:969 includes/routes.php:1746
msgid "Object has been added." msgid "Object has been added."
msgstr "L'objet a été ajouté." msgstr "L'objet a été ajouté."
#: includes/routes.php:1099 #: includes/routes.php:1106
msgid "My account" msgid "My account"
msgstr "Mon compte" msgstr "Mon compte"
#: includes/routes.php:1162 includes/routes.php:1908 #: includes/routes.php:1169 includes/routes.php:1918
msgid "The object has been partially modified." msgid "The object has been partially modified."
msgstr "L'objet a été partiellement modifié." msgstr "L'objet a été partiellement modifié."
#: includes/routes.php:1165 includes/routes.php:1911 #: includes/routes.php:1172 includes/routes.php:1921
msgid "The object has been modified successfully." msgid "The object has been modified successfully."
msgstr "L'objet a bien été modifié." msgstr "L'objet a bien été modifié."
#: includes/routes.php:1280 includes/routes.php:1951 #: includes/routes.php:1288 includes/routes.php:1961
msgid "%{objectname} has been successfully deleted." msgid "%{objectname} has been successfully deleted."
msgstr "%{objectname} a bien été supprimé." msgstr "%{objectname} a bien été supprimé."
#: includes/routes.php:1289 #: includes/routes.php:1297
msgid "Deleting : %{objectname}" msgid "Deleting : %{objectname}"
msgstr "Suppression : %{objectname}" msgstr "Suppression : %{objectname}"
#: includes/routes.php:1290 #: includes/routes.php:1298
msgid "Do you really want to delete <strong>%{displayName}</strong> ?" msgid "Do you really want to delete <strong>%{displayName}</strong> ?"
msgstr "Voulez-vous vraiment supprimer <strong>%{displayName}</strong> ?" msgstr "Voulez-vous vraiment supprimer <strong>%{displayName}</strong> ?"
#: includes/routes.php:1400 #: includes/routes.php:1409
msgid "" msgid ""
"The custom action %{customAction} have been successfully execute on " "The custom action %{customAction} have been successfully execute on "
"%{objectname}." "%{objectname}."
@ -3613,6 +3657,11 @@ msgstr "Format"
msgid "Global search" msgid "Global search"
msgstr "Recherche globale" msgstr "Recherche globale"
#: templates/default/email_templates.tpl:9
#: templates/default/email_template.tpl:12
msgid "HTML content"
msgstr "Contenu HTML"
#: templates/default/import.tpl:148 #: templates/default/import.tpl:148
msgid "Hook: %(name)" msgid "Hook: %(name)"
msgstr "Déclencheur : %(name)" msgstr "Déclencheur : %(name)"
@ -3654,7 +3703,7 @@ msgstr "Message"
msgid "Messages" msgid "Messages"
msgstr "Messages" msgstr "Messages"
#: templates/default/viewSearch.tpl:113 #: templates/default/viewSearch.tpl:128
msgid "Nb / page :" msgid "Nb / page :"
msgstr "Nb / page :" msgstr "Nb / page :"
@ -3662,6 +3711,10 @@ msgstr "Nb / page :"
msgid "No access log found for this object." msgid "No access log found for this object."
msgstr "Aucun log d'accès trouvé pour cet objet." msgstr "Aucun log d'accès trouvé pour cet objet."
#: templates/default/email_templates.tpl:23
msgid "No existing email template."
msgstr "Aucun modèle de courriel existant."
#: templates/default/LSform_view.tpl:34 #: templates/default/LSform_view.tpl:34
msgid "No field." msgid "No field."
msgstr "Aucun champ." msgstr "Aucun champ."
@ -3674,6 +3727,26 @@ msgstr "Aucun objet importé"
msgid "No value" msgid "No value"
msgstr "Aucune valeur" msgstr "Aucune valeur"
#: templates/default/email_template.tpl:30
msgid ""
"No writable path to save your changes on the HTML message of this template."
msgstr ""
"Aucun emplacement accessible en écriture pour enregistrer vos modifications "
"sur le contenu HTML de ce modèle."
#: templates/default/email_template.tpl:25
msgid "No writable path to save your changes on the subject of this template."
msgstr ""
"Aucun emplacement accessible en écriture pour enregistrer vos modifications "
"sur le sujet de ce modèle."
#: templates/default/email_template.tpl:35
msgid ""
"No writable path to save your changes on the text message of this template."
msgstr ""
"Aucun emplacement accessible en écriture pour enregistrer vos modifications "
"sur le contenu texte de ce modèle."
#: templates/default/import.tpl:45 #: templates/default/import.tpl:45
msgid "Object %(idx)" msgid "Object %(idx)"
msgstr "Objet %(idx)" msgstr "Objet %(idx)"
@ -3755,14 +3828,29 @@ msgstr "Résultat"
msgid "Right inherited from all connected users profile" msgid "Right inherited from all connected users profile"
msgstr "Droit hérité du profile \"Tous les utilisateurs connectés\"" msgstr "Droit hérité du profile \"Tous les utilisateurs connectés\""
#: templates/default/email_template.tpl:40
msgid "Save"
msgstr "Enregistrer"
#: templates/default/base_connected.tpl:6 #: templates/default/base_connected.tpl:6
msgid "Show/hide menu" msgid "Show/hide menu"
msgstr "Afficher/cacher le menu" msgstr "Afficher/cacher le menu"
#: templates/default/LSmail.tpl:21 #: templates/default/email_templates.tpl:8
#: templates/default/email_template.tpl:9
#: templates/default/email_template.tpl:22 templates/default/LSmail.tpl:21
msgid "Subject" msgid "Subject"
msgstr "Sujet" msgstr "Sujet"
#: templates/default/email_templates.tpl:7
msgid "Template name"
msgstr "Nom du modèle"
#: templates/default/email_templates.tpl:10
#: templates/default/email_template.tpl:15
msgid "Text content"
msgstr "Contenu texte"
#: templates/default/LSaccessRightsMatrixView.tpl:58 #: templates/default/LSaccessRightsMatrixView.tpl:58
msgid "Their relations with other objects" msgid "Their relations with other objects"
msgstr "Leurs relations avec les autres objets" msgstr "Leurs relations avec les autres objets"
@ -3804,3 +3892,12 @@ msgstr "événement(s) trouvé(s) pour cet objet."
#: templates/default/import.tpl:27 templates/default/import.tpl:33 #: templates/default/import.tpl:27 templates/default/import.tpl:33
msgid "no" msgid "no"
msgstr "non" msgstr "non"
#~ msgid "HTML body"
#~ msgstr "Corps HTML"
#~ msgid "HTML"
#~ msgstr "HTML"
#~ msgid "Text"
#~ msgstr "Texte"

View file

@ -170,27 +170,51 @@ msgid "ExportSearchResultAsCSV Error : An error occured writing a CSV row."
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:27 #: includes/addons/LSaddons.mail.php:27
msgid "MAIL Support : Pear::MAIL is missing." msgid "MAIL Support: Pear::MAIL is missing."
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:30 #: includes/addons/LSaddons.mail.php:30
msgid "MAIL Support : Pear::MAIL_MIME is missing." msgid "MAIL Support: Pear::MAIL_MIME is missing."
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:35 #: includes/addons/LSaddons.mail.php:33
msgid "MAIL Error : %{msg}" msgid "MAIL Support: Html2Text\\Html2Text is missing."
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:39 #: includes/addons/LSaddons.mail.php:38
msgid "MAIL : Error sending your email" msgid "MAIL Error: %{msg}"
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:125 #: includes/addons/LSaddons.mail.php:41
msgid "MAIL: Error sending your email"
msgstr ""
#: includes/addons/LSaddons.mail.php:44
msgid "MAIL: Unknown template %{name}."
msgstr ""
#: includes/addons/LSaddons.mail.php:47
msgid "MAIL: Template %{name} is incomplete."
msgstr ""
#: includes/addons/LSaddons.mail.php:50
msgid "MAIL: No writable place to save your changes on this template."
msgstr ""
#: includes/addons/LSaddons.mail.php:53
msgid "MAIL: An error occured saving your changes on this template."
msgstr ""
#: includes/addons/LSaddons.mail.php:158 includes/addons/LSaddons.mail.php:568
msgid "Email templates"
msgstr ""
#: includes/addons/LSaddons.mail.php:206
#, php-format #, php-format
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>" msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:126 #: includes/addons/LSaddons.mail.php:207
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -199,18 +223,38 @@ msgid ""
"Mail initialy intended for %s." "Mail initialy intended for %s."
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:156 #: includes/addons/LSaddons.mail.php:235
#, php-format #, php-format
msgid "<p><small>%s: %s</small></p>" msgid "<p><small>%s: %s</small></p>"
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:157 #: includes/addons/LSaddons.mail.php:236
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
"%s: %s" "%s: %s"
msgstr "" msgstr ""
#: includes/addons/LSaddons.mail.php:458
msgid "An exception occured forging message from email template '%{template}'"
msgstr ""
#: includes/addons/LSaddons.mail.php:498
msgid "Email template: %{name}"
msgstr ""
#: includes/addons/LSaddons.mail.php:508 includes/addons/LSaddons.mail.php:524
#: includes/addons/LSaddons.mail.php:542
msgid "Your changes have been saved."
msgstr ""
#: includes/addons/LSaddons.mail.php:560
#: includes/addons/LSaddons.showSupportInfo.php:78
#: includes/addons/LSaddons.accesslog.php:248
#: includes/addons/LSaddons.showTechInfo.php:117
msgid "Go back"
msgstr ""
#: includes/addons/LSaddons.phpldapadmin.php:27 #: includes/addons/LSaddons.phpldapadmin.php:27
msgid "PhpLdapAdmin Support : The constant %{const} is not defined." msgid "PhpLdapAdmin Support : The constant %{const} is not defined."
msgstr "" msgstr ""
@ -227,12 +271,6 @@ msgstr ""
msgid "Download" msgid "Download"
msgstr "" msgstr ""
#: includes/addons/LSaddons.showSupportInfo.php:78
#: includes/addons/LSaddons.accesslog.php:248
#: includes/addons/LSaddons.showTechInfo.php:117
msgid "Go back"
msgstr ""
#: includes/addons/LSaddons.dyngroup.php:27 #: includes/addons/LSaddons.dyngroup.php:27
msgid "Dynamic groups support: The constant %{const} is not defined." msgid "Dynamic groups support: The constant %{const} is not defined."
msgstr "" msgstr ""
@ -328,8 +366,8 @@ msgstr ""
#: includes/class/class.LSrelation.php:679 includes/class/class.LSform.php:346 #: includes/class/class.LSrelation.php:679 includes/class/class.LSform.php:346
#: includes/class/class.LSformElement_select_object.php:75 #: includes/class/class.LSformElement_select_object.php:75
#: includes/class/class.LSformElement_select_object.php:91 #: includes/class/class.LSformElement_select_object.php:91
#: includes/class/class.LSsearchEntry.php:237 includes/routes.php:1068 #: includes/class/class.LSsearchEntry.php:237 includes/routes.php:1075
#: includes/routes.php:1212 #: includes/routes.php:1219
msgid "Delete" msgid "Delete"
msgstr "" msgstr ""
@ -342,8 +380,8 @@ msgstr ""
#: includes/class/class.LSrelation.php:736 #: includes/class/class.LSrelation.php:736
#: includes/class/class.LSformElement_select_object.php:74 #: includes/class/class.LSformElement_select_object.php:74
#: includes/class/class.LSformElement_supannLabeledValue.php:90 #: includes/class/class.LSformElement_supannLabeledValue.php:90
#: includes/class/class.LSsearchEntry.php:221 includes/routes.php:1052 #: includes/class/class.LSsearchEntry.php:221 includes/routes.php:1059
#: includes/routes.php:1220 includes/routes.php:1305 includes/routes.php:1451 #: includes/routes.php:1227 includes/routes.php:1313 includes/routes.php:1460
msgid "Modify" msgid "Modify"
msgstr "" msgstr ""
@ -351,7 +389,7 @@ msgstr ""
msgid "Modify RDN" msgid "Modify RDN"
msgstr "" msgstr ""
#: includes/addons/LSaddons.accesslog.php:35 includes/routes.php:517 #: includes/addons/LSaddons.accesslog.php:35 includes/routes.php:521
#: templates/default/select.tpl:28 templates/default/global_search.tpl:6 #: templates/default/select.tpl:28 templates/default/global_search.tpl:6
msgid "Search" msgid "Search"
msgstr "" msgstr ""
@ -379,7 +417,7 @@ msgstr ""
#: includes/addons/LSaddons.accesslog.php:243 #: includes/addons/LSaddons.accesslog.php:243
#: includes/class/class.LSsession.php:1875 includes/routes.php:157 #: includes/class/class.LSsession.php:1875 includes/routes.php:157
#: includes/routes.php:474 templates/default/select.tpl:29 #: includes/routes.php:478 templates/default/select.tpl:29
msgid "Refresh" msgid "Refresh"
msgstr "" msgstr ""
@ -779,7 +817,7 @@ msgstr ""
#: includes/class/class.LSconfirmBox.php:37 #: includes/class/class.LSconfirmBox.php:37
#: includes/class/class.LSsmoothbox.php:39 includes/class/class.LSform.php:175 #: includes/class/class.LSsmoothbox.php:39 includes/class/class.LSform.php:175
#: includes/routes.php:638 includes/routes.php:1292 includes/routes.php:1438 #: includes/routes.php:645 includes/routes.php:1300 includes/routes.php:1447
#: templates/default/recoverpassword.tpl:21 #: templates/default/recoverpassword.tpl:21
msgid "Validate" msgid "Validate"
msgstr "" msgstr ""
@ -1915,8 +1953,8 @@ msgstr ""
msgid "No object." msgid "No object."
msgstr "" msgstr ""
#: includes/class/class.LSrelation.php:747 includes/routes.php:456 #: includes/class/class.LSrelation.php:747 includes/routes.php:460
#: includes/routes.php:997 #: includes/routes.php:1004
msgid "New" msgid "New"
msgstr "" msgstr ""
@ -2113,11 +2151,11 @@ msgid ""
"support." "support."
msgstr "" msgstr ""
#: includes/class/class.LSform.php:327 includes/routes.php:634 #: includes/class/class.LSform.php:327 includes/routes.php:641
msgid "Do you really want to execute custom action %{title} on this search ?" msgid "Do you really want to execute custom action %{title} on this search ?"
msgstr "" msgstr ""
#: includes/class/class.LSform.php:333 includes/routes.php:1432 #: includes/class/class.LSform.php:333 includes/routes.php:1441
msgid "" msgid ""
"Do you really want to execute custom action %{customAction} on " "Do you really want to execute custom action %{customAction} on "
"%{objectname} ?" "%{objectname} ?"
@ -2307,8 +2345,8 @@ msgstr ""
msgid "Display RSS stack." msgid "Display RSS stack."
msgstr "" msgstr ""
#: includes/class/class.LSattr_ldap_password.php:108 includes/routes.php:587 #: includes/class/class.LSattr_ldap_password.php:108 includes/routes.php:594
#: includes/routes.php:1379 #: includes/routes.php:1388
msgid "undefined" msgid "undefined"
msgstr "" msgstr ""
@ -2755,12 +2793,12 @@ msgstr ""
msgid "Unknown error : %{error}" msgid "Unknown error : %{error}"
msgstr "" msgstr ""
#: includes/class/class.LSsearchEntry.php:213 includes/routes.php:1204 #: includes/class/class.LSsearchEntry.php:213 includes/routes.php:1211
#: includes/routes.php:1297 includes/routes.php:1443 #: includes/routes.php:1305 includes/routes.php:1452
msgid "View" msgid "View"
msgstr "" msgstr ""
#: includes/class/class.LSsearchEntry.php:229 includes/routes.php:1060 #: includes/class/class.LSsearchEntry.php:229 includes/routes.php:1067
msgid "Copy" msgid "Copy"
msgstr "" msgstr ""
@ -2786,64 +2824,64 @@ msgstr ""
msgid "You must provide pattern for global search." msgid "You must provide pattern for global search."
msgstr "" msgstr ""
#: includes/routes.php:462 includes/routes.php:818 #: includes/routes.php:466 includes/routes.php:825
msgid "Import" msgid "Import"
msgstr "" msgstr ""
#: includes/routes.php:467 includes/routes.php:884 #: includes/routes.php:471 includes/routes.php:891
msgid "Export" msgid "Export"
msgstr "" msgstr ""
#: includes/routes.php:479 #: includes/routes.php:483
msgid "Reset" msgid "Reset"
msgstr "" msgstr ""
#: includes/routes.php:518 templates/default/select.tpl:31 #: includes/routes.php:522 templates/default/select.tpl:31
msgid "Approximative search" msgid "Approximative search"
msgstr "" msgstr ""
#: includes/routes.php:519 templates/default/select.tpl:32 #: includes/routes.php:523 templates/default/select.tpl:32
msgid "Recursive search" msgid "Recursive search"
msgstr "" msgstr ""
#: includes/routes.php:608 #: includes/routes.php:615
msgid "" msgid ""
"The custom action %{title} have been successfully execute on this search." "The custom action %{title} have been successfully execute on this search."
msgstr "" msgstr ""
#: includes/routes.php:956 #: includes/routes.php:963
msgid "Data entry form" msgid "Data entry form"
msgstr "" msgstr ""
#: includes/routes.php:962 includes/routes.php:1736 #: includes/routes.php:969 includes/routes.php:1746
msgid "Object has been added." msgid "Object has been added."
msgstr "" msgstr ""
#: includes/routes.php:1099 #: includes/routes.php:1106
msgid "My account" msgid "My account"
msgstr "" msgstr ""
#: includes/routes.php:1162 includes/routes.php:1908 #: includes/routes.php:1169 includes/routes.php:1918
msgid "The object has been partially modified." msgid "The object has been partially modified."
msgstr "" msgstr ""
#: includes/routes.php:1165 includes/routes.php:1911 #: includes/routes.php:1172 includes/routes.php:1921
msgid "The object has been modified successfully." msgid "The object has been modified successfully."
msgstr "" msgstr ""
#: includes/routes.php:1280 includes/routes.php:1951 #: includes/routes.php:1288 includes/routes.php:1961
msgid "%{objectname} has been successfully deleted." msgid "%{objectname} has been successfully deleted."
msgstr "" msgstr ""
#: includes/routes.php:1289 #: includes/routes.php:1297
msgid "Deleting : %{objectname}" msgid "Deleting : %{objectname}"
msgstr "" msgstr ""
#: includes/routes.php:1290 #: includes/routes.php:1298
msgid "Do you really want to delete <strong>%{displayName}</strong> ?" msgid "Do you really want to delete <strong>%{displayName}</strong> ?"
msgstr "" msgstr ""
#: includes/routes.php:1400 #: includes/routes.php:1409
msgid "" msgid ""
"The custom action %{customAction} have been successfully execute on " "The custom action %{customAction} have been successfully execute on "
"%{objectname}." "%{objectname}."
@ -3104,6 +3142,11 @@ msgstr ""
msgid "Global search" msgid "Global search"
msgstr "" msgstr ""
#: templates/default/email_templates.tpl:9
#: templates/default/email_template.tpl:12
msgid "HTML content"
msgstr ""
#: templates/default/import.tpl:148 #: templates/default/import.tpl:148
msgid "Hook: %(name)" msgid "Hook: %(name)"
msgstr "" msgstr ""
@ -3145,7 +3188,7 @@ msgstr ""
msgid "Messages" msgid "Messages"
msgstr "" msgstr ""
#: templates/default/viewSearch.tpl:113 #: templates/default/viewSearch.tpl:128
msgid "Nb / page :" msgid "Nb / page :"
msgstr "" msgstr ""
@ -3153,6 +3196,10 @@ msgstr ""
msgid "No access log found for this object." msgid "No access log found for this object."
msgstr "" msgstr ""
#: templates/default/email_templates.tpl:23
msgid "No existing email template."
msgstr ""
#: templates/default/LSform_view.tpl:34 #: templates/default/LSform_view.tpl:34
msgid "No field." msgid "No field."
msgstr "" msgstr ""
@ -3165,6 +3212,20 @@ msgstr ""
msgid "No value" msgid "No value"
msgstr "" msgstr ""
#: templates/default/email_template.tpl:30
msgid ""
"No writable path to save your changes on the HTML message of this template."
msgstr ""
#: templates/default/email_template.tpl:25
msgid "No writable path to save your changes on the subject of this template."
msgstr ""
#: templates/default/email_template.tpl:35
msgid ""
"No writable path to save your changes on the text message of this template."
msgstr ""
#: templates/default/import.tpl:45 #: templates/default/import.tpl:45
msgid "Object %(idx)" msgid "Object %(idx)"
msgstr "" msgstr ""
@ -3246,14 +3307,29 @@ msgstr ""
msgid "Right inherited from all connected users profile" msgid "Right inherited from all connected users profile"
msgstr "" msgstr ""
#: templates/default/email_template.tpl:40
msgid "Save"
msgstr ""
#: templates/default/base_connected.tpl:6 #: templates/default/base_connected.tpl:6
msgid "Show/hide menu" msgid "Show/hide menu"
msgstr "" msgstr ""
#: templates/default/LSmail.tpl:21 #: templates/default/email_templates.tpl:8
#: templates/default/email_template.tpl:9
#: templates/default/email_template.tpl:22 templates/default/LSmail.tpl:21
msgid "Subject" msgid "Subject"
msgstr "" msgstr ""
#: templates/default/email_templates.tpl:7
msgid "Template name"
msgstr ""
#: templates/default/email_templates.tpl:10
#: templates/default/email_template.tpl:15
msgid "Text content"
msgstr ""
#: templates/default/LSaccessRightsMatrixView.tpl:58 #: templates/default/LSaccessRightsMatrixView.tpl:58
msgid "Their relations with other objects" msgid "Their relations with other objects"
msgstr "" msgstr ""

View file

@ -2,13 +2,13 @@
{block name="content"} {block name="content"}
<div id='LSaccessRightsMatrixView'> <div id='LSaccessRightsMatrixView'>
<h1>{$pagetitle}</h1> <h1>{$pagetitle}</h1>
<ul class="LSaccessRightsMatrixView_tabs"> <ul class="LStabs">
{foreach $LSobjects as $obj => $obj_conf} {foreach $LSobjects as $obj => $obj_conf}
<li{if $LSobject==$obj} class="LSaccessRightsMatrixView_active_tab"{/if}><a href="addon/LSaccessRightsMatrixView/accessRightsMatrix?LSobject={$obj}">{$obj_conf.label}</a></li> <li{if $LSobject==$obj} class="LStabs_active"{/if}><a href="addon/LSaccessRightsMatrixView/accessRightsMatrix?LSobject={$obj}">{$obj_conf.label}</a></li>
{/foreach} {/foreach}
</ul> </ul>
<div class='LSaccessRightsMatrixView_tab_content'> <div class='LStabs_content LStabs_content_active'>
<h2>{$LSobjects[$LSobject]['label']}</h2> <h2>{$LSobjects[$LSobject]['label']}</h2>
<table class="table-header-rotated"> <table class="table-header-rotated">

View file

@ -0,0 +1,43 @@
{extends file='ls:base_connected.tpl'}
{block name="content"}
<h1>{$pagetitle}</h1>
{include file='ls:LSview_actions.tpl'}
<ul class="LStabs">
<li{if $tab=="subject"} class="LStabs_active"{/if}>
<a href="addon/mail/templates?name={$template.name}&tab=subject">{tr msg="Subject"}</a>
</li>
<li{if $tab=="html"} class="LStabs_active"{/if}>
<a href="addon/mail/templates?name={$template.name}&tab=html">{tr msg="HTML content"}</a>
</li>
<li{if $tab=="txt"} class="LStabs_active"{/if}>
<a href="addon/mail/templates?name={$template.name}&tab=txt">{tr msg="Text content"}</a>
</li>
</ul>
<div class='LStabs_content LStabs_content_active'>
<form action="addon/mail/templates?name={$template.name}&tab={$tab}" method="POST">
{if $tab == "subject"}
<input type="text" name="subject" value="{$template.subject|escape:"htmlall"}"
{if !$writable}disabled="disabled" class="LStips"
title="{tr msg="No writable path to save your changes on the subject of this template."}"
{/if}
/>
{elseif $tab == "html"}
<textarea name="html" {if !$writable}disabled="disabled"
title="{tr msg="No writable path to save your changes on the HTML message of this template."}"
{/if}
>{$template.html}</textarea>
{else}
<textarea name="txt" {if !$writable}disabled="disabled" class="LStips"
title="{tr msg="No writable path to save your changes on the text message of this template."}"
{/if}
>{$template.txt}</textarea>
{/if}
<div class="form-footer">
<button type="submit">{tr msg="Save"}</button>
</div>
</form>
</div>
{/block}

View file

@ -0,0 +1,28 @@
{extends file='ls:base_connected.tpl'}
{block name="content"}
<h1>{$pagetitle}</h1>
<table class="LStable">
<thead>
<tr>
<th>{tr msg="Template name"}</th>
<th class="mail_subject">{tr msg="Subject"}</th>
<th class="mail_content">{tr msg="HTML content"}</th>
<th class="mail_content">{tr msg="Text content"}</th>
</tr>
</thead>
<tbody>
{foreach $templates as $name => $tpl}
<tr class="{cycle values=",bis"}">
<td><a href="addon/mail/templates?name={$name|escape:"url"}">{$name}</td>
<td class="mail_subject">{$tpl.subject|escape:"htmlall"}</td>
<td class="mail_content">{$tpl.html|escape:"htmlall"}</td>
<td class="mail_content">{$tpl.txt|escape:"htmlall"}</td>
</tr>
{foreachelse}
<tr>
<td colspan="4" class="center">{tr msg="No existing email template."}</td>
</tr>
{/foreach}
</tbody>
</table>
{/block}