diff --git a/includes/controllers/ApiController.php b/includes/controllers/ApiController.php
index 9b39de333..d13aa97de 100644
--- a/includes/controllers/ApiController.php
+++ b/includes/controllers/ApiController.php
@@ -179,8 +179,13 @@ public function createUser()
$user = $userController->create([
'name' => strval($_POST['name']),
'email' => strval($_POST['email']),
- 'password' => $this->wiki->generateRandomString(30),
+ 'password' => $this->wiki->generateRandomString(30)
]);
+ if (!boolval($this->wiki->config['contact_disable_email_for_password']) && !empty($user)) {
+ $link = $userController->sendPasswordRecoveryEmail($user);
+ } else {
+ $link = '';
+ }
$code = Response::HTTP_OK;
$result = [
'created' => [$user['name']],
@@ -188,6 +193,7 @@ public function createUser()
'name' => $user['name'],
'email' => $user['email'],
'signuptime' => $user['signuptime'],
+ 'link' => $link
],
];
} catch (UserNameAlreadyUsedException $th) {
diff --git a/includes/controllers/UserController.php b/includes/controllers/UserController.php
index 4ba023444..8af9d5f50 100644
--- a/includes/controllers/UserController.php
+++ b/includes/controllers/UserController.php
@@ -103,6 +103,15 @@ public function create(array $newValues): ?User
return null;
}
+
+ public function sendPasswordRecoveryEmail(User $user): string
+ {
+ if ($this->userManager->sendPasswordRecoveryEmail($user, _t('LOGIN_PASSWORD_FOR'))) {
+ return $this->userManager->getUserLink();
+ } else {
+ return "";
+ }
+ }
/**
* update user params
diff --git a/includes/services/UserManager.php b/includes/services/UserManager.php
index 20655ae90..047a70154 100644
--- a/includes/services/UserManager.php
+++ b/includes/services/UserManager.php
@@ -19,6 +19,10 @@
use YesWiki\Security\Controller\SecurityController;
use YesWiki\Wiki;
+if (! function_exists('send_mail')) {
+ require_once 'includes/email.inc.php';
+}
+
class UserManager implements UserProviderInterface, PasswordUpgraderInterface
{
protected $wiki;
@@ -26,9 +30,12 @@ class UserManager implements UserProviderInterface, PasswordUpgraderInterface
protected $passwordHasherFactory;
protected $securityController;
protected $params;
-
+ protected $userlink;
private $getOneByNameCacheResults;
+ private const PW_SALT = 'FBcA';
+ public const KEY_VOCABULARY = 'http://outils-reseaux.org/_vocabulary/key';
+
public function __construct(
Wiki $wiki,
DbService $dbService,
@@ -42,6 +49,7 @@ public function __construct(
$this->securityController = $securityController;
$this->params = $params;
$this->getOneByNameCacheResults = [];
+ $this->userlink = "";
}
private function arrayToUser(?array $userAsArray = null, bool $fillEmpty = false): ?User
@@ -107,6 +115,7 @@ function ($userAsArray) {
*/
public function create($wikiNameOrUser, string $email = '', string $plainPassword = '')
{
+ $this->userlink = '';
if ($this->securityController->isWikiHibernated()) {
throw new Exception(_t('WIKI_IN_HIBERNATION'));
}
@@ -177,6 +186,92 @@ public function create($wikiNameOrUser, string $email = '', string $plainPasswor
);
}
+ /*
+ * Password recovery process (AKA reset password)
+ * 1. A key is generated using name, email alongside with other stuff.
+ * 2. The triple (user's name, specific key "vocabulary",key) is stored in triples table.
+ * 3. In order to update h·er·is password, the user must provided that key.
+ * 4. The new password is accepted only if the key matches with the value in triples table.
+ * 5. The corresponding row is removed from triples table.
+ */
+
+ protected function generateUserLink($user)
+ {
+ // Generate the password recovery key
+ $key = md5($user['name'] . '_' . $user['email'] . random_int(0, 10000) . date('Y-m-d H:i:s') . self::PW_SALT);
+ $tripleStore = $this->wiki->services->get(TripleStore::class);
+ // Erase the previous triples in the trible table
+ $tripleStore->delete($user['name'], self::KEY_VOCABULARY, null, '', '');
+ // Store the (name, vocabulary, key) triple in triples table
+ $tripleStore->create($user['name'], self::KEY_VOCABULARY, $key, '', '');
+
+ // Generate the recovery email
+ $this->userlink = $this->wiki->Href('', 'MotDePassePerdu', [
+ 'a' => 'recover',
+ 'email' => $key,
+ 'u' => base64_encode($user['name'])
+ ], false);
+ }
+
+ /**
+ * Part of the Password recovery process: Handles the password recovery email process.
+ *
+ * Generates the password recovery key
+ * Stores the (name, vocabulary, key) triple in triples table
+ * Generates the recovery email
+ * Sends it
+ *
+ * @return bool True if OK or false if any problems
+ */
+ public function sendPasswordRecoveryEmail(User $user, string $title): bool
+ {
+ $this->generateUserLink($user);
+ $pieces = parse_url($this->params->get('base_url'));
+ $domain = isset($pieces['host']) ? $pieces['host'] : '';
+
+ $message = _t('LOGIN_DEAR') . ' ' . $user['name'] . ",\n";
+ $message .= _t('LOGIN_CLICK_FOLLOWING_LINK') . ' :' . "\n";
+ $message .= '-----------------------' . "\n";
+ $message .= $this->userlink . "\n";
+ $message .= '-----------------------' . "\n";
+ $message .= _t('LOGIN_THE_TEAM') . ' ' . $domain . "\n";
+
+ $subject = $title . ' ' . $domain;
+ // Send the email
+ return send_mail($this->params->get('BAZ_ADRESSE_MAIL_ADMIN'), $this->params->get('BAZ_ADRESSE_MAIL_ADMIN'), $user['email'], $subject, $message);
+ }
+
+ /**
+ * Assessor for userlink field
+ *
+ * @return string
+ */
+ public function getUserLink(): string
+ {
+ return $this->userlink;
+ }
+
+ /**
+ * Assessor for userlink field
+ *
+ * @return string
+ */
+ public function getLastUserLink(User $user): string
+ {
+ $tripleStore = $this->wiki->services->get(TripleStore::class);
+ $key = $tripleStore->getOne($user['name'], self::KEY_VOCABULARY, '', '');
+ if ($key != null) {
+ $this->userlink = $this->wiki->Href('', 'MotDePassePerdu', [
+ 'a' => 'recover',
+ 'email' => $key,
+ 'u' => base64_encode($user['name'])
+ ], false);
+ } else {
+ $this->generateUserLink($user);
+ }
+ return $this->userlink;
+ }
+
/**
* update user params
* for e-mail check is existing e-mail.
@@ -423,4 +518,4 @@ public function logout()
{
$this->wiki->services->get(AuthController::class)->logout();
}
-}
+}
\ No newline at end of file
diff --git a/javascripts/users-table.js b/javascripts/users-table.js
index 3d15e6ce0..3dc85030a 100644
--- a/javascripts/users-table.js
+++ b/javascripts/users-table.js
@@ -18,6 +18,7 @@ const usersTableService = {
success(data) {
const userName = data.user.name
const userEmail = data.user.email
+ const userLink = data.user.link
const { signuptime } = data.user
// append In Datable
const table = $(form).siblings('.dataTables_wrapper').first()
@@ -33,6 +34,9 @@ const usersTableService = {
'',
''
]).draw()
+ if (userLink !== '') {
+ $(`#users-table-link-change-password`).html("
"+userLink+"")
+ }
toastMessage(_t('USERSTABLE_USER_CREATED', { name: userName }), 1100, 'alert alert-success')
},
error(e) {
diff --git a/lang/yeswiki_fr.php b/lang/yeswiki_fr.php
index da3833bcc..906f3fc98 100644
--- a/lang/yeswiki_fr.php
+++ b/lang/yeswiki_fr.php
@@ -213,6 +213,7 @@
'ERROR_ACTION_TRAIL' => 'Erreur action {{trail ...}}',
'INDICATE_THE_PARAMETER_TOC' => 'Indiquez le nom de la page sommaire, paramètre "toc"',
// actions/usersettings.php
+ 'USER_GOTOADMIN' => 'Gestion des utilisateurices',
'USER_SETTINGS' => 'Paramètres utilisateur',
'USER_SIGN_UP' => 'S\'inscrire',
'YOU_ARE_NOW_DISCONNECTED' => 'Vous êtes maintenant déconnecté',
@@ -628,4 +629,4 @@
'REACTION_TITLE_PARAM_NEEDED' => 'Le paramètre \'titre\' est obligatoire',
'REACTION_BAD_IMAGE_FORMAT' => 'Mauvais format d\'image : doit être un fichier, un icône utf8 ou une classe Fontawesome',
'REACTION_NO_IMAGE' => 'Image manquante',
-];
+];
\ No newline at end of file
diff --git a/lang/yeswikijs_en.php b/lang/yeswikijs_en.php
index bc0187441..00f8019d3 100644
--- a/lang/yeswikijs_en.php
+++ b/lang/yeswikijs_en.php
@@ -83,6 +83,7 @@
'MULTIDELETE_END' => 'Deletions finished',
'MULTIDELETE_ERROR' => 'Item {itemId} has not been deleted! {error}',
// javascripts/users-table.js
+ 'LINK_TO_CHANGE_PASSWORD' => "Link to change password",
'USERSTABLE_USER_CREATED' => "User '{name}' created",
'USERSTABLE_USER_NOT_CREATED' => "User '{name}' not created : {error}",
'USERSTABLE_USER_DELETED' => 'The user "{username}" was deleted.',
diff --git a/lang/yeswikijs_fr.php b/lang/yeswikijs_fr.php
index ffdd5c384..7d78d6998 100644
--- a/lang/yeswikijs_fr.php
+++ b/lang/yeswikijs_fr.php
@@ -113,6 +113,7 @@
'MULTIDELETE_ERROR' => "L'élément {itemId} n'a pas été supprimé ! {error}",
// javascripts/users-table.js
+ 'LINK_TO_CHANGE_PASSWORD' => "Lien pour changer le mot de passe",
'USERSTABLE_USER_CREATED' => "Utilisateur '{name}' créé",
'USERSTABLE_USER_NOT_CREATED' => "Utilisateur '{name}' non créé : {error}",
'USERSTABLE_USER_DELETED' => 'L\'utilisateur "{username}" a été supprimé.',
diff --git a/templates/users-table.twig b/templates/users-table.twig
index 64129fbb3..459ea17fa 100644
--- a/templates/users-table.twig
+++ b/templates/users-table.twig
@@ -28,6 +28,7 @@
+
{% endif %}
diff --git a/tools/contact/config.yaml b/tools/contact/config.yaml
index c0525e8d4..3efc09c48 100644
--- a/tools/contact/config.yaml
+++ b/tools/contact/config.yaml
@@ -9,6 +9,7 @@ parameters:
contact_reply_to: '' # default mail to reply to
contact_debug: 0 # debug mode (0 pour rien, 1 pour normal, 2 pour détaillé)
contact_passphrase: '' # passphrase pour envoyer des mail
+ contact_disable_email_for_password: false # pour désactiver l'envoie d'email pour ré-initaliser un mot de passe (ex: LDAP, SSO)
contact_editable_config_params:
- 'contact_use_long_wiki_urls_in_emails'
- 'contact_mail_func'
@@ -19,3 +20,4 @@ parameters:
- 'contact_from'
- 'contact_reply_to'
- 'contact_debug'
+ - 'contact_disable_email_for_password'
diff --git a/tools/contact/lang/contact_fr.inc.php b/tools/contact/lang/contact_fr.inc.php
index 9f0b94905..d466732d6 100755
--- a/tools/contact/lang/contact_fr.inc.php
+++ b/tools/contact/lang/contact_fr.inc.php
@@ -154,4 +154,5 @@
'EDIT_CONFIG_HINT_CONTACT_REPLY_TO' => 'Utilisateur auquel la réponse mail sera envoyée',
'EDIT_CONFIG_HINT_CONTACT_DEBUG' => 'Mode verbeux pour débugguer (mettre 2 pour avoir des informations)',
'EDIT_CONFIG_GROUP_CONTACT' => 'Envoi des e-mails',
+ 'EDIT_CONFIG_HINT_CONTACT_DISABLE_EMAIL_FOR_PASSWORD' => 'Désactiver l\'envoie d\'email pour ré-initaliser un mot de passe (ex: LDAP, SSO)',
];
diff --git a/tools/login/actions/LoginAction.php b/tools/login/actions/LoginAction.php
index b6c1eb514..2578162c4 100644
--- a/tools/login/actions/LoginAction.php
+++ b/tools/login/actions/LoginAction.php
@@ -77,10 +77,9 @@ public function formatArguments($arg)
: $incomingurl
),
- 'lostpasswordurl' => !empty($arg['lostpasswordurl'])
- ? $this->wiki->generateLink($arg['lostpasswordurl'])
- // TODO : check page name for other languages
- : $this->wiki->Href('', 'MotDePassePerdu'),
+ 'lostpasswordurl' => ! boolval($this->params->get('contact_disable_email_for_password')) ? (! empty($arg['lostpasswordurl']) ? $this->wiki->generateLink($arg['lostpasswordurl']) :
+ // TODO : check page name for other languages
+ $this->wiki->Href('', 'MotDePassePerdu')) : '',
'class' => !empty($arg['class']) ? $arg['class'] : '',
'btnclass' => !empty($arg['btnclass']) ? $arg['btnclass'] : '',
@@ -151,7 +150,7 @@ private function renderForm(string $action): string
'email' => ((isset($user['email'])) ? $user['email'] : ((isset($_POST['email'])) ? $_POST['email'] : '')),
'incomingurl' => $this->arguments['incomingurl'],
'signupurl' => $this->arguments['signupurl'],
- 'lostpasswordurl' => $this->arguments['lostpasswordurl'],
+ 'lostpasswordurl' => ! boolval($this->params->get('contact_disable_email_for_password')) ? $this->arguments['lostpasswordurl'] : '',
'profileurl' => $this->arguments['profileurl'],
'userpage' => $this->arguments['userpage'],
'PageMenuUser' => $pageMenuUserContent,
diff --git a/tools/login/actions/LostPasswordAction.php b/tools/login/actions/LostPasswordAction.php
index e26117aa7..fde97cbe4 100644
--- a/tools/login/actions/LostPasswordAction.php
+++ b/tools/login/actions/LostPasswordAction.php
@@ -11,14 +11,8 @@
use YesWiki\Core\YesWikiAction;
use YesWiki\Security\Controller\SecurityController;
-if (!function_exists('send_mail')) {
- require_once 'includes/email.inc.php';
-}
-
class LostPasswordAction extends YesWikiAction
{
- private const PW_SALT = 'FBcA';
- public const KEY_VOCABULARY = 'http://outils-reseaux.org/_vocabulary/key';
protected $authController;
protected $errorType;
@@ -137,7 +131,7 @@ private function manageSubStep(int $subStep): ?User
$user = $this->userManager->getOneByEmail($email);
if (!empty($user)) {
$this->typeOfRendering = 'successPage';
- $this->sendPasswordRecoveryEmail($user);
+ $this->userManager->sendPasswordRecoveryEmail($user, _t('LOGIN_PASSWORD_LOST_FOR'));
} else {
$this->errorType = 'userNotFound';
$this->typeOfRendering = 'userNotFound';
@@ -184,53 +178,6 @@ private function manageSubStep(int $subStep): ?User
return $user ?? null;
}
- /* Password recovery process (AKA reset password)
- 1. A key is generated using name, email alongside with other stuff.
- 2. The triple (user's name, specific key "vocabulary",key) is stored in triples table.
- 3. In order to update h·er·is password, the user must provided that key.
- 4. The new password is accepted only if the key matches with the value in triples table.
- 5. The corresponding row is removed from triples table.
- */
-
- /** Part of the Password recovery process: Handles the password recovery email process.
- *
- * Generates the password recovery key
- * Stores the (name, vocabulary, key) triple in triples table
- * Generates the recovery email
- * Sends it
- *
- * @return bool True if OK or false if any problems
- */
- private function sendPasswordRecoveryEmail(User $user)
- {
- // Generate the password recovery key
- $key = md5($user['name'] . '_' . $user['email'] . random_int(0, 10000) . date('Y-m-d H:i:s') . self::PW_SALT);
- // Erase the previous triples in the trible table
- $this->tripleStore->delete($user['name'], self::KEY_VOCABULARY, null, '', '');
- // Store the (name, vocabulary, key) triple in triples table
- $res = $this->tripleStore->create($user['name'], self::KEY_VOCABULARY, $key, '', '');
-
- // Generate the recovery email
- $passwordLink = $this->wiki->Href('', '', [
- 'a' => 'recover',
- 'email' => $key,
- 'u' => base64_encode($user['name']),
- ], false);
- $pieces = parse_url($this->params->get('base_url'));
- $domain = isset($pieces['host']) ? $pieces['host'] : '';
-
- $message = _t('LOGIN_DEAR') . ' ' . $user['name'] . ",\n";
- $message .= _t('LOGIN_CLICK_FOLLOWING_LINK') . ' :' . "\n";
- $message .= '-----------------------' . "\n";
- $message .= $passwordLink . "\n";
- $message .= '-----------------------' . "\n";
- $message .= _t('LOGIN_THE_TEAM') . ' ' . $domain . "\n";
-
- $subject = _t('LOGIN_PASSWORD_LOST_FOR') . ' ' . $domain;
- // Send the email
- return send_mail($this->params->get('BAZ_ADRESSE_MAIL_ADMIN'), $this->params->get('BAZ_ADRESSE_MAIL_ADMIN'), $user['email'], $subject, $message);
- }
-
/** Part of the Password recovery process: sets the password to a new value if given the the proper recovery key (sent in a recovery email).
*
* In order to update h·er·is password, the user provides a key (sent using sendPasswordRecoveryEmail())
@@ -262,7 +209,7 @@ private function resetPassword(string $userName, string $key, string $password)
}
$this->authController->setPassword($user, $password);
// Was able to update password => Remove the key from triples table
- $this->tripleStore->delete($user['name'], self::KEY_VOCABULARY, $key, '', '');
+ $this->tripleStore->delete($user['name'], UserManager::KEY_VOCABULARY, $key, '', '');
return true;
}
@@ -282,7 +229,7 @@ private function resetPassword(string $userName, string $key, string $password)
private function checkEmailKey(string $hash, string $user): bool
{
// Pas de detournement possible car utilisation de _vocabulary/key ....
- return !is_null($this->tripleStore->exist($user, self::KEY_VOCABULARY, $hash, '', ''));
+ return !is_null($this->tripleStore->exist($user, UserManager::KEY_VOCABULARY, $hash, '', ''));
}
/* End of Password recovery process (AKA reset password) */
}
diff --git a/tools/login/actions/UserSettingsAction.php b/tools/login/actions/UserSettingsAction.php
index a778474dd..d4385f82b 100644
--- a/tools/login/actions/UserSettingsAction.php
+++ b/tools/login/actions/UserSettingsAction.php
@@ -43,6 +43,7 @@ class UserSettingsAction extends YesWikiAction
private $referrer;
private $wantedEmail;
private $wantedUserName;
+ private $userlink;
public function formatArguments($arg)
{
@@ -60,6 +61,11 @@ public function run()
$this->errorPasswordChange = '';
$this->referrer = '';
$user = $this->getUser($_GET ?? []);
+ if (!boolval($this->wiki->config['contact_disable_email_for_password']) && !empty($user)) {
+ $this->userlink = $this->userManager->getLastUserLink($user);
+ } else {
+ $this->userlink = '';
+ }
$this->doPrerenderingActions($_POST ?? [], $user);
@@ -159,6 +165,7 @@ private function displayForm(?User $user = null)
'referrer' => $this->referrer,
'user' => $user,
'userLoggedIn' => $this->userLoggedIn,
+ 'userlink' => $this->userlink
]);
} else {
$captcha = $this->securityController->renderCaptchaField();
@@ -178,6 +185,7 @@ private function displayForm(?User $user = null)
'name' => $this->wantedUserName,
'email' => $this->wantedEmail,
'captcha' => $captcha,
+ 'userlink' => ''
]);
}
}
@@ -226,6 +234,12 @@ private function update(array $post, User $user)
$user,
$sanitizedPost
);
+ $this->userlink = '';
+ if (!boolval($this->wiki->config['contact_disable_email_for_password'])) {
+ if ($this->userManager->sendPasswordRecoveryEmail($user, _t('LOGIN_PASSWORD_FOR'))) {
+ $this->userlink = $this->userManager->getUserLink();
+ }
+ }
$user = $this->userManager->getOneByEmail($sanitizedPost['email']);
@@ -277,7 +291,7 @@ private function changePassword(?User $user, array $post)
$this->wiki->Redirect($this->wiki->href());
} catch (TokenNotFoundException $th) {
$this->errorPasswordChange = _t('USERSETTINGS_PASSWORD_NOT_CHANGED') . ' ' . $th->getMessage();
- } catch (BadFormatPasswordException|Throwable $ex) {
+ } catch (BadFormatPasswordException | Throwable $ex) {
// Something when wrong when updating the user in DB
$this->errorPasswordChange = _t('USERSETTINGS_PASSWORD_NOT_CHANGED') . ' ' . $ex->getMessage();
}
@@ -303,8 +317,10 @@ private function signup(array $post)
$password = isset($post['password']) && is_string($post['password']) ? $post['password'] : '';
if (!empty($emptyInputsParametersNames)) {
$this->error = str_replace('{parameters}', implode(',', $emptyInputsParametersNames), _t('USERSETTINGS_SIGNUP_MISSING_INPUT'));
- } elseif ($this->authController->checkPasswordValidateRequirements($password) &&
- $post['confpassword'] !== $password) {
+ } elseif (
+ $this->authController->checkPasswordValidateRequirements($password) &&
+ $post['confpassword'] !== $password
+ ) {
$this->error = _t('USER_PASSWORDS_NOT_IDENTICAL') . '.';
} else { // Password is correct
$_POST['submit'] = SecurityController::EDIT_PAGE_SUBMIT_VALUE;
@@ -346,4 +362,4 @@ private function checklogged(array $post)
{
$this->error = _t('USER_MUST_ACCEPT_COOKIES_TO_GET_CONNECTED') . '.';
}
-}
+}
\ No newline at end of file
diff --git a/tools/login/lang/login_en.inc.php b/tools/login/lang/login_en.inc.php
index 85b4e28c9..07dea20e4 100644
--- a/tools/login/lang/login_en.inc.php
+++ b/tools/login/lang/login_en.inc.php
@@ -37,7 +37,9 @@
'LOGIN_DEAR' => 'Dear',
'LOGIN_CLICK_FOLLOWING_LINK' => 'Click on the link below to reset your password',
'LOGIN_THE_TEAM' => 'The team from',
+ 'LOGIN_PASSWORD_FOR' => 'Password for',
'LOGIN_PASSWORD_LOST_FOR' => 'Lost password for',
+ 'LAST_LINK_TO_CHANGE_PASSWORD' => 'Last link to change password',
// 'LOGIN_NO_SIGNUP_IN_THIS_PERIOD' => 'Il n\'y a pas d\'inscription pour cette période.',
// actions/login.php
// 'LOGIN_COOKIES_ERROR' => 'Vous devez accepter les cookies pour pouvoir vous connecter.',
diff --git a/tools/login/lang/login_fr.inc.php b/tools/login/lang/login_fr.inc.php
index 3a90550b0..2b53fa414 100755
--- a/tools/login/lang/login_fr.inc.php
+++ b/tools/login/lang/login_fr.inc.php
@@ -37,10 +37,12 @@
'LOGIN_DEAR' => 'Cher',
'LOGIN_CLICK_FOLLOWING_LINK' => 'Cliquez sur le lien suivant pour ré-initialiser votre mot de passe',
'LOGIN_THE_TEAM' => 'L\'équipe de',
+ 'LOGIN_PASSWORD_FOR' => 'Mot de passe pour',
'LOGIN_PASSWORD_LOST_FOR' => 'Mot de passe perdu pour',
'LOGIN_NO_SIGNUP_IN_THIS_PERIOD' => 'Il n\'y a pas d\'inscription pour cette période.',
'LOGIN_MY_OPTIONS' => 'Mes options',
'LOGIN_MY_CONTENTS' => 'Mes contenus',
+ 'LINK_TO_CHANGE_PASSWORD' => 'Lien pour changer le mot de passe',
// actions/login.php
'LOGIN_COOKIES_ERROR' => 'Vous devez accepter les cookies pour pouvoir vous connecter.',
diff --git a/tools/login/templates/usersettings.twig b/tools/login/templates/usersettings.twig
index e532879e8..1be274aeb 100644
--- a/tools/login/templates/usersettings.twig
+++ b/tools/login/templates/usersettings.twig
@@ -1,4 +1,5 @@
-{{ _t('USER_SETTINGS') }}{{ adminIsActing ? ' — ' ~ user.name : ''}}
+{% if adminIsActing %} {{ _t('USER_GOTOADMIN')}}{% endif %}
+{{ _t('USER_SETTINGS') }}{% if adminIsActing %} — {{user.name}}{% endif %}
{% if errorUpdate is not empty %}
{{ errorUpdate }}
@@ -25,6 +26,14 @@
#}
+{% if userlink is not empty %}
+
+{% endif %}
-{% endif %}
+{% endif %}
\ No newline at end of file