Added personal role management.

This commit is contained in:
flash 2018-11-17 21:37:18 +01:00
parent 3cb971aa03
commit e7cddfd37e
12 changed files with 226 additions and 31 deletions

View file

@ -0,0 +1,66 @@
.settings__role {
border: 1px solid var(--accent-colour);
background-color: var(--accent-colour);
border-radius: 2px;
margin: 2px;
overflow: none;
width: 200px;
&__collection {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 2px;
}
&__content {
background-color: var(--background-colour-translucent);
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
&__name {
font-size: 1.2em;
line-height: 1.7em;
border-bottom: 1px solid var(--accent-colour);
padding: 0 5px;
}
&__description {
font-size: .9em;
line-height: 1.8em;
padding: 0 2px;
margin: 0 2px;
flex: 1 1 auto;
}
&__options {
flex: 0 0 auto;
display: flex;
font-size: 1.5em;
justify-content: space-evenly;
}
&__option {
border: 0;
background: transparent;
color: inherit;
font: inherit;
text-shadow: inherit;
transition: color .2s;
flex: 0 0 auto;
width: 40px;
height: 40px;
&:not(&--disabled):hover {
color: var(--accent-colour);
cursor: pointer;
}
&--disabled {
opacity: .2;
}
}
}

View file

@ -5,7 +5,7 @@
overflow: hidden;
&--current {
// todo: make this now bad
// todo: make this not bad
background-image: linear-gradient(0deg, #111c, #111c);
background-color: var(--accent-colour);
}

View file

@ -133,6 +133,7 @@ body {
@import "classes/settings/login-history";
@import "classes/settings/session";
@import "classes/settings/sessions";
@import "classes/settings/role";
// News
@import "classes/news/container";

View file

@ -141,23 +141,35 @@ function recursiveConcat(string $source, string $existing = ''): string
return $existing;
}
$doAll = empty($argv[1]) || $argv[1] === 'all';
$doCss = $doAll || $argv[1] === 'css';
$doJs = $doAll || $argv[1] === 'js';
// Make sure we're running from the misuzu root directory.
chdir(__DIR__);
misuzu_log('Cleanup');
createDirIfNotExist(CSS_DIR);
createDirIfNotExist(JS_DIR);
deleteAllFilesInDir(CSS_DIR, '*.css');
deleteAllFilesInDir(JS_DIR, '*.js');
deleteAllFilesInDir(TS_DIR, '*.d.ts');
misuzu_log();
misuzu_log('Compiling LESS');
if ($doCss) {
createDirIfNotExist(CSS_DIR);
deleteAllFilesInDir(CSS_DIR, '*.css');
}
if (!is_file(LESS_DIR . LESS_ENTRY_POINT)) {
if ($doJs) {
createDirIfNotExist(JS_DIR);
deleteAllFilesInDir(JS_DIR, '*.js');
deleteAllFilesInDir(TS_DIR, '*.d.ts');
}
if ($doCss) {
misuzu_log();
misuzu_log('Compiling LESS');
if (!is_file(LESS_DIR . LESS_ENTRY_POINT)) {
misuzu_log('==> ERR: Entry point for this style does not exist (' . basename(LESS_ENTRY_POINT) . ')');
} else {
} else {
system(sprintf(LESS_CMD, escapeshellarg(LESS_DIR . LESS_ENTRY_POINT), LESS_DEST));
}
}
misuzu_log();
@ -169,16 +181,22 @@ define('IMPORT_SEQ', [
'files' => NODE_IMPORT_CSS,
'destination' => NODE_DEST_CSS,
'insert-semicolon' => false,
'do' => $doCss,
],
[
'name' => 'JavaScript',
'files' => NODE_IMPORT_JS,
'destination' => NODE_DEST_JS,
'insert-semicolon' => true,
'do' => $doJs,
],
]);
foreach (IMPORT_SEQ as $sequence) {
if (!$sequence['do']) {
continue;
}
misuzu_log("=> {$sequence['name']}");
$contents = '';
@ -203,12 +221,14 @@ foreach (IMPORT_SEQ as $sequence) {
file_put_contents($sequence['destination'], $contents);
}
misuzu_log();
misuzu_log('Compiling TypeScript');
misuzu_log(shell_exec('tsc --extendedDiagnostics -p tsconfig.json'));
file_put_contents(TS_DEST, recursiveConcat(TS_SRC));
deleteAllFilesInDir(TS_SRC, '*.js');
rmdir(TS_SRC);
if ($doJs) {
misuzu_log();
misuzu_log('Compiling TypeScript');
misuzu_log(shell_exec('tsc --extendedDiagnostics -p tsconfig.json'));
file_put_contents(TS_DEST, recursiveConcat(TS_SRC));
deleteAllFilesInDir(TS_SRC, '*.js');
rmdir(TS_SRC);
}
misuzu_log();
misuzu_log('Copying data...');
@ -222,7 +242,7 @@ foreach (NODE_COPY_DIRECTORY as $source => $dest) {
}
// no need to do this in debug mode, auto reload is enabled and cache is disabled
if (!file_exists(__DIR__ . '/.debug')) {
if ($doAll && !file_exists(__DIR__ . '/.debug')) {
// Clear Twig cache
misuzu_log();
misuzu_log('Deleting template cache');

View file

@ -0,0 +1,22 @@
<?php
namespace Misuzu\DatabaseMigrations\RolesTableExtensions;
use PDO;
function migrate_up(PDO $conn): void
{
$conn->exec("
ALTER TABLE `msz_roles`
CHANGE COLUMN `role_secret` `role_hidden` TINYINT(1) NOT NULL DEFAULT '0' AFTER `role_description`,
ADD COLUMN `role_can_leave` TINYINT(1) NOT NULL DEFAULT '0' AFTER `role_hidden`;
");
}
function migrate_down(PDO $conn): void
{
$conn->exec("
ALTER TABLE `msz_roles`
CHANGE COLUMN `role_hidden` `role_secret` TINYINT(1) NOT NULL DEFAULT '0' AFTER `role_description`,
DROP COLUMN `role_can_leave`;
");
}

View file

@ -375,12 +375,12 @@ switch ($_GET['v'] ?? null) {
$updateRole = db_prepare('
INSERT INTO `msz_roles`
(
`role_name`, `role_hierarchy`, `role_secret`, `role_colour`,
`role_name`, `role_hierarchy`, `role_hidden`, `role_colour`,
`role_description`, `role_title`
)
VALUES
(
:role_name, :role_hierarchy, :role_secret, :role_colour,
:role_name, :role_hierarchy, :role_hidden, :role_colour,
:role_description, :role_title
)
');
@ -389,7 +389,7 @@ switch ($_GET['v'] ?? null) {
UPDATE `msz_roles`
SET `role_name` = :role_name,
`role_hierarchy` = :role_hierarchy,
`role_secret` = :role_secret,
`role_hidden` = :role_hidden,
`role_colour` = :role_colour,
`role_description` = :role_description,
`role_title` = :role_title
@ -400,7 +400,7 @@ switch ($_GET['v'] ?? null) {
$updateRole->bindValue('role_name', $roleName);
$updateRole->bindValue('role_hierarchy', $roleHierarchy);
$updateRole->bindValue('role_secret', $roleSecret ? 1 : 0);
$updateRole->bindValue('role_hidden', $roleSecret ? 1 : 0);
$updateRole->bindValue('role_colour', $roleColour);
$updateRole->bindValue('role_description', $roleDescription);
$updateRole->bindValue('role_title', $roleTitle);

View file

@ -78,7 +78,7 @@ if (!$role) {
$roles = db_query('
SELECT `role_id`, `role_name`, `role_colour`
FROM `msz_roles`
WHERE `role_secret` = 0
WHERE `role_hidden` = 0
ORDER BY `role_id`
')->fetchAll(PDO::FETCH_ASSOC);

View file

@ -51,9 +51,29 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
}
if (!$disableAccountOptions) {
$currentPasswordValid = !empty($_POST['current_password']);
if (!empty($_POST['role'])) {
$roleId = (int)($_POST['role']['id'] ?? 0);
if ($roleId > 0 && user_role_has(user_session_current('user_id'), $roleId)) {
switch ($_POST['role']['mode'] ?? '') {
case 'display':
user_role_set_display(user_session_current('user_id'), $roleId);
break;
case 'leave':
if (user_role_can_leave($roleId)) {
user_role_remove(user_session_current('user_id'), $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 (!$disableAccountOptions && !empty($_POST['current_password'])) {
if (!user_password_verify_db(user_session_current('user_id'), $_POST['current_password'] ?? '')) {
$errors[] = 'Your password was incorrect.';
} else {
@ -158,17 +178,16 @@ $logins['list'] = user_login_attempts_list($sessions['offset'], $sessions['take'
$logs['list'] = audit_log_list($logs['offset'], $logs['take'], user_session_current('user_id'));
$getUserRoles = db_prepare('
SELECT r.`role_id`, r.`role_name`
SELECT r.`role_id`, r.`role_name`, r.`role_description`, r.`role_colour`, r.`role_can_leave`
FROM `msz_user_roles` as ur
LEFT JOIN `msz_roles` as r
ON r.`role_id` = ur.`role_id`
WHERE ur.`user_id` = :user_id
ORDER BY r.`role_hierarchy` DESC
');
$getUserRoles->bindValue('user_id', user_session_current('user_id'));
$userRoles = $getUserRoles->execute() ? $getUserRoles->fetchAll(PDO::FETCH_ASSOC) : [];
var_dump($userRoles);
if (empty($errors)) { // delete this in 2019
$errors[] = 'A few of the elements on this page have been moved to the on-profile editor. To find them, go to your profile and hit the "Edit Profile" button below your avatar.';
}
@ -180,5 +199,6 @@ echo tpl_render('user.settings', [
'sessions' => $sessions,
'logins' => $logins,
'logs' => $logs,
'roles' => $userRoles,
'user_roles' => $userRoles,
'user_display_role' => user_role_get_display(user_session_current('user_id')),
]);

View file

@ -26,6 +26,17 @@ function user_role_remove(int $userId, int $roleId): bool
return $removeRole->execute();
}
function user_role_can_leave(int $roleId): bool
{
$canLeaveRole = db_prepare('
SELECT `role_can_leave` != 0
FROM `msz_roles`
WHERE `role_id` = :role_id
');
$canLeaveRole->bindValue('role_id', $roleId);
return $canLeaveRole->execute() ? (bool)$canLeaveRole->fetchColumn() : false;
}
function user_role_has(int $userId, int $roleId): bool
{
$hasRole = db_prepare('
@ -55,3 +66,18 @@ function user_role_set_display(int $userId, int $roleId): bool
return $setDisplay->execute();
}
function user_role_get_display(int $userId): int
{
if ($userId < 1) {
return MSZ_ROLE_MAIN;
}
$fetchRole = db_prepare('
SELECT `display_role`
FROM `msz_users`
WHERE `user_id` = :user_id
');
$fetchRole->bindValue('user_id', $userId);
return $fetchRole->execute() ? (int)$fetchRole->fetchColumn() : MSZ_ROLE_MAIN;
}

View file

@ -1,4 +1,8 @@
<?php
// Quick note to myself and others about the `display_role` column in the users database.
// Never ever EVER use it for ANYTHING other than determining display colours, there's a small chance that it might not be accurate.
// And even if it were, roles properties are aggregated and thus must all be accounted for.
define('MSZ_PERM_USER_EDIT_PROFILE', 1);
define('MSZ_PERM_USER_CHANGE_AVATAR', 1 << 1);
define('MSZ_PERM_USER_CHANGE_BACKGROUND', 1 << 2);

View file

@ -20,7 +20,7 @@
<label class="form__label">
<div class="form__label__text">Hide Rank</div>
<div class="form__label__input">
{{ input_checkbox('role[secret]', '', edit_role is defined and edit_role.role_secret) }}
{{ input_checkbox('role[secret]', '', edit_role is defined and edit_role.role_hidden) }}
</div>
</label>

View file

@ -92,6 +92,42 @@
<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="/settings.php">
{{ 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 DAWG?')"
{% if not role.role_can_leave %}disabled{% endif %}>
<i class="fas fa-times-circle"></i>
</button>
</form>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="container settings__container" id="sessions">