Made settings multi-page again.
This commit is contained in:
parent
36a0c750e8
commit
a2ae5e3d15
13 changed files with 552 additions and 490 deletions
|
@ -15,9 +15,7 @@
|
|||
|
||||
&__menu {
|
||||
width: 280px;
|
||||
position: sticky;
|
||||
top: 2px;
|
||||
margin: 0 2px 2px;
|
||||
margin-right: 2px;
|
||||
|
||||
@media (max-width: @site-mobile-width) {
|
||||
width: 100%;
|
||||
|
@ -38,5 +36,10 @@
|
|||
&:hover {
|
||||
background-color: var(--background-colour-translucent-9);
|
||||
}
|
||||
|
||||
@media (max-width: @site-mobile-width) {
|
||||
display: inline-block;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,210 +1,4 @@
|
|||
<?php
|
||||
require_once '../misuzu.php';
|
||||
|
||||
if (!user_session_active()) {
|
||||
echo render_error(401);
|
||||
return;
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
|
||||
$currentUserId = user_session_current('user_id');
|
||||
$currentEmail = user_email_get($currentUserId);
|
||||
$isRestricted = user_warning_check_restriction($currentUserId);
|
||||
$twoFactorInfo = user_totp_info($currentUserId);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!csrf_verify('settings', $_POST['csrf'] ?? '')) {
|
||||
$errors[] = MSZ_TMP_USER_ERROR_STRINGS['csrf'];
|
||||
} else {
|
||||
if (!empty($_POST['session'])) {
|
||||
$currentSessionKilled = false;
|
||||
|
||||
if (is_array($_POST['session'])) {
|
||||
foreach ($_POST['session'] as $sessionId) {
|
||||
$sessionId = intval($sessionId);
|
||||
$session = user_session_find($sessionId);
|
||||
|
||||
if (!$session || (int)$session['user_id'] !== $currentUserId) {
|
||||
$errors[] = "Session #{$sessionId} does not exist.";
|
||||
break;
|
||||
} elseif ((int)$session['session_id'] === user_session_current('session_id')) {
|
||||
$currentSessionKilled = true;
|
||||
}
|
||||
|
||||
user_session_delete($session['session_id']);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_SESSION_DESTROY, $currentUserId, [
|
||||
$session['session_id'],
|
||||
]);
|
||||
}
|
||||
} elseif ($_POST['session'] === 'all') {
|
||||
$currentSessionKilled = true;
|
||||
user_session_purge_all($currentUserId);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_SESSION_DESTROY_ALL, $currentUserId);
|
||||
}
|
||||
|
||||
if ($currentSessionKilled) {
|
||||
header(sprintf('Location: %s', url('index')));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_POST['role']) && !$isRestricted) {
|
||||
$roleId = (int)($_POST['role']['id'] ?? 0);
|
||||
|
||||
if ($roleId > 0 && user_role_has($currentUserId, $roleId)) {
|
||||
switch ($_POST['role']['mode'] ?? '') {
|
||||
case 'display':
|
||||
user_role_set_display($currentUserId, $roleId);
|
||||
break;
|
||||
|
||||
case 'leave':
|
||||
if (user_role_can_leave($roleId)) {
|
||||
user_role_remove($currentUserId, $roleId);
|
||||
} else {
|
||||
$errors[] = "You're not allow to leave this role, an administrator has to remove it for you.";
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$errors[] = "You're trying to modify a role that hasn't been assigned to you.";
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['tfa']['enable']) && (bool)$twoFactorInfo['totp_enabled'] !== (bool)$_POST['tfa']['enable']) {
|
||||
if ((bool)$_POST['tfa']['enable']) {
|
||||
$tfaKey = totp_generate_key();
|
||||
|
||||
tpl_vars([
|
||||
'settings_2fa_code' => $tfaKey,
|
||||
'settings_2fa_image' => totp_qrcode(totp_uri(
|
||||
sprintf(
|
||||
'%s:%s',
|
||||
config_get_default('Misuzu', 'Site', 'name'),
|
||||
$twoFactorInfo['username']
|
||||
),
|
||||
$tfaKey,
|
||||
$_SERVER['HTTP_HOST']
|
||||
)),
|
||||
]);
|
||||
|
||||
user_totp_update($currentUserId, $tfaKey);
|
||||
} else {
|
||||
user_totp_update($currentUserId, null);
|
||||
}
|
||||
|
||||
$twoFactorInfo['totp_enabled'] = !$twoFactorInfo['totp_enabled'];
|
||||
}
|
||||
|
||||
if (!empty($_POST['current_password'])) {
|
||||
if (!user_password_verify_db($currentUserId, $_POST['current_password'] ?? '')) {
|
||||
$errors[] = 'Your password was incorrect.';
|
||||
} else {
|
||||
// Changing e-mail
|
||||
if (!empty($_POST['email']['new'])) {
|
||||
if (empty($_POST['email']['confirm']) || $_POST['email']['new'] !== $_POST['email']['confirm']) {
|
||||
$errors[] = 'The addresses you entered did not match each other.';
|
||||
} elseif ($currentEmail === mb_strtolower($_POST['email']['confirm'])) {
|
||||
$errors[] = 'This is already your e-mail address!';
|
||||
} else {
|
||||
$checkMail = user_validate_email($_POST['email']['new'], true);
|
||||
|
||||
if ($checkMail !== '') {
|
||||
switch ($checkMail) {
|
||||
case 'dns':
|
||||
$errors[] = 'No valid MX record exists for this domain.';
|
||||
break;
|
||||
|
||||
case 'format':
|
||||
$errors[] = 'The given e-mail address was incorrectly formatted.';
|
||||
break;
|
||||
|
||||
case 'in-use':
|
||||
$errors[] = 'This e-mail address is already in use.';
|
||||
break;
|
||||
|
||||
default:
|
||||
$errors[] = 'Unknown e-mail validation error.';
|
||||
}
|
||||
} else {
|
||||
user_email_set($currentUserId, $_POST['email']['new']);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_EMAIL_CHANGE, $currentUserId, [
|
||||
$_POST['email']['new'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Changing password
|
||||
if (!empty($_POST['password']['new'])) {
|
||||
if (empty($_POST['password']['confirm']) || $_POST['password']['new'] !== $_POST['password']['confirm']) {
|
||||
$errors[] = 'The new passwords you entered did not match each other.';
|
||||
} else {
|
||||
$checkPassword = user_validate_password($_POST['password']['new']);
|
||||
|
||||
if ($checkPassword !== '') {
|
||||
$errors[] = 'The given passwords was too weak.';
|
||||
} else {
|
||||
user_password_set($currentUserId, $_POST['password']['new']);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_PASSWORD_CHANGE, $currentUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sessions = [
|
||||
'list' => [],
|
||||
'active' => user_session_current('session_id'),
|
||||
'pagination' => pagination_create(user_session_count($currentUserId), 15),
|
||||
];
|
||||
|
||||
$logins = [
|
||||
'list' => [],
|
||||
'pagination' => pagination_create(user_login_attempts_count($currentUserId), 15),
|
||||
];
|
||||
|
||||
$logs = [
|
||||
'list' => [],
|
||||
'pagination' => pagination_create(audit_log_count($currentUserId), 15),
|
||||
'strings' => MSZ_AUDIT_LOG_STRINGS,
|
||||
];
|
||||
|
||||
foreach (['sessions', 'logins', 'logs'] as $section) {
|
||||
if (!pagination_is_valid_offset(pagination_offset(($$section)['pagination'], pagination_param("{$section}_page")))) {
|
||||
($$section)['pagination']['offset'] = 0;
|
||||
($$section)['pagination']['page'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$sessions['list'] = user_session_list(
|
||||
$sessions['pagination']['offset'],
|
||||
$sessions['pagination']['range'],
|
||||
$currentUserId
|
||||
);
|
||||
$logins['list'] = user_login_attempts_list(
|
||||
$logins['pagination']['offset'],
|
||||
$logins['pagination']['range'],
|
||||
$currentUserId
|
||||
);
|
||||
$logs['list'] = audit_log_list(
|
||||
$logs['pagination']['offset'],
|
||||
$logs['pagination']['range'],
|
||||
$currentUserId
|
||||
);
|
||||
|
||||
$userRoles = user_role_all_user($currentUserId);
|
||||
|
||||
echo tpl_render('user.settings', [
|
||||
'errors' => $errors,
|
||||
'current_email' => $currentEmail,
|
||||
'sessions' => $sessions,
|
||||
'logins' => $logins,
|
||||
'logs' => $logs,
|
||||
'user_roles' => $userRoles,
|
||||
'user_display_role' => user_role_get_display($currentUserId),
|
||||
'is_restricted' => $isRestricted,
|
||||
'settings_2fa_enabled' => $twoFactorInfo['totp_enabled'],
|
||||
]);
|
||||
header('Location: ' . url('settings-index'));
|
||||
|
|
129
public/settings/account.php
Normal file
129
public/settings/account.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
if(!user_session_active()) {
|
||||
echo render_error(401);
|
||||
return;
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$currentUserId = user_session_current('user_id');
|
||||
$currentEmail = user_email_get($currentUserId);
|
||||
$isRestricted = user_warning_check_restriction($currentUserId);
|
||||
$twoFactorInfo = user_totp_info($currentUserId);
|
||||
$isVerifiedRequest = csrf_verify('settings', $_POST['csrf'] ?? '');
|
||||
|
||||
if(!$isRestricted && $isVerifiedRequest && !empty($_POST['role'])) {
|
||||
$roleId = (int)($_POST['role']['id'] ?? 0);
|
||||
|
||||
if($roleId > 0 && user_role_has($currentUserId, $roleId)) {
|
||||
switch ($_POST['role']['mode'] ?? '') {
|
||||
case 'display':
|
||||
user_role_set_display($currentUserId, $roleId);
|
||||
break;
|
||||
|
||||
case 'leave':
|
||||
if (user_role_can_leave($roleId)) {
|
||||
user_role_remove($currentUserId, $roleId);
|
||||
} else {
|
||||
$errors[] = "You're not allow to leave this role, an administrator has to remove it for you.";
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$errors[] = "You're trying to modify a role that hasn't been assigned to you.";
|
||||
}
|
||||
}
|
||||
|
||||
if($isVerifiedRequest && isset($_POST['tfa']['enable']) && (bool)$twoFactorInfo['totp_enabled'] !== (bool)$_POST['tfa']['enable']) {
|
||||
if((bool)$_POST['tfa']['enable']) {
|
||||
$tfaKey = totp_generate_key();
|
||||
|
||||
tpl_vars([
|
||||
'settings_2fa_code' => $tfaKey,
|
||||
'settings_2fa_image' => totp_qrcode(totp_uri(
|
||||
sprintf(
|
||||
'%s:%s',
|
||||
config_get_default('Misuzu', 'Site', 'name'),
|
||||
$twoFactorInfo['username']
|
||||
),
|
||||
$tfaKey,
|
||||
$_SERVER['HTTP_HOST']
|
||||
)),
|
||||
]);
|
||||
|
||||
user_totp_update($currentUserId, $tfaKey);
|
||||
} else {
|
||||
user_totp_update($currentUserId, null);
|
||||
}
|
||||
|
||||
$twoFactorInfo['totp_enabled'] = !$twoFactorInfo['totp_enabled'];
|
||||
}
|
||||
|
||||
if($isVerifiedRequest && !empty($_POST['current_password'])) {
|
||||
if(!user_password_verify_db($currentUserId, $_POST['current_password'] ?? '')) {
|
||||
$errors[] = 'Your password was incorrect.';
|
||||
} else {
|
||||
// Changing e-mail
|
||||
if(!empty($_POST['email']['new'])) {
|
||||
if(empty($_POST['email']['confirm']) || $_POST['email']['new'] !== $_POST['email']['confirm']) {
|
||||
$errors[] = 'The addresses you entered did not match each other.';
|
||||
} elseif($currentEmail === mb_strtolower($_POST['email']['confirm'])) {
|
||||
$errors[] = 'This is already your e-mail address!';
|
||||
} else {
|
||||
$checkMail = user_validate_email($_POST['email']['new'], true);
|
||||
|
||||
if ($checkMail !== '') {
|
||||
switch ($checkMail) {
|
||||
case 'dns':
|
||||
$errors[] = 'No valid MX record exists for this domain.';
|
||||
break;
|
||||
|
||||
case 'format':
|
||||
$errors[] = 'The given e-mail address was incorrectly formatted.';
|
||||
break;
|
||||
|
||||
case 'in-use':
|
||||
$errors[] = 'This e-mail address is already in use.';
|
||||
break;
|
||||
|
||||
default:
|
||||
$errors[] = 'Unknown e-mail validation error.';
|
||||
}
|
||||
} else {
|
||||
user_email_set($currentUserId, $_POST['email']['new']);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_EMAIL_CHANGE, $currentUserId, [
|
||||
$_POST['email']['new'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Changing password
|
||||
if(!empty($_POST['password']['new'])) {
|
||||
if(empty($_POST['password']['confirm']) || $_POST['password']['new'] !== $_POST['password']['confirm']) {
|
||||
$errors[] = 'The new passwords you entered did not match each other.';
|
||||
} else {
|
||||
$checkPassword = user_validate_password($_POST['password']['new']);
|
||||
|
||||
if($checkPassword !== '') {
|
||||
$errors[] = 'The given passwords was too weak.';
|
||||
} else {
|
||||
user_password_set($currentUserId, $_POST['password']['new']);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_PASSWORD_CHANGE, $currentUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$userRoles = user_role_all_user($currentUserId);
|
||||
|
||||
echo tpl_render('settings.account', [
|
||||
'errors' => $errors,
|
||||
'current_email' => $currentEmail,
|
||||
'user_roles' => $userRoles,
|
||||
'user_display_role' => user_role_get_display($currentUserId),
|
||||
'is_restricted' => $isRestricted,
|
||||
'settings_2fa_enabled' => $twoFactorInfo['totp_enabled'],
|
||||
]);
|
11
public/settings/index.php
Normal file
11
public/settings/index.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
if (!user_session_active()) {
|
||||
echo render_error(401);
|
||||
return;
|
||||
}
|
||||
|
||||
// do something with this page
|
||||
|
||||
header('Location: ' . url('settings-account'));
|
41
public/settings/logs.php
Normal file
41
public/settings/logs.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
if(!user_session_active()) {
|
||||
echo render_error(401);
|
||||
return;
|
||||
}
|
||||
|
||||
$currentUserId = user_session_current('user_id');
|
||||
$loginHistoryPagination = pagination_create(user_login_attempts_count($currentUserId), 15);
|
||||
$accountLogPagination = pagination_create(audit_log_count($currentUserId), 15);
|
||||
|
||||
if(!pagination_is_valid_offset(pagination_offset($loginHistoryPagination, pagination_param('hp')))) {
|
||||
$loginHistoryPagination['offset'] = 0;
|
||||
$loginHistoryPagination['page'] = 1;
|
||||
}
|
||||
|
||||
if(!pagination_is_valid_offset(pagination_offset($accountLogPagination, pagination_param('ap')))) {
|
||||
$accountLogPagination['offset'] = 0;
|
||||
$accountLogPagination['page'] = 1;
|
||||
}
|
||||
|
||||
$loginHistoryList = user_login_attempts_list(
|
||||
$loginHistoryPagination['offset'],
|
||||
$loginHistoryPagination['range'],
|
||||
$currentUserId
|
||||
);
|
||||
|
||||
$accountLogList = audit_log_list(
|
||||
$accountLogPagination['offset'],
|
||||
$accountLogPagination['range'],
|
||||
$currentUserId
|
||||
);
|
||||
|
||||
echo tpl_render('settings.logs', [
|
||||
'login_history_list' => $loginHistoryList,
|
||||
'login_history_pagination' => $loginHistoryPagination,
|
||||
'account_log_list' => $accountLogList,
|
||||
'account_log_pagination' => $accountLogPagination,
|
||||
'account_log_strings' => MSZ_AUDIT_LOG_STRINGS,
|
||||
]);
|
63
public/settings/sessions.php
Normal file
63
public/settings/sessions.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
if(!user_session_active()) {
|
||||
echo render_error(401);
|
||||
return;
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$currentUserId = user_session_current('user_id');
|
||||
$sessionActive = user_session_current('session_id');
|
||||
|
||||
if(!empty($_POST['session']) && csrf_verify('user_session', $_POST['csrf'] ?? '')) {
|
||||
$currentSessionKilled = false;
|
||||
|
||||
if(is_array($_POST['session'])) {
|
||||
foreach($_POST['session'] as $sessionId) {
|
||||
$sessionId = intval($sessionId);
|
||||
$session = user_session_find($sessionId);
|
||||
|
||||
if (!$session || (int)$session['user_id'] !== $currentUserId) {
|
||||
$errors[] = "Session #{$sessionId} does not exist.";
|
||||
continue;
|
||||
} elseif((int)$session['session_id'] === $sessionActive) {
|
||||
$currentSessionKilled = true;
|
||||
}
|
||||
|
||||
user_session_delete($session['session_id']);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_SESSION_DESTROY, $currentUserId, [
|
||||
$session['session_id'],
|
||||
]);
|
||||
}
|
||||
} elseif($_POST['session'] === 'all') {
|
||||
$currentSessionKilled = true;
|
||||
user_session_purge_all($currentUserId);
|
||||
audit_log(MSZ_AUDIT_PERSONAL_SESSION_DESTROY_ALL, $currentUserId);
|
||||
}
|
||||
|
||||
if($currentSessionKilled) {
|
||||
header(sprintf('Location: %s', url('index')));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$sessionPagination = pagination_create(user_session_count($currentUserId), 15);
|
||||
|
||||
if(!pagination_is_valid_offset(pagination_offset($sessionPagination, pagination_param()))) {
|
||||
$sessionPagination['offset'] = 0;
|
||||
$sessionPagination['page'] = 1;
|
||||
}
|
||||
|
||||
$sessionList = user_session_list(
|
||||
$sessionPagination['offset'],
|
||||
$sessionPagination['range'],
|
||||
$currentUserId
|
||||
);
|
||||
|
||||
echo tpl_render('settings.sessions', [
|
||||
'errors' => $errors,
|
||||
'session_list' => $sessionList,
|
||||
'session_active_id' => $sessionActive,
|
||||
'session_pagination' => $sessionPagination,
|
||||
]);
|
11
src/url.php
11
src/url.php
|
@ -80,13 +80,10 @@ define('MSZ_URLS', [
|
|||
'user-relation-none' => ['/relations.php', ['u' => '<user>', 'm' => '[MSZ_USER_RELATION_NONE]', 'c' => '{user_relation}']],
|
||||
'user-relation-follow' => ['/relations.php', ['u' => '<user>', 'm' => '[MSZ_USER_RELATION_FOLLOW]', 'c' => '{user_relation}']],
|
||||
|
||||
'settings-index' => ['/settings.php'],
|
||||
'settings-account' => ['/settings.php', [], 'account'],
|
||||
'settings-roles' => ['/settings.php', [], 'roles'],
|
||||
'settings-tfa' => ['/settings.php', [], 'tfa'],
|
||||
'settings-sessions' => ['/settings.php', [], 'sessions'],
|
||||
'settings-login-attempts' => ['/settings.php', [], 'login-attempts'],
|
||||
'settings-account-log' => ['/settings.php', [], 'account-log'],
|
||||
'settings-index' => ['/settings'],
|
||||
'settings-account' => ['/settings/account.php'],
|
||||
'settings-sessions' => ['/settings/sessions.php'],
|
||||
'settings-logs' => ['/settings/logs.php'],
|
||||
|
||||
'comment-create' => ['/comments.php', ['m' => 'create']],
|
||||
'comment-vote' => ['/comments.php', ['c' => '<comment>', 'csrf' => '{comments}', 'm' => 'vote', 'v' => '<vote>']],
|
||||
|
|
144
templates/settings/account.twig
Normal file
144
templates/settings/account.twig
Normal file
|
@ -0,0 +1,144 @@
|
|||
{% extends 'settings/master.twig' %}
|
||||
{% from 'macros.twig' import container_title %}
|
||||
{% from '_layout/input.twig' import input_hidden, input_csrf, input_text, input_select %}
|
||||
|
||||
{% set title = 'Settings / Account' %}
|
||||
|
||||
{% block settings_content %}
|
||||
<form action="{{ url('settings-account') }}" method="post" class="container settings__container">
|
||||
{{ container_title('<i class="fas fa-user fa-fw"></i> Account') }}
|
||||
{{ input_csrf('settings') }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>Here you can change your e-mail address and/or your password, please make sure your e-mail is accurate and your password is strong in order to protect your account. For convenience your current e-mail address is displayed. You are required to verify yourself by entering your current password to change either value.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__account">
|
||||
<div class="settings__account__section">
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
New e-mail address
|
||||
</div>
|
||||
{{ input_text('email[new]', 'settings__account__input', '', 'email', current_email) }}
|
||||
</label>
|
||||
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
Confirm new e-mail address
|
||||
</div>
|
||||
{{ input_text('email[confirm]', 'settings__account__input', '', 'email') }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings__account__section">
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
New password
|
||||
</div>
|
||||
{{ input_text('password[new]', 'settings__account__input', '', 'password') }}
|
||||
</label>
|
||||
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
Confirm new password
|
||||
</div>
|
||||
{{ input_text('password[confirm]', 'settings__account__input', '', 'password') }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings__account__section settings__account__section--confirm">
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
Current password
|
||||
</div>
|
||||
{{ input_text('current_password', 'settings__account__input', '', 'password') }}
|
||||
</label>
|
||||
|
||||
<div class="settings__account__buttons">
|
||||
<button class="input__button settings__account__button">Update</button>
|
||||
<button class="input__button settings__account__button" type="reset">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% if not is_restricted %}
|
||||
<div class="container settings__container">
|
||||
{{ container_title('<i class="fas fa-user-check fa-fw"></i> Roles') }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>This is a listing of the user roles you're a part of, you can select which you want to leave or which one you want to boast as your main role which will change your username colour accordingly.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__role__collection">
|
||||
{% for role in user_roles %}
|
||||
{% set is_display_role = user_display_role == role.role_id %}
|
||||
|
||||
<div class="settings__role" style="{{ role.role_colour|html_colour('--accent-colour') }}">
|
||||
<div class="settings__role__content">
|
||||
<div class="settings__role__name">
|
||||
{{ role.role_name }}
|
||||
</div>
|
||||
|
||||
<div class="settings__role__description">
|
||||
{{ role.role_description }}
|
||||
</div>
|
||||
|
||||
<form class="settings__role__options" method="post" action="{{ url('settings-account') }}">
|
||||
{{ input_csrf('settings') }}
|
||||
{{ input_hidden('role[id]', role.role_id) }}
|
||||
|
||||
<button class="settings__role__option{% if is_display_role %} settings__role__option--disabled{% endif %}"
|
||||
name="role[mode]" value="display" title="Set this as your display role"
|
||||
{% if is_display_role %}disabled{% endif %}>
|
||||
<i class="far {{ is_display_role ? 'fa-check-square' : 'fa-square' }}"></i>
|
||||
</button>
|
||||
|
||||
<button class="settings__role__option{% if not role.role_can_leave %} settings__role__option--disabled{% endif %}"
|
||||
name="role[mode]" value="leave" title="Leave this role"
|
||||
onclick="return confirm('Are you sure you want to remove {{ role.role_name|replace({"'": "\'"}) }} from your account?')"
|
||||
{% if not role.role_can_leave %}disabled{% endif %}>
|
||||
<i class="fas fa-times-circle"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form action="{{ url('settings-account') }}" method="post" class="container settings__container">
|
||||
{{ container_title('<i class="fas fa-unlock-alt fa-fw"></i> Two Factor Authentication') }}
|
||||
{{ input_csrf('settings') }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>Secure your account by requiring a second step during log in in the form of a time based code. You can use applications like Authy, Google or Microsoft Authenticator or other compliant TOTP applications.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__two-factor">
|
||||
{% if settings_2fa_image is defined and settings_2fa_code is defined %}
|
||||
<div class="settings__two-factor__code">
|
||||
<div class="settings__two-factor__code__text">
|
||||
{{ settings_2fa_code }}
|
||||
</div>
|
||||
<img src="{{ settings_2fa_image }}" alt="{{ settings_2fa_code }}" class="settings__two-factor__code__image">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="settings__two-factor__settings">
|
||||
{% if settings_2fa_enabled %}
|
||||
<div class="settings__two-factor__settings__status">
|
||||
<i class="fas fa-lock fa-fw"></i> Two Factor Authentication is enabled!
|
||||
</div>
|
||||
<button class="input__button" name="tfa[enable]" value="0">Disable</button>
|
||||
{% else %}
|
||||
<div class="settings__two-factor__settings__status">
|
||||
<i class="fas fa-lock-open fa-fw"></i> Two Factor Authentication is disabled.
|
||||
</div>
|
||||
<button class="input__button" name="tfa[enable]" value="1">Enable</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
57
templates/settings/logs.twig
Normal file
57
templates/settings/logs.twig
Normal file
|
@ -0,0 +1,57 @@
|
|||
{% extends 'settings/master.twig' %}
|
||||
{% from 'macros.twig' import container_title, pagination %}
|
||||
{% from 'user/macros.twig' import user_login_attempt, user_account_log %}
|
||||
|
||||
{% set title = 'Settings / Logs' %}
|
||||
|
||||
{% block settings_content %}
|
||||
<div class="container settings__container" id="login-history">
|
||||
{{ container_title('<i class="fas fa-user-lock fa-fw"></i> Login History') }}
|
||||
{% set lhpagination = pagination(login_history_pagination, url('settings-logs'), null, {
|
||||
'ap': account_log_pagination.page > 1 ? account_log_pagination.page : 0,
|
||||
}, 'hp', 'login-history') %}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>These are all the login attempts to your account. If any attempt that you don't recognise is marked as successful your account may be compromised, ask a staff member for advice in this case.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__login-attempts">
|
||||
<div class="settings__login-attempts__pagination">
|
||||
{{ lhpagination }}
|
||||
</div>
|
||||
|
||||
{% for attempt in login_history_list %}
|
||||
{{ user_login_attempt(attempt) }}
|
||||
{% endfor %}
|
||||
|
||||
<div class="settings__login-attempts__pagination">
|
||||
{{ lhpagination }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container settings__container" id="account-log">
|
||||
{{ container_title('<i class="fas fa-file-alt fa-fw"></i> Account Log') }}
|
||||
{% set alpagination = pagination(account_log_pagination, url('settings-logs'), null, {
|
||||
'hp': login_history_pagination.page > 1 ? login_history_pagination.page : 0,
|
||||
}, 'ap', 'account-log') %}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>This is a log of all "important" actions that have been done using your account for your review. If you notice anything strange, please alert the staff.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__account-logs">
|
||||
<div class="settings__account-logs__pagination">
|
||||
{{ alpagination }}
|
||||
</div>
|
||||
|
||||
{% for log in account_log_list %}
|
||||
{{ user_account_log(log, account_log_strings) }}
|
||||
{% endfor %}
|
||||
|
||||
<div class="settings__account-logs__pagination">
|
||||
{{ alpagination }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
51
templates/settings/master.twig
Normal file
51
templates/settings/master.twig
Normal file
|
@ -0,0 +1,51 @@
|
|||
{% extends 'master.twig' %}
|
||||
{% from 'macros.twig' import container_title %}
|
||||
|
||||
{% set menu = [
|
||||
{
|
||||
'icon': 'fas fa-user fa-fw',
|
||||
'title': 'Account',
|
||||
'url': url('settings-account'),
|
||||
},
|
||||
{
|
||||
'icon': 'fas fa-key fa-fw',
|
||||
'title': 'Sessions',
|
||||
'url': url('settings-sessions'),
|
||||
},
|
||||
{
|
||||
'icon': 'fas fa-file-alt fa-fw',
|
||||
'title': 'Logs',
|
||||
'url': url('settings-logs'),
|
||||
},
|
||||
] %}
|
||||
|
||||
{% block content %}
|
||||
{% if errors is defined and errors|length > 0 %}
|
||||
<div class="warning">
|
||||
<div class="warning__content">
|
||||
{% for error in errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="settings__wrapper">
|
||||
<div class="settings__wrapper__sidebar">
|
||||
<div class="container settings__container settings__wrapper__menu">
|
||||
{{ container_title('<i class="fas fa-cogs fa-fw"></i> Settings') }}
|
||||
|
||||
{% for item in menu %}
|
||||
<a href="{{ item.url }}" class="settings__wrapper__link">
|
||||
<i class="{{ item.icon }}"></i> {{ item.title }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings__wrapper__content">
|
||||
{% block settings_content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
43
templates/settings/sessions.twig
Normal file
43
templates/settings/sessions.twig
Normal file
|
@ -0,0 +1,43 @@
|
|||
{% extends 'settings/master.twig' %}
|
||||
{% from 'macros.twig' import container_title, pagination %}
|
||||
{% from 'user/macros.twig' import user_session %}
|
||||
{% from '_layout/input.twig' import input_hidden, input_csrf %}
|
||||
|
||||
{% set title = 'Settings / Sessions' %}
|
||||
|
||||
{% block settings_content %}
|
||||
<div class="container settings__container">
|
||||
{{ container_title('<i class="fas fa-key fa-fw"></i> Sessions') }}
|
||||
|
||||
{% set spagination = pagination(session_pagination, url('settings-sessions')) %}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>These are the active logins to your account, clicking the Kill button will force a logout on that session. Your current login is highlighted with a different colour so you don't accidentally force yourself to logout.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__sessions">
|
||||
<form action="{{ url('settings-sessions') }}" method="post" class="settings__sessions__all">
|
||||
{{ input_csrf('user_session') }}
|
||||
{{ input_hidden('session', 'all') }}
|
||||
|
||||
<button class="input__button">
|
||||
<i class="fas fa-bomb"></i> Kill ALL active sessions
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="settings__sessions__pagination">
|
||||
{{ spagination }}
|
||||
</div>
|
||||
|
||||
<div class="settings__sessions__list">
|
||||
{% for session in session_list %}
|
||||
{{ user_session(session, session.session_id == session_active_id) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="settings__sessions__pagination">
|
||||
{{ spagination }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -131,8 +131,8 @@
|
|||
{{ browser.browser }} on {{ browser.platform }}
|
||||
</div>
|
||||
|
||||
<form class="settings__session__actions" method="post" action="{{ url('settings-index') }}">
|
||||
{{ input_csrf('settings') }}
|
||||
<form class="settings__session__actions" method="post" action="{{ url('settings-sessions') }}">
|
||||
{{ input_csrf('user_session') }}
|
||||
{{ input_hidden('session[]', session.session_id) }}
|
||||
|
||||
<button class="settings__session__action" title="{{ is_current_session ? 'Logout' : 'End Session' }}">
|
||||
|
|
|
@ -1,271 +0,0 @@
|
|||
{% extends 'user/master.twig' %}
|
||||
{% from 'macros.twig' import container_title, pagination %}
|
||||
{% from 'user/macros.twig' import user_session, user_login_attempt, user_account_log %}
|
||||
{% from '_layout/input.twig' import input_hidden, input_csrf, input_text, input_select %}
|
||||
|
||||
{% set title = 'Settings' %}
|
||||
{% set menu = {
|
||||
'account': ['<i class="fas fa-user fa-fw"></i> Account', true],
|
||||
'roles': ['<i class="fas fa-user-check fa-fw"></i> Roles', not is_restricted],
|
||||
'tfa': ['<i class="fas fa-unlock-alt fa-fw"></i> Two Factor Authentication', true],
|
||||
'sessions': ['<i class="fas fa-key fa-fw"></i> Sessions', true],
|
||||
'login-attempts': ['<i class="fas fa-user-lock fa-fw"></i> Login Attempts', true],
|
||||
'account-log': ['<i class="fas fa-file-alt fa-fw"></i> Account Log', true],
|
||||
} %}
|
||||
|
||||
{% block content %}
|
||||
{% if errors|length > 0 %}
|
||||
<div class="warning">
|
||||
<div class="warning__content">
|
||||
{% for error in errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="settings__wrapper">
|
||||
<div class="settings__wrapper__sidebar">
|
||||
<div class="container settings__container settings__wrapper__menu">
|
||||
{{ container_title('Settings') }}
|
||||
|
||||
{% for id, item in menu %}
|
||||
{% if item[1] %}
|
||||
<a href="#{{ id }}" class="settings__wrapper__link">
|
||||
{{ item[0]|raw }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings__wrapper__content">
|
||||
<form action="{{ url('settings-index') }}" method="post" class="container settings__container" id="account">
|
||||
{{ container_title('<i class="fas fa-user fa-fw"></i> Account') }}
|
||||
{{ input_csrf('settings') }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>Here you can change your e-mail address and/or your password, please make sure your e-mail is accurate and your password is strong in order to protect your account. For convenience your current e-mail address is displayed. You are required to verify yourself by entering your current password to change either value.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__account">
|
||||
<div class="settings__account__section">
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
New e-mail address
|
||||
</div>
|
||||
{{ input_text('email[new]', 'settings__account__input', '', 'email', current_email) }}
|
||||
</label>
|
||||
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
Confirm new e-mail address
|
||||
</div>
|
||||
{{ input_text('email[confirm]', 'settings__account__input', '', 'email') }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings__account__section">
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
New password
|
||||
</div>
|
||||
{{ input_text('password[new]', 'settings__account__input', '', 'password') }}
|
||||
</label>
|
||||
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
Confirm new password
|
||||
</div>
|
||||
{{ input_text('password[confirm]', 'settings__account__input', '', 'password') }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings__account__section settings__account__section--confirm">
|
||||
<label class="settings__account__input">
|
||||
<div class="settings__account__title">
|
||||
Current password
|
||||
</div>
|
||||
{{ input_text('current_password', 'settings__account__input', '', 'password') }}
|
||||
</label>
|
||||
|
||||
<div class="settings__account__buttons">
|
||||
<button class="input__button settings__account__button">Update</button>
|
||||
<button class="input__button settings__account__button" type="reset">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% if not is_restricted %}
|
||||
<div class="container settings__container" id="roles">
|
||||
{{ container_title('<i class="fas fa-user-check fa-fw"></i> Roles') }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>This is a listing of the user roles you're a part of, you can select which you want to leave or which one you want to boast as your main role which will change your username colour accordingly.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__role__collection">
|
||||
{% for role in user_roles %}
|
||||
{% set is_display_role = user_display_role == role.role_id %}
|
||||
|
||||
<div class="settings__role" style="{{ role.role_colour|html_colour('--accent-colour') }}">
|
||||
<div class="settings__role__content">
|
||||
<div class="settings__role__name">
|
||||
{{ role.role_name }}
|
||||
</div>
|
||||
|
||||
<div class="settings__role__description">
|
||||
{{ role.role_description }}
|
||||
</div>
|
||||
|
||||
<form class="settings__role__options" method="post" action="{{ url('settings-index') }}">
|
||||
{{ input_csrf('settings') }}
|
||||
{{ input_hidden('role[id]', role.role_id) }}
|
||||
|
||||
<button class="settings__role__option{% if is_display_role %} settings__role__option--disabled{% endif %}"
|
||||
name="role[mode]" value="display" title="Set this as your display role"
|
||||
{% if is_display_role %}disabled{% endif %}>
|
||||
<i class="far {{ is_display_role ? 'fa-check-square' : 'fa-square' }}"></i>
|
||||
</button>
|
||||
|
||||
<button class="settings__role__option{% if not role.role_can_leave %} settings__role__option--disabled{% endif %}"
|
||||
name="role[mode]" value="leave" title="Leave this role"
|
||||
onclick="return confirm('Are you sure you want to remove {{ role.role_name|replace({"'": "\'"}) }} from your account?')"
|
||||
{% if not role.role_can_leave %}disabled{% endif %}>
|
||||
<i class="fas fa-times-circle"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form action="{{ url('settings-index') }}" method="post" class="container settings__container" id="tfa">
|
||||
{{ container_title('<i class="fas fa-unlock-alt fa-fw"></i> Two Factor Authentication') }}
|
||||
{{ input_csrf('settings') }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>Secure your account by requiring a second step during log in in the form of a time based code. You can use applications like Authy, Google or Microsoft Authenticator or other compliant TOTP applications.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__two-factor">
|
||||
{% if settings_2fa_image is defined and settings_2fa_code is defined %}
|
||||
<div class="settings__two-factor__code">
|
||||
<div class="settings__two-factor__code__text">
|
||||
{{ settings_2fa_code }}
|
||||
</div>
|
||||
<img src="{{ settings_2fa_image }}" alt="{{ settings_2fa_code }}" class="settings__two-factor__code__image">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="settings__two-factor__settings">
|
||||
{% if settings_2fa_enabled %}
|
||||
<div class="settings__two-factor__settings__status">
|
||||
<i class="fas fa-lock fa-fw"></i> Two Factor Authentication is enabled!
|
||||
</div>
|
||||
<button class="input__button" name="tfa[enable]" value="0">Disable</button>
|
||||
{% else %}
|
||||
<div class="settings__two-factor__settings__status">
|
||||
<i class="fas fa-lock-open fa-fw"></i> Two Factor Authentication is disabled.
|
||||
</div>
|
||||
<button class="input__button" name="tfa[enable]" value="1">Enable</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="container settings__container" id="sessions">
|
||||
{{ container_title('<i class="fas fa-key fa-fw"></i> Sessions') }}
|
||||
{% set spagination = pagination(sessions.pagination, url('settings-index'), null, {
|
||||
'logins_page': logins.pagination.page > 1 ? logins.pagination.page : 0,
|
||||
'logs_page': logs.pagination.page > 1 ? logs.pagination.page : 0,
|
||||
}, 'sessions_page', 'sessions') %}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>These are the active logins to your account, clicking the Kill button will force a logout on that session. Your current login is highlighted with a different colour so you don't accidentally force yourself to logout.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__sessions">
|
||||
<form action="{{ url('settings-index') }}" method="post" class="settings__sessions__all">
|
||||
{{ input_csrf('settings') }}
|
||||
{{ input_hidden('session', 'all') }}
|
||||
|
||||
<button class="input__button">
|
||||
<i class="fas fa-bomb"></i> Kill ALL active sessions
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="settings__sessions__pagination">
|
||||
{{ spagination }}
|
||||
</div>
|
||||
|
||||
<div class="settings__sessions__list">
|
||||
{% for session in sessions.list %}
|
||||
{{ user_session(session, session.session_id == sessions.active) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="settings__sessions__pagination">
|
||||
{{ spagination }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container settings__container" id="login-attempts">
|
||||
{{ container_title('<i class="fas fa-user-lock fa-fw"></i> Login Attempts') }}
|
||||
{% set lhpagination = pagination(logins.pagination, url('settings-index'), null, {
|
||||
'sessions_page': sessions.pagination.page > 1 ? sessions.pagination.page : 0,
|
||||
'logs_page': logs.pagination.page > 1 ? logs.pagination.page : 0,
|
||||
}, 'logins_page', 'login-attempts') %}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>These are all the login attempts to your account. If any attempt that you don't recognise is marked as successful your account may be compromised, ask a staff member for advice in this case.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__login-attempts">
|
||||
<div class="settings__login-attempts__pagination">
|
||||
{{ lhpagination }}
|
||||
</div>
|
||||
|
||||
{% for attempt in logins.list %}
|
||||
{{ user_login_attempt(attempt) }}
|
||||
{% endfor %}
|
||||
|
||||
<div class="settings__login-attempts__pagination">
|
||||
{{ lhpagination }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container settings__container" id="account-log">
|
||||
{{ container_title('<i class="fas fa-file-alt fa-fw"></i> Account Log') }}
|
||||
{% set alpagination = pagination(logs.pagination, url('settings-index'), null, {
|
||||
'sessions_page': sessions.pagination.page > 1 ? sessions.pagination.page : 0,
|
||||
'logins_page': logins.pagination.page > 1 ? logins.pagination.page : 0,
|
||||
}, 'logs_page', 'account-log') %}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>This is a log of all "important" actions that have been done using your account for your review. If you notice anything strange, please alert the staff.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__account-logs">
|
||||
<div class="settings__account-logs__pagination">
|
||||
{{ alpagination }}
|
||||
</div>
|
||||
|
||||
{% for log in logs.list %}
|
||||
{{ user_account_log(log, logs.strings) }}
|
||||
{% endfor %}
|
||||
|
||||
<div class="settings__account-logs__pagination">
|
||||
{{ alpagination }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Add table
Reference in a new issue