diff options
29 files changed, 819 insertions, 347 deletions
diff --git a/app/Controller/Config.php b/app/Controller/Config.php index 48bfb9cf..a364c5f4 100644 --- a/app/Controller/Config.php +++ b/app/Controller/Config.php @@ -19,27 +19,15 @@ class Config extends Base { $this->response->html($this->template->layout('config_index', array( 'db_size' => $this->config->getDatabaseSize(), - 'user' => $_SESSION['user'], - 'user_projects' => $this->project->getAvailableList($this->acl->getUserId()), - 'notifications' => $this->notification->readSettings($this->acl->getUserId()), 'languages' => $this->config->getLanguages(), 'values' => $this->config->getAll(), 'errors' => array(), 'menu' => 'config', 'title' => t('Settings'), 'timezones' => $this->config->getTimezones(), - 'remember_me_sessions' => $this->authentication->backend('rememberMe')->getAll($this->acl->getUserId()), - 'last_logins' => $this->lastLogin->getAll($this->acl->getUserId()), ))); } - public function notifications() - { - $values = $this->request->getValues(); - $this->notification->saveSettings($this->acl->getUserId(), $values); - $this->response->redirect('?controller=config#notifications'); - } - /** * Validate and save settings * @@ -64,17 +52,12 @@ class Config extends Base $this->response->html($this->template->layout('config_index', array( 'db_size' => $this->config->getDatabaseSize(), - 'user' => $_SESSION['user'], - 'user_projects' => $this->project->getAvailableList($this->acl->getUserId()), - 'notifications' => $this->notification->readSettings($this->acl->getUserId()), 'languages' => $this->config->getLanguages(), 'values' => $values, 'errors' => $errors, 'menu' => 'config', 'title' => t('Settings'), 'timezones' => $this->config->getTimezones(), - 'remember_me_sessions' => $this->authentication->backend('rememberMe')->getAll($this->acl->getUserId()), - 'last_logins' => $this->lastLogin->getAll($this->acl->getUserId()), ))); } @@ -115,16 +98,4 @@ class Config extends Base $this->session->flash(t('All tokens have been regenerated.')); $this->response->redirect('?controller=config'); } - - /** - * Remove a "RememberMe" token - * - * @access public - */ - public function removeRememberMeToken() - { - $this->checkCSRFParam(); - $this->authentication->backend('rememberMe')->remove($this->request->getIntegerParam('id')); - $this->response->redirect('?controller=config&action=index#remember-me'); - } } diff --git a/app/Controller/User.php b/app/Controller/User.php index 0bb7aec1..25402f03 100644 --- a/app/Controller/User.php +++ b/app/Controller/User.php @@ -65,6 +65,48 @@ class User extends Base } /** + * Common layout for project views + * + * @access private + * @param string $template Template name + * @param array $params Template parameters + * @return string + */ + private function layout($template, array $params) + { + $content = $this->template->load($template, $params); + $params['user_content_for_layout'] = $content; + $params['menu'] = 'users'; + + if (isset($params['user'])) { + $params['title'] = $params['user']['name'] ?: $params['user']['username']; + } + + return $this->template->layout('user_layout', $params); + } + + /** + * Common method to get the user + * + * @access private + * @return array + */ + private function getUser() + { + $user = $this->user->getById($this->request->getIntegerParam('user_id'), true); + + if (! $user) { + $this->notfound(); + } + + if ($this->acl->isRegularUser() && $this->acl->getUserId() != $user['id']) { + $this->forbidden(); + } + + return $user; + } + + /** * List all users * * @access public @@ -131,91 +173,180 @@ class User extends Base } /** - * Display a form to edit a user + * Display user information * * @access public */ - public function edit() + public function show() { - $user = $this->user->getById($this->request->getIntegerParam('user_id')); + $user = $this->getUser(); + $this->response->html($this->layout('user_show', array( + 'projects' => $this->project->getAvailableList($user['id']), + 'user' => $user, + ))); + } - if (! $user) $this->notfound(); + /** + * Display last connections + * + * @access public + */ + public function last() + { + $user = $this->getUser(); + $this->response->html($this->layout('user_last', array( + 'last_logins' => $this->lastLogin->getAll($user['id']), + 'user' => $user, + ))); + } - if ($this->acl->isRegularUser() && $this->acl->getUserId() != $user['id']) { - $this->forbidden(); - } + /** + * Display user sessions + * + * @access public + */ + public function sessions() + { + $user = $this->getUser(); + $this->response->html($this->layout('user_sessions', array( + 'sessions' => $this->authentication->backend('rememberMe')->getAll($user['id']), + 'user' => $user, + ))); + } - unset($user['password']); + /** + * Remove a "RememberMe" token + * + * @access public + */ + public function removeSession() + { + $this->checkCSRFParam(); + $user = $this->getUser(); + $this->authentication->backend('rememberMe')->remove($this->request->getIntegerParam('id')); + $this->response->redirect('?controller=user&action=sessions&user_id='.$user['id']); + } - $this->response->html($this->template->layout('user_edit', array( - 'projects' => $this->project->filterListByAccess($this->project->getList(), $user['id']), - 'errors' => array(), - 'values' => $user, - 'menu' => 'users', - 'title' => t('Edit user') + /** + * Display user notifications + * + * @access public + */ + public function notifications() + { + $user = $this->getUser(); + + if ($this->request->isPost()) { + $values = $this->request->getValues(); + $this->notification->saveSettings($user['id'], $values); + $this->session->flash(t('User updated successfully.')); + $this->response->redirect('?controller=user&action=notifications&user_id='.$user['id']); + } + + $this->response->html($this->layout('user_notifications', array( + 'projects' => $this->project->getAvailableList($user['id']), + 'notifications' => $this->notification->readSettings($user['id']), + 'user' => $user, ))); } /** - * Validate and update a user + * Display external accounts * * @access public */ - public function update() + public function external() { - $values = $this->request->getValues(); + $user = $this->getUser(); + $this->response->html($this->layout('user_external', array( + 'last_logins' => $this->lastLogin->getAll($user['id']), + 'user' => $user, + ))); + } - if ($this->acl->isAdminUser()) { - $values += array('is_admin' => 0); - } - else { + /** + * Password modification + * + * @access public + */ + public function password() + { + $user = $this->getUser(); + $values = array('id' => $user['id']); + $errors = array(); - if ($this->acl->getUserId() != $values['id']) { - $this->forbidden(); - } + if ($this->request->isPost()) { - if (isset($values['is_admin'])) { - unset($values['is_admin']); // Regular users can't be admin - } - } + $values = $this->request->getValues(); + list($valid, $errors) = $this->user->validatePasswordModification($values); - list($valid, $errors) = $this->user->validateModification($values); + if ($valid) { - if ($valid) { + if ($this->user->update($values)) { + $this->session->flash(t('Password modified successfully.')); + } + else { + $this->session->flashError(t('Unable to change the password.')); + } - if ($this->user->update($values)) { - $this->session->flash(t('User updated successfully.')); - $this->response->redirect('?controller=user'); - } - else { - $this->session->flashError(t('Unable to update your user.')); + $this->response->redirect('?controller=user&action=show&user_id='.$user['id']); } } - $this->response->html($this->template->layout('user_edit', array( - 'projects' => $this->project->filterListByAccess($this->project->getList(), $values['id']), - 'errors' => $errors, + $this->response->html($this->layout('user_password', array( 'values' => $values, - 'menu' => 'users', - 'title' => t('Edit user') + 'errors' => $errors, + 'user' => $user, ))); } /** - * Confirmation dialog before to remove a user + * Display a form to edit a user * * @access public */ - public function confirm() + public function edit() { - $user = $this->user->getById($this->request->getIntegerParam('user_id')); + $user = $this->getUser(); + $values = $user; + $errors = array(); + + unset($values['password']); + + if ($this->request->isPost()) { + + $values = $this->request->getValues(); + + if ($this->acl->isAdminUser()) { + $values += array('is_admin' => 0); + } + else { + + if (isset($values['is_admin'])) { + unset($values['is_admin']); // Regular users can't be admin + } + } + + list($valid, $errors) = $this->user->validateModification($values); + + if ($valid) { + + if ($this->user->update($values)) { + $this->session->flash(t('User updated successfully.')); + } + else { + $this->session->flashError(t('Unable to update your user.')); + } - if (! $user) $this->notfound(); + $this->response->redirect('?controller=user&action=show&user_id='.$user['id']); + } + } - $this->response->html($this->template->layout('user_remove', array( + $this->response->html($this->layout('user_edit', array( + 'values' => $values, + 'errors' => $errors, + 'projects' => $this->project->filterListByAccess($this->project->getList(), $user['id']), 'user' => $user, - 'menu' => 'users', - 'title' => t('Remove user') ))); } @@ -226,16 +357,24 @@ class User extends Base */ public function remove() { - $this->checkCSRFParam(); - $user_id = $this->request->getIntegerParam('user_id'); + $user = $this->getUser(); + + if ($this->request->getStringParam('confirmation') === 'yes') { - if ($user_id && $this->user->remove($user_id)) { - $this->session->flash(t('User removed successfully.')); - } else { - $this->session->flashError(t('Unable to remove this user.')); + $this->checkCSRFParam(); + + if ($this->user->remove($user['id'])) { + $this->session->flash(t('User removed successfully.')); + } else { + $this->session->flashError(t('Unable to remove this user.')); + } + + $this->response->redirect('?controller=user'); } - $this->response->redirect('?controller=user'); + $this->response->html($this->layout('user_remove', array( + 'user' => $user, + ))); } /** @@ -263,7 +402,7 @@ class User extends Base $this->session->flashError(t('Unable to link your Google Account.')); } - $this->response->redirect('?controller=user'); + $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); } else if ($this->authentication->backend('google')->authenticate($profile['id'])) { $this->response->redirect('?controller=app'); @@ -297,7 +436,7 @@ class User extends Base $this->session->flashError(t('Unable to unlink your Google Account.')); } - $this->response->redirect('?controller=user'); + $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); } /** @@ -324,7 +463,7 @@ class User extends Base $this->session->flashError(t('Unable to link your GitHub Account.')); } - $this->response->redirect('?controller=user'); + $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); } else if ($this->authentication->backend('gitHub')->authenticate($profile['id'])) { $this->response->redirect('?controller=app'); @@ -361,6 +500,6 @@ class User extends Base $this->session->flashError(t('Unable to unlink your GitHub Account.')); } - $this->response->redirect('?controller=user'); + $this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); } } diff --git a/app/Locales/de_DE/translations.php b/app/Locales/de_DE/translations.php index eaa32aa6..006efe84 100644 --- a/app/Locales/de_DE/translations.php +++ b/app/Locales/de_DE/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => 'Alle Benutzer', 'Username' => 'Benutzername', 'Password' => 'Passwort', - 'Default Project' => 'Standardprojekt', + 'Default project' => 'Standardprojekt', 'Administrator' => 'Administrator', 'Sign in' => 'Anmelden', 'Users' => 'Benutzer', @@ -273,7 +273,7 @@ return array( 'IP address' => 'IP Adresse', 'User agent' => 'User Agent', 'Persistent connections' => 'Bestehende Verbindungen', - 'No session' => 'Keine Sitzung', + 'No session.' => 'Keine Sitzung.', 'Expiration date' => 'Ablaufdatum', 'Remember Me' => 'Angemeldet bleiben', 'Creation date' => 'Erstellungsdatum', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Locales/es_ES/translations.php b/app/Locales/es_ES/translations.php index 93e0dd46..295d6464 100644 --- a/app/Locales/es_ES/translations.php +++ b/app/Locales/es_ES/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => 'Todos los usuarios', 'Username' => 'Nombre de usuario', 'Password' => 'Contraseña', - 'Default Project' => 'Proyecto por defecto', + 'Default project' => 'Proyecto por defecto', 'Administrator' => 'Administrador', 'Sign in' => 'Iniciar sesión', 'Users' => 'Usuarios', @@ -273,7 +273,7 @@ return array( 'IP address' => 'Dirección IP', 'User agent' => 'Agente de usuario', 'Persistent connections' => 'Conexión persistente', - 'No session' => 'No existe sesión', + 'No session.' => 'No existe sesión.', 'Expiration date' => 'Fecha de expiración', 'Remember Me' => 'Recuérdame', 'Creation date' => 'Fecha de creación', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Locales/fi_FI/translations.php b/app/Locales/fi_FI/translations.php index 1d9d8150..d7e929ce 100644 --- a/app/Locales/fi_FI/translations.php +++ b/app/Locales/fi_FI/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => 'Kaikki käyttäjät', 'Username' => 'Käyttäjänimi', 'Password' => 'Salasana', - 'Default Project' => 'Oletusprojekti', + 'Default project' => 'Oletusprojekti', 'Administrator' => 'Ylläpitäjä', 'Sign in' => 'Kirjaudu sisään', 'Users' => 'Käyttäjät', @@ -273,7 +273,7 @@ return array( 'IP address' => 'IP-Osoite', 'User agent' => 'Selain', 'Persistent connections' => 'Voimassa olevat yhteydet', - 'No session' => 'Ei sessioita', + 'No session.' => 'Ei sessioita.', 'Expiration date' => 'Vanhentumispäivä', 'Remember Me' => 'Muista minut', 'Creation date' => 'Luomispäivä', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Locales/fr_FR/translations.php b/app/Locales/fr_FR/translations.php index 147e12f6..230e51db 100644 --- a/app/Locales/fr_FR/translations.php +++ b/app/Locales/fr_FR/translations.php @@ -27,9 +27,9 @@ return array( 'Do you really want to remove this user: "%s"?' => 'Voulez-vous vraiment supprimer cet utilisateur : « %s » ?', 'New user' => 'Ajouter un utilisateur', 'All users' => 'Tous les utilisateurs', - 'Username' => 'Identifiant', + 'Username' => 'Nom d\'utilisateur', 'Password' => 'Mot de passe', - 'Default Project' => 'Projet par défaut', + 'Default project' => 'Projet par défaut', 'Administrator' => 'Administrateur', 'Sign in' => 'Connexion', 'Users' => 'Utilisateurs', @@ -273,7 +273,7 @@ return array( 'IP address' => 'Adresse IP', 'User agent' => 'Agent utilisateur', 'Persistent connections' => 'Connexions persistantes', - 'No session' => 'Aucune session', + 'No session.' => 'Aucune session.', 'Expiration date' => 'Date d\'expiration', 'Remember Me' => 'Connexion automatique', 'Creation date' => 'Date de création', @@ -437,5 +437,33 @@ return array( 'Move the task to another project' => 'Déplacer la tâche vers un autre projet', 'Move to another project' => 'Déplacer vers un autre projet', 'Do you really want to duplicate this task?' => 'Voulez-vous vraiment dupliquer cette tâche ?', - 'Duplicate a task' => 'Dupliquer une tâche' + 'Duplicate a task' => 'Dupliquer une tâche', + 'External accounts' => 'Comptes externes', + 'Account type' => 'Type de compte', + 'Local' => 'Local', + 'Remote' => 'Distant', + 'Enabled' => 'Activé', + 'Disabled' => 'Désactivé', + 'Google account linked' => 'Compte Google attaché', + 'Github account linked' => 'Compte Github attaché', + 'Username:' => 'Nom d\'utilisateur :', + 'Name:' => 'Nom :', + 'Email:' => 'Email :', + 'Default project:' => 'Projet par défaut :', + 'Notifications:' => 'Notifications :', + 'Group:' => 'Groupe :', + 'Regular user' => 'Utilisateur normal', + 'Account type:' => 'Type de compte :', + 'Edit profile' => 'Modifier le profile', + 'Change password' => 'Changer le mot de passe', + 'Password modification' => 'Changement de mot de passe', + 'External authentications' => 'Authentifications externe', + 'Google Account' => 'Compte Google', + 'Github Account' => 'Compte Github', + 'Never connected.' => 'Jamais connecté.', + 'No account linked.' => 'Aucun compte attaché.', + 'Account linked.' => 'Compte attaché.', + 'No external authentication enabled.' => 'Aucune authentication externe activée.', + 'Password modified successfully.' => 'Mot de passe changé avec succès.', + 'Unable to change the password.' => 'Impossible de changer le mot de passe.', ); diff --git a/app/Locales/it_IT/translations.php b/app/Locales/it_IT/translations.php index f313187e..3c5e3ae8 100644 --- a/app/Locales/it_IT/translations.php +++ b/app/Locales/it_IT/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => 'Tutti gli utenti', 'Username' => 'Nome di utente', 'Password' => 'Password', - 'Default Project' => 'Progetto predefinito', + 'Default project' => 'Progetto predefinito', 'Administrator' => 'Amministratore', 'Sign in' => 'Iscriversi', 'Users' => 'Utenti', @@ -273,7 +273,7 @@ return array( 'IP address' => 'Indirizzo IP', 'User agent' => 'Navigatore', 'Persistent connections' => 'Conessioni persistenti', - 'No session' => 'Non essiste sessione', + 'No session.' => 'Non essiste sessione.', 'Expiration date' => 'Data di scadenza', 'Remember Me' => 'Riccordami', 'Creation date' => 'Data di creazione', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Locales/pl_PL/translations.php b/app/Locales/pl_PL/translations.php index 7967a674..f12ec080 100644 --- a/app/Locales/pl_PL/translations.php +++ b/app/Locales/pl_PL/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => 'Wszyscy użytkownicy', 'Username' => 'Nazwa użytkownika', 'Password' => 'Hasło', - 'Default Project' => 'Domyślny projekt', + 'Default project' => 'Domyślny projekt', 'Administrator' => 'Administrator', 'Sign in' => 'Zaloguj', 'Users' => 'Użytkownicy', @@ -273,7 +273,7 @@ return array( 'IP address' => 'Adres IP', 'User agent' => 'Przeglądarka', 'Persistent connections' => 'Stałe połączenia', - 'No session' => 'Brak sesji', + 'No session.' => 'Brak sesji.', 'Expiration date' => 'Data zakończenia', 'Remember Me' => 'Pamiętaj mnie', 'Creation date' => 'Data utworzenia', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Locales/pt_BR/translations.php b/app/Locales/pt_BR/translations.php index f8e68d74..ec67c90a 100644 --- a/app/Locales/pt_BR/translations.php +++ b/app/Locales/pt_BR/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => 'Todos os usuários', 'Username' => 'Nome do usuário', 'Password' => 'Senha', - 'Default Project' => 'Projeto default', + 'Default project' => 'Projeto default', 'Administrator' => 'Administrador', 'Sign in' => 'Logar', 'Users' => 'Usuários', @@ -273,7 +273,7 @@ return array( 'IP address' => 'Endereço IP', 'User agent' => 'Agente usuário', 'Persistent connections' => 'Conexões persistentes', - 'No session' => 'Sem sessão', + 'No session.' => 'Sem sessão.', 'Expiration date' => 'Data de expiração', 'Remember Me' => 'Lembre-se de mim', 'Creation date' => 'Data de criação', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Locales/sv_SE/translations.php b/app/Locales/sv_SE/translations.php index 57a0e29d..55878da5 100644 --- a/app/Locales/sv_SE/translations.php +++ b/app/Locales/sv_SE/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => 'Alla användare', 'Username' => 'Användarnamn', 'Password' => 'Lösenord', - 'Default Project' => 'Standardprojekt', + 'Default project' => 'Standardprojekt', 'Administrator' => 'Administratör', 'Sign in' => 'Logga in', 'Users' => 'Användare', @@ -273,7 +273,7 @@ return array( 'IP address' => 'IP-adress', 'User agent' => 'Användaragent/webbläsare', 'Persistent connections' => 'Beständiga anslutningar', - 'No session' => 'Ingen session', + 'No session.' => 'Ingen session.', 'Expiration date' => 'Förfallodatum', 'Remember Me' => 'Kom ihåg mig', 'Creation date' => 'Skapatdatum', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Locales/zh_CN/translations.php b/app/Locales/zh_CN/translations.php index dcbd3b74..91d5ff49 100644 --- a/app/Locales/zh_CN/translations.php +++ b/app/Locales/zh_CN/translations.php @@ -29,7 +29,7 @@ return array( 'All users' => '所有用户', 'Username' => '用户名', 'Password' => '密码', - 'Default Project' => '默认项目', + 'Default project' => '默认项目', 'Administrator' => '管理员', 'Sign in' => '登录', 'Users' => '用户组', @@ -273,7 +273,7 @@ return array( 'IP address' => 'IP地址', 'User agent' => '用户代理', 'Persistent connections' => '持续连接', - 'No session' => '无会话', + 'No session.' => '无会话', 'Expiration date' => '过期', 'Remember Me' => '记住我', 'Creation date' => '创建日期', @@ -438,4 +438,32 @@ return array( // 'Move to another project' => '', // 'Do you really want to duplicate this task?' => '', // 'Duplicate a task' => '', + // 'External accounts' => '', + // 'Account type' => '', + // 'Local' => '', + // 'Remote' => '', + // 'Enabled' => '', + // 'Disabled' => '', + // 'Google account linked' => '', + // 'Github account linked' => '', + // 'Username:' => '', + // 'Name:' => '', + // 'Email:' => '', + // 'Default project:' => '', + // 'Notifications:' => '', + // 'Group:' => '', + // 'Regular user' => '', + // 'Account type:' => '', + // 'Edit profile' => '', + // 'Change password' => '', + // 'Password modification' => '', + // 'External authentications' => '', + // 'Google Account' => '', + // 'Github Account' => '', + // 'Never connected.' => '', + // 'No account linked.' => '', + // 'Account linked.' => '', + // 'No external authentication enabled.' => '', + // 'Password modified successfully.' => '', + // 'Unable to change the password.' => '', ); diff --git a/app/Model/Acl.php b/app/Model/Acl.php index f2b287be..a7620731 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -32,8 +32,7 @@ class Acl extends Base 'app' => array('index'), 'board' => array('index', 'show', 'assign', 'assigntask', 'save', 'check'), 'project' => array('tasks', 'index', 'forbidden', 'search', 'export', 'show'), - 'user' => array('index', 'edit', 'update', 'forbidden', 'logout', 'index', 'unlinkgoogle', 'unlinkgithub'), - 'config' => array('index', 'removeremembermetoken', 'notifications'), + 'user' => array('index', 'edit', 'forbidden', 'logout', 'index', 'show', 'external', 'unlinkgoogle', 'unlinkgithub', 'sessions', 'removesession', 'last', 'notifications', 'password'), 'comment' => array('create', 'save', 'confirm', 'remove', 'update', 'edit', 'forbidden'), 'file' => array('create', 'save', 'download', 'confirm', 'remove', 'open', 'image'), 'subtask' => array('create', 'save', 'edit', 'update', 'confirm', 'remove'), diff --git a/app/Model/User.php b/app/Model/User.php index d019dfcc..918ecf2a 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -86,7 +86,7 @@ class User extends Base return $this->db ->table(self::TABLE) ->asc('username') - ->columns('id', 'username', 'name', 'email', 'is_admin', 'default_project_id', 'is_ldap_user') + ->columns('id', 'username', 'name', 'email', 'is_admin', 'default_project_id', 'is_ldap_user', 'notifications_enabled', 'google_id', 'github_id') ->findAll(); } @@ -291,17 +291,11 @@ class User extends Base { $v = new Validator($values, array( new Validators\Required('id', t('The user id is required')), - new Validators\Required('username', t('The username is required')), - new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50), - new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'), new Validators\Required('current_password', t('The current password is required')), new Validators\Required('password', t('The password is required')), new Validators\MinLength('password', t('The minimum length is %d characters', 6), 6), new Validators\Required('confirmation', t('The confirmation is required')), new Validators\Equals('password', 'confirmation', t('Passwords don\'t match')), - new Validators\Integer('default_project_id', t('This value must be an integer')), - new Validators\Integer('is_admin', t('This value must be an integer')), - new Validators\Email('email', t('Email address invalid')), )); if ($v->execute()) { diff --git a/app/Templates/config_index.php b/app/Templates/config_index.php index 11662c87..98b8b28d 100644 --- a/app/Templates/config_index.php +++ b/app/Templates/config_index.php @@ -1,143 +1,67 @@ <section id="main"> - <?php if ($user['is_admin']): ?> - <div class="page-header"> - <h2><?= t('Application settings') ?></h2> - </div> - <section> - <form method="post" action="?controller=config&action=save" autocomplete="off"> - - <?= Helper\form_csrf() ?> - - <?= Helper\form_label(t('Language'), 'language') ?> - <?= Helper\form_select('language', $languages, $values, $errors) ?><br/> - - <?= Helper\form_label(t('Timezone'), 'timezone') ?> - <?= Helper\form_select('timezone', $timezones, $values, $errors) ?><br/> - - <?= Helper\form_label(t('Webhook URL for task creation'), 'webhooks_url_task_creation') ?> - <?= Helper\form_text('webhooks_url_task_creation', $values, $errors) ?><br/> - - <?= Helper\form_label(t('Webhook URL for task modification'), 'webhooks_url_task_modification') ?> - <?= Helper\form_text('webhooks_url_task_modification', $values, $errors) ?><br/> - - <div class="form-actions"> - <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> - </div> - </form> - </section> - <?php endif ?> - <div class="page-header"> - <h2><?= t('User settings') ?></h2> + <h2><?= t('Application settings') ?></h2> </div> <section> - <h3 id="notifications"><?= t('Email notifications') ?></h3> - <form method="post" action="?controller=config&action=notifications" autocomplete="off"> + <form method="post" action="?controller=config&action=save" autocomplete="off"> - <?= Helper\form_csrf() ?> + <?= Helper\form_csrf() ?> - <?= Helper\form_checkbox('notifications_enabled', t('Enable email notifications'), '1', $notifications['notifications_enabled'] == 1) ?><br/> + <?= Helper\form_label(t('Language'), 'language') ?> + <?= Helper\form_select('language', $languages, $values, $errors) ?><br/> - <p><?= t('I want to receive notifications only for those projects:') ?><br/><br/></p> + <?= Helper\form_label(t('Timezone'), 'timezone') ?> + <?= Helper\form_select('timezone', $timezones, $values, $errors) ?><br/> - <div class="form-checkbox-group"> - <?php foreach ($user_projects as $project_id => $project_name): ?> - <?= Helper\form_checkbox('projects['.$project_id.']', $project_name, '1', isset($notifications['project_'.$project_id])) ?> - <?php endforeach ?> - </div> - <div class="form-actions"> - <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> - </div> - </form> - </section> + <?= Helper\form_label(t('Webhook URL for task creation'), 'webhooks_url_task_creation') ?> + <?= Helper\form_text('webhooks_url_task_creation', $values, $errors) ?><br/> - <?php if ($user['is_admin']): ?> - <div class="page-header"> - <h2><?= t('More information') ?></h2> + <?= Helper\form_label(t('Webhook URL for task modification'), 'webhooks_url_task_modification') ?> + <?= Helper\form_text('webhooks_url_task_modification', $values, $errors) ?><br/> + + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> </div> - <section class="settings"> - <ul> - <li><a href="?controller=config&action=tokens<?= Helper\param_csrf() ?>"><?= t('Reset all tokens') ?></a></li> - <li> - <?= t('Webhooks token:') ?> - <strong><?= Helper\escape($values['webhooks_token']) ?></strong> - </li> + </form> + </section> + + <div class="page-header"> + <h2><?= t('More information') ?></h2> + </div> + <section class="settings"> + <ul> + <li><a href="?controller=config&action=tokens<?= Helper\param_csrf() ?>"><?= t('Reset all tokens') ?></a></li> + <li> + <?= t('Webhooks token:') ?> + <strong><?= Helper\escape($values['webhooks_token']) ?></strong> + </li> + <li> + <?= t('API token:') ?> + <strong><?= Helper\escape($values['api_token']) ?></strong> + </li> + <?php if (DB_DRIVER === 'sqlite'): ?> <li> - <?= t('API token:') ?> - <strong><?= Helper\escape($values['api_token']) ?></strong> + <?= t('Database size:') ?> + <strong><?= Helper\format_bytes($db_size) ?></strong> </li> - <?php if (DB_DRIVER === 'sqlite'): ?> - <li> - <?= t('Database size:') ?> - <strong><?= Helper\format_bytes($db_size) ?></strong> - </li> - <li> - <a href="?controller=config&action=downloadDb<?= Helper\param_csrf() ?>"><?= t('Download the database') ?></a> - <?= t('(Gzip compressed Sqlite file)') ?> - </li> - <li> - <a href="?controller=config&action=optimizeDb <?= Helper\param_csrf() ?>"><?= t('Optimize the database') ?></a> - <?= t('(VACUUM command)') ?> - </li> - <?php endif ?> <li> - <?= t('Official website:') ?> - <a href="http://kanboard.net/" target="_blank" rel="noreferer">http://kanboard.net/</a> + <a href="?controller=config&action=downloadDb<?= Helper\param_csrf() ?>"><?= t('Download the database') ?></a> + <?= t('(Gzip compressed Sqlite file)') ?> </li> <li> - <?= t('Application version:') ?> - <?= APP_VERSION ?> + <a href="?controller=config&action=optimizeDb <?= Helper\param_csrf() ?>"><?= t('Optimize the database') ?></a> + <?= t('(VACUUM command)') ?> </li> - </ul> - </section> - <?php endif ?> - - <div class="page-header" id="last-logins"> - <h2><?= t('Last logins') ?></h2> - </div> - <?php if (! empty($last_logins)): ?> - <table class="table-small table-hover"> - <tr> - <th><?= t('Login date') ?></th> - <th><?= t('Authentication method') ?></th> - <th><?= t('IP address') ?></th> - <th><?= t('User agent') ?></th> - </tr> - <?php foreach($last_logins as $login): ?> - <tr> - <td><?= dt('%B %e, %G at %k:%M %p', $login['date_creation']) ?></td> - <td><?= Helper\escape($login['auth_type']) ?></td> - <td><?= Helper\escape($login['ip']) ?></td> - <td><?= Helper\escape($login['user_agent']) ?></td> - </tr> - <?php endforeach ?> - </table> - <?php endif ?> - - <div class="page-header" id="remember-me"> - <h2><?= t('Persistent connections') ?></h2> - </div> - <?php if (empty($remember_me_sessions)): ?> - <p class="alert alert-info"><?= t('No session') ?></p> - <?php else: ?> - <table class="table-small table-hover"> - <tr> - <th><?= t('Creation date') ?></th> - <th><?= t('Expiration date') ?></th> - <th><?= t('IP address') ?></th> - <th><?= t('User agent') ?></th> - <th><?= t('Action') ?></th> - </tr> - <?php foreach($remember_me_sessions as $session): ?> - <tr> - <td><?= dt('%B %e, %G at %k:%M %p', $session['date_creation']) ?></td> - <td><?= dt('%B %e, %G at %k:%M %p', $session['expiration']) ?></td> - <td><?= Helper\escape($session['ip']) ?></td> - <td><?= Helper\escape($session['user_agent']) ?></td> - <td><a href="?controller=config&action=removeRememberMeToken&id=<?= $session['id'].Helper\param_csrf() ?>"><?= t('Remove') ?></a></td> - </tr> - <?php endforeach ?> - </table> - <?php endif ?> + <?php endif ?> + <li> + <?= t('Official website:') ?> + <a href="http://kanboard.net/" target="_blank" rel="noreferer">http://kanboard.net/</a> + </li> + <li> + <?= t('Application version:') ?> + <?= APP_VERSION ?> + </li> + </ul> + </section> </section> diff --git a/app/Templates/layout.php b/app/Templates/layout.php index 9bc815c9..30a4e091 100644 --- a/app/Templates/layout.php +++ b/app/Templates/layout.php @@ -57,12 +57,14 @@ <li <?= isset($menu) && $menu === 'users' ? 'class="active"' : '' ?>> <a href="?controller=user"><?= t('Users') ?></a> </li> - <li <?= isset($menu) && $menu === 'config' ? 'class="active"' : '' ?>> - <a href="?controller=config"><?= t('Settings') ?></a> - </li> + <?php if (Helper\is_admin()): ?> + <li <?= isset($menu) && $menu === 'config' ? 'class="active"' : '' ?>> + <a href="?controller=config"><?= t('Settings') ?></a> + </li> + <?php endif ?> <li> <a href="?controller=user&action=logout<?= Helper\param_csrf() ?>"><?= t('Logout') ?></a> - (<?= Helper\escape(Helper\get_username()) ?>) + (<a class="username" href="?controller=user&action=show&user_id=<?= Helper\get_user_id() ?>"><?= Helper\escape(Helper\get_username()) ?></a>) </li> </ul> </nav> diff --git a/app/Templates/user_edit.php b/app/Templates/user_edit.php index 8fba922f..14063d49 100644 --- a/app/Templates/user_edit.php +++ b/app/Templates/user_edit.php @@ -1,79 +1,30 @@ -<section id="main"> - <div class="page-header"> - <h2><?= t('Edit user') ?></h2> - <ul> - <li><a href="?controller=user"><?= t('All users') ?></a></li> - </ul> - </div> - <section> - <form method="post" action="?controller=user&action=update" autocomplete="off"> - - <?= Helper\form_csrf() ?> - - <div class="form-column"> - - <?= Helper\form_hidden('id', $values) ?> - <?= Helper\form_hidden('is_ldap_user', $values) ?> - - <?= Helper\form_label(t('Username'), 'username') ?> - <?= Helper\form_text('username', $values, $errors, array('required', $values['is_ldap_user'] == 1 ? 'readonly' : '')) ?><br/> - - <?= Helper\form_label(t('Name'), 'name') ?> - <?= Helper\form_text('name', $values, $errors) ?><br/> +<div class="page-header"> + <h2><?= t('Edit user') ?></h2> +</div> +<form method="post" action="?controller=user&action=edit&user_id=<?= $user['id'] ?>" autocomplete="off"> - <?= Helper\form_label(t('Email'), 'email') ?> - <?= Helper\form_email('email', $values, $errors) ?><br/> + <?= Helper\form_csrf() ?> - <?= Helper\form_label(t('Default Project'), 'default_project_id') ?> - <?= Helper\form_select('default_project_id', $projects, $values, $errors) ?><br/> + <?= Helper\form_hidden('id', $values) ?> + <?= Helper\form_hidden('is_ldap_user', $values) ?> - </div> + <?= Helper\form_label(t('Username'), 'username') ?> + <?= Helper\form_text('username', $values, $errors, array('required', $values['is_ldap_user'] == 1 ? 'readonly' : '')) ?><br/> - <div class="form-column"> + <?= Helper\form_label(t('Name'), 'name') ?> + <?= Helper\form_text('name', $values, $errors) ?><br/> - <?php if ($values['is_ldap_user'] == 0): ?> + <?= Helper\form_label(t('Email'), 'email') ?> + <?= Helper\form_email('email', $values, $errors) ?><br/> - <?= Helper\form_label(t('Current password for the user "%s"', Helper\get_username()), 'current_password') ?> - <?= Helper\form_password('current_password', $values, $errors) ?><br/> + <?= Helper\form_label(t('Default project'), 'default_project_id') ?> + <?= Helper\form_select('default_project_id', $projects, $values, $errors) ?><br/> - <?= Helper\form_label(t('Password'), 'password') ?> - <?= Helper\form_password('password', $values, $errors) ?><br/> + <?php if (Helper\is_admin()): ?> + <?= Helper\form_checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1 ? true : false) ?><br/> + <?php endif ?> - <?= Helper\form_label(t('Confirmation'), 'confirmation') ?> - <?= Helper\form_password('confirmation', $values, $errors) ?><br/> - - <?php endif ?> - - <?php if (Helper\is_admin()): ?> - <?= Helper\form_checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1 ? true : false) ?><br/> - <?php endif ?> - - <ul> - <?php if (GOOGLE_AUTH && Helper\is_current_user($values['id'])): ?> - <li> - <?php if (empty($values['google_id'])): ?> - <a href="?controller=user&action=google<?= Helper\param_csrf() ?>"><?= t('Link my Google Account') ?></a> - <?php else: ?> - <a href="?controller=user&action=unlinkGoogle<?= Helper\param_csrf() ?>"><?= t('Unlink my Google Account') ?></a> - <?php endif ?> - </li> - <?php endif ?> - - <?php if (GITHUB_AUTH && Helper\is_current_user($values['id'])): ?> - <li> - <?php if (empty($values['github_id'])): ?> - <a href="?controller=user&action=gitHub<?= Helper\param_csrf() ?>"><?= t('Link my GitHub Account') ?></a> - <?php else: ?> - <a href="?controller=user&action=unlinkGitHub<?= Helper\param_csrf() ?>"><?= t('Unlink my GitHub Account') ?></a> - <?php endif ?> - </li> - <?php endif ?> - </ul> - </div> - - <div class="form-actions"> - <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> <a href="?controller=user"><?= t('cancel') ?></a> - </div> - </form> - </section> -</section>
\ No newline at end of file + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> <a href="?controller=user&action=show&user_id=<?= $user['id'] ?>"><?= t('cancel') ?></a> + </div> +</form>
\ No newline at end of file diff --git a/app/Templates/user_external.php b/app/Templates/user_external.php new file mode 100644 index 00000000..727cd2bf --- /dev/null +++ b/app/Templates/user_external.php @@ -0,0 +1,39 @@ +<div class="page-header"> + <h2><?= t('External authentications') ?></h2> +</div> + +<?php if (GOOGLE_AUTH): ?> + <h3><?= t('Google Account') ?></h3> + + <p class="settings"> + <?php if (Helper\is_current_user($user['id'])): ?> + <?php if (empty($user['google_id'])): ?> + <a href="?controller=user&action=google<?= Helper\param_csrf() ?>"><?= t('Link my Google Account') ?></a> + <?php else: ?> + <a href="?controller=user&action=unlinkGoogle<?= Helper\param_csrf() ?>"><?= t('Unlink my Google Account') ?></a> + <?php endif ?> + <?php else: ?> + <?= empty($user['google_id']) ? t('No account linked.') : t('Account linked.') ?> + <?php endif ?> + </p> +<?php endif ?> + +<?php if (GITHUB_AUTH): ?> + <h3><?= t('Github Account') ?></h3> + + <p class="settings"> + <?php if (Helper\is_current_user($user['id'])): ?> + <?php if (empty($user['github_id'])): ?> + <a href="?controller=user&action=gitHub<?= Helper\param_csrf() ?>"><?= t('Link my GitHub Account') ?></a> + <?php else: ?> + <a href="?controller=user&action=unlinkGitHub<?= Helper\param_csrf() ?>"><?= t('Unlink my GitHub Account') ?></a> + <?php endif ?> + <?php else: ?> + <?= empty($user['github_id']) ? t('No account linked.') : t('Account linked.') ?> + <?php endif ?> + </p> +<?php endif ?> + +<?php if (! GOOGLE_AUTH && ! GITHUB_AUTH): ?> + <p class="alert"><?= t('No external authentication enabled.') ?></p> +<?php endif ?> diff --git a/app/Templates/user_index.php b/app/Templates/user_index.php index f6302a6b..7e9197b5 100644 --- a/app/Templates/user_index.php +++ b/app/Templates/user_index.php @@ -13,17 +13,23 @@ <?php else: ?> <table> <tr> + <th><?= t('Id') ?></th> <th><?= t('Username') ?></th> <th><?= t('Name') ?></th> <th><?= t('Email') ?></th> <th><?= t('Administrator') ?></th> - <th><?= t('Default Project') ?></th> - <th><?= t('Actions') ?></th> + <th><?= t('Default project') ?></th> + <th><?= t('Notifications') ?></th> + <th><?= t('External accounts') ?></th> + <th><?= t('Account type') ?></th> </tr> <?php foreach ($users as $user): ?> <tr> <td> - <span title="user_id=<?= $user['id'] ?>"><?= Helper\escape($user['username']) ?></span> + <a href="?controller=user&action=show&user_id=<?= $user['id'] ?>">#<?= $user['id'] ?></a> + </td> + <td> + <a href="?controller=user&action=show&user_id=<?= $user['id'] ?>"><?= Helper\escape($user['username']) ?></a> </td> <td> <?= Helper\escape($user['name']) ?> @@ -38,15 +44,24 @@ <?= (isset($user['default_project_id']) && isset($projects[$user['default_project_id']])) ? Helper\escape($projects[$user['default_project_id']]) : t('None'); ?> </td> <td> - <?php if (Helper\is_admin() || Helper\is_current_user($user['id'])): ?> - <a href="?controller=user&action=edit&user_id=<?= $user['id'] ?>"><?= t('edit') ?></a> + <?php if ($user['notifications_enabled'] == 1): ?> + <?= t('Enabled') ?> + <?php else: ?> + <?= t('Disabled') ?> <?php endif ?> - <?php if (Helper\is_admin()): ?> - <?php if (count($users) > 1): ?> - <?= t('or') ?> - <a href="?controller=user&action=confirm&user_id=<?= $user['id'] ?>"><?= t('remove') ?></a> - <?php endif ?> + </td> + <td> + <ul class="no-bullet"> + <?php if ($user['google_id']): ?> + <li><?= t('Google account linked') ?></li> <?php endif ?> + <?php if ($user['github_id']): ?> + <li><?= t('Github account linked') ?></li> + <?php endif ?> + </ul> + </td> + <td> + <?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?> </td> </tr> <?php endforeach ?> diff --git a/app/Templates/user_last.php b/app/Templates/user_last.php new file mode 100644 index 00000000..0b55b0d5 --- /dev/null +++ b/app/Templates/user_last.php @@ -0,0 +1,24 @@ +<div class="page-header"> + <h2><?= t('Last logins') ?></h2> +</div> + +<?php if (empty($last_logins)): ?> + <p class="alert"><?= t('Never connected.') ?></p> +<?php else: ?> + <table class="table-small"> + <tr> + <th><?= t('Login date') ?></th> + <th><?= t('Authentication method') ?></th> + <th><?= t('IP address') ?></th> + <th><?= t('User agent') ?></th> + </tr> + <?php foreach($last_logins as $login): ?> + <tr> + <td><?= dt('%B %e, %Y at %k:%M %p', $login['date_creation']) ?></td> + <td><?= Helper\escape($login['auth_type']) ?></td> + <td><?= Helper\escape($login['ip']) ?></td> + <td><?= Helper\escape(Helper\summary($login['user_agent'])) ?></td> + </tr> + <?php endforeach ?> + </table> +<?php endif ?>
\ No newline at end of file diff --git a/app/Templates/user_layout.php b/app/Templates/user_layout.php new file mode 100644 index 00000000..890b0c0a --- /dev/null +++ b/app/Templates/user_layout.php @@ -0,0 +1,19 @@ +<section id="main"> + <div class="page-header"> + <h2><?= Helper\escape($user['name'] ?: $user['username']).' (#'.$user['id'].')' ?></h2> + <ul> + <li><a href="?controller=user&action=index"><?= t('All users') ?></a></li> + <?php if (Helper\is_admin()): ?> + <li><a href="?controller=user&action=create"><?= t('New user') ?></a></li> + <?php endif ?> + </ul> + </div> + <section class="user-show" id="user-section"> + + <?= Helper\template('user_sidebar', array('user' => $user)) ?> + + <div class="user-show-main"> + <?= $user_content_for_layout ?> + </div> + </section> +</section>
\ No newline at end of file diff --git a/app/Templates/user_new.php b/app/Templates/user_new.php index 3e22b7ee..48d7b6d3 100644 --- a/app/Templates/user_new.php +++ b/app/Templates/user_new.php @@ -21,9 +21,6 @@ <?= Helper\form_label(t('Email'), 'email') ?> <?= Helper\form_email('email', $values, $errors) ?><br/> - <?= Helper\form_label(t('Default Project'), 'default_project_id') ?> - <?= Helper\form_select('default_project_id', $projects, $values, $errors) ?><br/> - </div> <div class="form-column"> @@ -34,6 +31,9 @@ <?= Helper\form_label(t('Confirmation'), 'confirmation') ?> <?= Helper\form_password('confirmation', $values, $errors, array('required')) ?><br/> + <?= Helper\form_label(t('Default project'), 'default_project_id') ?> + <?= Helper\form_select('default_project_id', $projects, $values, $errors) ?><br/> + <?= Helper\form_checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1 ? true : false) ?> </div> diff --git a/app/Templates/user_notifications.php b/app/Templates/user_notifications.php new file mode 100644 index 00000000..13dd9809 --- /dev/null +++ b/app/Templates/user_notifications.php @@ -0,0 +1,22 @@ +<div class="page-header"> + <h2><?= t('Email notifications') ?></h2> +</div> + +<form method="post" action="?controller=user&action=notifications&user_id=<?= $user['id'] ?>" autocomplete="off"> + + <?= Helper\form_csrf() ?> + + <?= Helper\form_checkbox('notifications_enabled', t('Enable email notifications'), '1', $notifications['notifications_enabled'] == 1) ?><br/> + + <p><?= t('I want to receive notifications only for those projects:') ?><br/><br/></p> + + <div class="form-checkbox-group"> + <?php foreach ($projects as $project_id => $project_name): ?> + <?= Helper\form_checkbox('projects['.$project_id.']', $project_name, '1', isset($notifications['project_'.$project_id])) ?> + <?php endforeach ?> + </div> + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> + <?= t('or') ?> <a href="?controller=user&action=show&user_id=<?= $user['id'] ?>"><?= t('cancel') ?></a> + </div> +</form>
\ No newline at end of file diff --git a/app/Templates/user_password.php b/app/Templates/user_password.php new file mode 100644 index 00000000..a494e42d --- /dev/null +++ b/app/Templates/user_password.php @@ -0,0 +1,23 @@ +<div class="page-header"> + <h2><?= t('Password modification') ?></h2> +</div> + +<form method="post" action="?controller=user&action=password&user_id=<?= $user['id'] ?>" autocomplete="off"> + + <?= Helper\form_hidden('id', $values) ?> + <?= Helper\form_csrf() ?> + + <?= Helper\form_label(t('Current password for the user "%s"', Helper\get_username()), 'current_password') ?> + <?= Helper\form_password('current_password', $values, $errors) ?><br/> + + <?= Helper\form_label(t('Password'), 'password') ?> + <?= Helper\form_password('password', $values, $errors) ?><br/> + + <?= Helper\form_label(t('Confirmation'), 'confirmation') ?> + <?= Helper\form_password('confirmation', $values, $errors) ?><br/> + + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> <?= t('or') ?> <a href="?controller=user&action=show&user_id=<?= $user['id'] ?>"><?= t('cancel') ?></a> + </div> + +</form>
\ No newline at end of file diff --git a/app/Templates/user_remove.php b/app/Templates/user_remove.php index 45774d27..c20ccbba 100644 --- a/app/Templates/user_remove.php +++ b/app/Templates/user_remove.php @@ -1,14 +1,12 @@ -<section id="main"> - <div class="page-header"> - <h2><?= t('Remove user') ?></h2> - </div> +<div class="page-header"> + <h2><?= t('Remove user') ?></h2> +</div> - <div class="confirm"> - <p class="alert alert-info"><?= t('Do you really want to remove this user: "%s"?', $user['name'] ?: $user['username']) ?></p> +<div class="confirm"> + <p class="alert alert-info"><?= t('Do you really want to remove this user: "%s"?', $user['name'] ?: $user['username']) ?></p> - <div class="form-actions"> - <a href="?controller=user&action=remove&user_id=<?= $user['id'].Helper\param_csrf() ?>" class="btn btn-red"><?= t('Yes') ?></a> - <?= t('or') ?> <a href="?controller=user"><?= t('cancel') ?></a> - </div> + <div class="form-actions"> + <a href="?controller=user&action=remove&confirmation=yes&user_id=<?= $user['id'].Helper\param_csrf() ?>" class="btn btn-red"><?= t('Yes') ?></a> + <?= t('or') ?> <a href="?controller=user&action=show&user_id=<?= $user['id'] ?>"><?= t('cancel') ?></a> </div> -</section>
\ No newline at end of file +</div>
\ No newline at end of file diff --git a/app/Templates/user_sessions.php b/app/Templates/user_sessions.php new file mode 100644 index 00000000..b647d726 --- /dev/null +++ b/app/Templates/user_sessions.php @@ -0,0 +1,26 @@ +<div class="page-header"> + <h2><?= t('Persistent connections') ?></h2> +</div> + +<?php if (empty($sessions)): ?> + <p class="alert"><?= t('No session.') ?></p> +<?php else: ?> + <table class="table-small"> + <tr> + <th><?= t('Creation date') ?></th> + <th><?= t('Expiration date') ?></th> + <th><?= t('IP address') ?></th> + <th><?= t('User agent') ?></th> + <th><?= t('Action') ?></th> + </tr> + <?php foreach($sessions as $session): ?> + <tr> + <td><?= dt('%B %e, %Y at %k:%M %p', $session['date_creation']) ?></td> + <td><?= dt('%B %e, %Y at %k:%M %p', $session['expiration']) ?></td> + <td><?= Helper\escape($session['ip']) ?></td> + <td><?= Helper\escape(Helper\summary($session['user_agent'])) ?></td> + <td><a href="?controller=user&action=removeSession&user_id=<?= $user['id'] ?>&id=<?= $session['id'].Helper\param_csrf() ?>"><?= t('Remove') ?></a></td> + </tr> + <?php endforeach ?> + </table> +<?php endif ?> diff --git a/app/Templates/user_show.php b/app/Templates/user_show.php new file mode 100644 index 00000000..5d42d3cf --- /dev/null +++ b/app/Templates/user_show.php @@ -0,0 +1,12 @@ +<div class="page-header"> + <h2><?= t('Summary') ?></h2> +</div> +<ul class="settings"> + <li><?= t('Username:') ?> <strong><?= Helper\escape($user['username']) ?></strong></li> + <li><?= t('Name:') ?> <strong><?= Helper\escape($user['name']) ?></strong></li> + <li><?= t('Email:') ?> <strong><?= Helper\escape($user['email']) ?></strong></li> + <li><?= t('Default project:') ?> <strong><?= (isset($user['default_project_id']) && isset($projects[$user['default_project_id']])) ? Helper\escape($projects[$user['default_project_id']]) : t('None'); ?></strong></li> + <li><?= t('Notifications:') ?> <strong><?= $user['notifications_enabled'] == 1 ? t('Enabled') : t('Disabled') ?></strong></li> + <li><?= t('Group:') ?> <strong><?= $user['is_admin'] ? t('Administrator') : t('Regular user') ?></strong></li> + <li><?= t('Account type:') ?> <strong><?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?></strong></li> +</ul> diff --git a/app/Templates/user_sidebar.php b/app/Templates/user_sidebar.php new file mode 100644 index 00000000..9d8f8b46 --- /dev/null +++ b/app/Templates/user_sidebar.php @@ -0,0 +1,42 @@ +<div class="project-show-sidebar"> + <h2><?= t('Actions') ?></h2> + <div class="user-show-actions"> + <ul> + <li> + <a href="?controller=user&action=show&user_id=<?= $user['id'] ?>"><?= t('Summary') ?></a> + </li> + + <?php if (Helper\is_admin() || Helper\is_current_user($user['id'])): ?> + <li> + <a href="?controller=user&action=edit&user_id=<?= $user['id'] ?>"><?= t('Edit profile') ?></a> + </li> + + <?php if ($user['is_ldap_user'] == 0): ?> + <li> + <a href="?controller=user&action=password&user_id=<?= $user['id'] ?>"><?= t('Change password') ?></a> + </li> + <?php endif ?> + + <li> + <a href="?controller=user&action=notifications&user_id=<?= $user['id'] ?>"><?= t('Email notifications') ?></a> + </li> + <li> + <a href="?controller=user&action=external&user_id=<?= $user['id'] ?>"><?= t('External accounts') ?></a> + </li> + <li> + <a href="?controller=user&action=last&user_id=<?= $user['id'] ?>"><?= t('Last logins') ?></a> + </li> + <li> + <a href="?controller=user&action=sessions&user_id=<?= $user['id'] ?>"><?= t('Persistent connections') ?></a> + </li> + <?php endif ?> + + <?php if (Helper\is_admin()): ?> + <li> + <a href="?controller=user&action=remove&user_id=<?= $user['id'] ?>"><?= t('Remove') ?></a> + </li> + <?php endif ?> + + </ul> + </div> +</div>
\ No newline at end of file diff --git a/app/helpers.php b/app/helpers.php index 9a2b4cbf..0d8409c8 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -40,6 +40,11 @@ function get_username() return $_SESSION['user']['name'] ?: $_SESSION['user']['username']; } +function get_user_id() +{ + return $_SESSION['user']['id']; +} + function parse($text) { $text = markdown($text); @@ -110,15 +115,12 @@ function get_host_from_url($url) return escape(parse_url($url, PHP_URL_HOST)) ?: $url; } -function summary($value, $min_length = 5, $max_length = 120, $end = '[...]') +function summary($value, $max_length = 85, $end = '[...]') { $length = strlen($value); if ($length > $max_length) { - return substr($value, 0, strpos($value, ' ', $max_length)).' '.$end; - } - else if ($length < $min_length) { - return ''; + return substr($value, 0, $max_length).' '.$end; } return $value; diff --git a/assets/css/app.css b/assets/css/app.css index e5f2fc57..d2657ab4 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -60,6 +60,11 @@ h3 { font-size: 1.2em; } +ul.no-bullet li { + list-style-type: none; + margin-left: 0; +} + /* tables */ table { width: 100%; @@ -103,7 +108,7 @@ td li { } .table-small { - font-size: 0.85em; + font-size: 0.8em; } .table-hover tr:hover td { @@ -461,6 +466,15 @@ nav .active a { font-weight: bold; } +.username { + color: #000; +} + +.username:hover { + color: red; + text-decoration: underline; +} + .logo { color: #DF5353; letter-spacing: 1px; @@ -676,16 +690,19 @@ a.task-board-nobody { } /* task view */ +.user-show, .project-show, .task-show { position: relative; } +.user-show-main, .project-show-main, .task-show-main { margin-left: 330px; } +.user-show-sidebar, .project-show-sidebar, .task-show-sidebar { position: absolute; @@ -699,6 +716,7 @@ a.task-board-nobody { border-radius: 5px; } +.user-show-sidebar li, .project-show-sidebar li, .task-show-sidebar li { list-style-type: square; |