Completed user quota implementation

This commit is contained in:
Sergio Brighenti 2020-03-01 17:03:07 +01:00
parent a5b8db5330
commit 17c24860b2
19 changed files with 191 additions and 133 deletions

View file

@ -25,32 +25,22 @@ class AdminController extends Controller
*/ */
public function system(Request $request, Response $response): Response public function system(Request $request, Response $response): Response
{ {
$usersCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `users`')->fetch()->count;
$mediasCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count;
$orphanFilesCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `user_id` IS NULL')->fetch()->count;
$totalSize = $this->database->query('SELECT SUM(`current_disk_quota`) AS `sum` FROM `users`')->fetch()->sum ?? 0;
$registerEnabled = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'register_enabled\'')->fetch()->value ?? 'off';
$hideByDefault = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'hide_by_default\'')->fetch()->value ?? 'off';
$copyUrl = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'copy_url_behavior\'')->fetch()->value ?? 'off';
$quotaEnabled = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'quota_enabled\'')->fetch()->value ?? 'off';
$defaultUserQuota = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'default_user_quota\'')->fetch()->value ?? stringToBytes('1G');
return view()->render($response, 'dashboard/system.twig', [ return view()->render($response, 'dashboard/system.twig', [
'usersCount' => $usersCount, 'usersCount' => $usersCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `users`')->fetch()->count,
'mediasCount' => $mediasCount, 'mediasCount' => $mediasCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count,
'orphanFilesCount' => $orphanFilesCount, 'orphanFilesCount' => $orphanFilesCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `user_id` IS NULL')->fetch()->count,
'totalSize' => humanFileSize($totalSize), 'totalSize' => humanFileSize($totalSize = $this->database->query('SELECT SUM(`current_disk_quota`) AS `sum` FROM `users`')->fetch()->sum ?? 0),
'post_max_size' => ini_get('post_max_size'), 'post_max_size' => ini_get('post_max_size'),
'upload_max_filesize' => ini_get('upload_max_filesize'), 'upload_max_filesize' => ini_get('upload_max_filesize'),
'installed_lang' => $this->lang->getList(), 'installed_lang' => $this->lang->getList(),
'forced_lang' => $request->getAttribute('forced_lang'), 'forced_lang' => $request->getAttribute('forced_lang'),
'php_version' => phpversion(), 'php_version' => phpversion(),
'max_memory' => ini_get('memory_limit'), 'max_memory' => ini_get('memory_limit'),
'register_enabled' => $registerEnabled, 'register_enabled' => $this->getSetting('register_enabled', 'off'),
'hide_by_default' => $hideByDefault, 'hide_by_default' => $this->getSetting('hide_by_default', 'off'),
'copy_url_behavior' => $copyUrl, 'copy_url_behavior' => $this->getSetting('copy_url_behavior', 'off'),
'quota_enabled' => $quotaEnabled, 'quota_enabled' => $this->getSetting('quota_enabled', 'off'),
'default_user_quota' => humanFileSize($defaultUserQuota, 0, true), 'default_user_quota' => humanFileSize($this->getSetting('default_user_quota', stringToBytes('1G')), 0, true),
]); ]);
} }

View file

@ -23,10 +23,8 @@ class LoginController extends Controller
return redirect($response, route('home')); return redirect($response, route('home'));
} }
$registerEnabled = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'register_enabled\'')->fetch()->value ?? 'off';
return view()->render($response, 'auth/login.twig', [ return view()->render($response, 'auth/login.twig', [
'register_enabled' => $registerEnabled, 'register_enabled' => $this->getSetting('register_enabled', 'off'),
]); ]);
} }
@ -41,35 +39,34 @@ class LoginController extends Controller
public function login(Request $request, Response $response): Response public function login(Request $request, Response $response): Response
{ {
$username = param($request, 'username'); $username = param($request, 'username');
$result = $this->database->query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$username, $username])->fetch(); $user = $this->database->query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active`, `current_disk_quota`, `max_disk_quota` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$username, $username])->fetch();
if (!$result || !password_verify(param($request, 'password'), $result->password)) { if (!$user || !password_verify(param($request, 'password'), $user->password)) {
$this->session->alert(lang('bad_login'), 'danger'); $this->session->alert(lang('bad_login'), 'danger');
return redirect($response, route('login')); return redirect($response, route('login'));
} }
if (isset($this->config['maintenance']) && $this->config['maintenance'] && !$result->is_admin) { if (isset($this->config['maintenance']) && $this->config['maintenance'] && !$user->is_admin) {
$this->session->alert(lang('maintenance_in_progress'), 'info'); $this->session->alert(lang('maintenance_in_progress'), 'info');
return redirect($response, route('login')); return redirect($response, route('login'));
} }
if (!$result->active) { if (!$user->active) {
$this->session->alert(lang('account_disabled'), 'danger'); $this->session->alert(lang('account_disabled'), 'danger');
return redirect($response, route('login')); return redirect($response, route('login'));
} }
$this->session->set('logged', true); $this->session->set('logged', true);
$this->session->set('user_id', $result->id); $this->session->set('user_id', $user->id);
$this->session->set('username', $result->username); $this->session->set('username', $user->username);
$this->session->set('admin', $result->is_admin); $this->session->set('admin', $user->is_admin);
// TODO: update $this->setSessionQuotaInfo($user->current_disk_quota, $user->max_disk_quota);
$this->session->set('used_space', humanFileSize($this->getUsedSpaceByUser($result->id)));
$this->session->alert(lang('welcome', [$result->username]), 'info'); $this->session->alert(lang('welcome', [$user->username]), 'info');
$this->logger->info("User $result->username logged in."); $this->logger->info("User $user->username logged in.");
if (param($request, 'remember') === 'on') { if (param($request, 'remember') === 'on') {
$this->refreshRememberCookie($result->id); $this->refreshRememberCookie($user->id);
} }
if ($this->session->has('redirectTo')) { if ($this->session->has('redirectTo')) {

View file

@ -27,8 +27,7 @@ class RegisterController extends Controller
return redirect($response, route('home')); return redirect($response, route('home'));
} }
$registerEnabled = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'register_enabled\'')->fetch()->value ?? 'off'; if ($this->getSetting('register_enabled', 'off') === 'off') {
if ($registerEnabled === 'off') {
throw new HttpNotFoundException($request); throw new HttpNotFoundException($request);
} }
@ -48,8 +47,7 @@ class RegisterController extends Controller
return redirect($response, route('home')); return redirect($response, route('home'));
} }
$registerEnabled = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'register_enabled\'')->fetch()->value ?? 'off'; if ($this->getSetting('register_enabled', 'off') === 'off') {
if ($registerEnabled === 'off') {
throw new HttpNotFoundException($request); throw new HttpNotFoundException($request);
} }

View file

@ -53,13 +53,33 @@ abstract class Controller
} }
/** /**
* @param $id * @param $key
* * @param null $default
* @return object * @return object
*/ */
protected function getUsedSpaceByUser($id) protected function getSetting($key, $default = null)
{ {
return $this->database->query('SELECT `current_disk_quota`, `max_disk_quota` FROM `users` WHERE `id` = ?', $id)->fetch(); return $this->database->query('SELECT `value` FROM `settings` WHERE `key` = '.$this->database->getPdo()->quote($key))->fetch()->value ?? $default;
}
/**
* @param $current
* @param $max
*/
protected function setSessionQuotaInfo($current, $max)
{
$this->session->set('current_disk_quota', humanFileSize($current));
if ($this->getSetting('quota_enabled', 'off') === 'on') {
if ($max < 0) {
$this->session->set('max_disk_quota', '∞');
} else {
$this->session->set('max_disk_quota', humanFileSize($max));
$this->session->set('percent_disk_quota', round(($current * 100) / $max));
}
} else {
$this->session->set('max_disk_quota', null);
$this->session->set('percent_disk_quota', null);
}
} }
/** /**
@ -80,8 +100,7 @@ abstract class Controller
} else { } else {
$tot = $user->current_disk_quota + $fileSize; $tot = $user->current_disk_quota + $fileSize;
$quotaEnabled = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'quota_enabled\'')->fetch()->value ?? 'off'; if ($this->getSetting('quota_enabled') === 'on' && $user->max_disk_quota > 0 && $user->max_disk_quota < $tot) {
if ($quotaEnabled === 'on' && $user->max_disk_quota > 0 && $user->max_disk_quota < $tot) {
return false; return false;
} }
} }

View file

@ -9,8 +9,8 @@ use Psr\Http\Message\ServerRequestInterface as Request;
class DashboardController extends Controller class DashboardController extends Controller
{ {
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* *
* @return Response * @return Response
*/ */
@ -24,15 +24,15 @@ class DashboardController extends Controller
} }
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* @param int|null $page * @param int|null $page
* *
* @throws \Twig\Error\LoaderError * @return Response
* @throws \Twig\Error\RuntimeError * @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError * @throws \Twig\Error\SyntaxError
* *
* @return Response * @throws \Twig\Error\LoaderError
*/ */
public function home(Request $request, Response $response, int $page = 0): Response public function home(Request $request, Response $response, int $page = 0): Response
{ {
@ -58,23 +58,21 @@ class DashboardController extends Controller
->search(param($request, 'search', null)) ->search(param($request, 'search', null))
->run($page); ->run($page);
$copyUrl = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'copy_url_behavior\'')->fetch()->value ?? 'off';
return view()->render( return view()->render(
$response, $response,
($this->session->get('admin', false) && $this->session->get('gallery_view', true)) ? 'dashboard/list.twig' : 'dashboard/grid.twig', ($this->session->get('admin', false) && $this->session->get('gallery_view', true)) ? 'dashboard/list.twig' : 'dashboard/grid.twig',
[ [
'medias' => $query->getMedia(), 'medias' => $query->getMedia(),
'next' => $page < floor($query->getPages()), 'next' => $page < floor($query->getPages()),
'previous' => $page >= 1, 'previous' => $page >= 1,
'current_page' => ++$page, 'current_page' => ++$page,
'copy_url_behavior' => $copyUrl, 'copy_url_behavior' => $this->getSetting('copy_url_behavior', 'off'),
] ]
); );
} }
/** /**
* @param Response $response * @param Response $response
* *
* @return Response * @return Response
*/ */

View file

@ -66,14 +66,12 @@ class MediaController extends Controller
throw new HttpNotFoundException($request); throw new HttpNotFoundException($request);
} }
$copyUrl = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'copy_url_behavior\'')->fetch()->value ?? 'off';
return view()->render($response, 'upload/public.twig', [ return view()->render($response, 'upload/public.twig', [
'delete_token' => $token, 'delete_token' => $token,
'media' => $media, 'media' => $media,
'type' => $type, 'type' => $type,
'url' => urlFor("/{$userCode}/{$mediaCode}"), 'url' => urlFor("/{$userCode}/{$mediaCode}"),
'copy_url_behavior' => $copyUrl, 'copy_url_behavior' => $this->getSetting('copy_url_behavior', 'off'),
]); ]);
} }
@ -203,8 +201,10 @@ class MediaController extends Controller
$size = $this->deleteMedia($request, $media->storage_path, $id); $size = $this->deleteMedia($request, $media->storage_path, $id);
$this->updateUserQuota($request, $media->user_id, $size, true); $this->updateUserQuota($request, $media->user_id, $size, true);
$this->logger->info('User '.$this->session->get('username').' deleted a media.', [$id]); $this->logger->info('User '.$this->session->get('username').' deleted a media.', [$id]);
//TODO update if ($media->user_id === $this->session->get('user_id')) {
$this->session->set('used_space', humanFileSize($this->getUsedSpaceByUser($this->session->get('user_id')))); $user = $this->getUser($request, $media->user_id, true);
$this->setSessionQuotaInfo($user->current_disk_quota, $user->max_disk_quota);
}
} else { } else {
throw new HttpUnauthorizedException($request); throw new HttpUnauthorizedException($request);
} }

View file

@ -13,6 +13,8 @@ class SettingController extends Controller
* @param Response $response * @param Response $response
* *
* @return Response * @return Response
* @throws \Slim\Exception\HttpNotFoundException
* @throws \Slim\Exception\HttpUnauthorizedException
*/ */
public function saveSettings(Request $request, Response $response): Response public function saveSettings(Request $request, Response $response): Response
{ {
@ -24,6 +26,10 @@ class SettingController extends Controller
$this->updateSetting('register_enabled', param($request, 'register_enabled', 'off')); $this->updateSetting('register_enabled', param($request, 'register_enabled', 'off'));
$this->updateSetting('hide_by_default', param($request, 'hide_by_default', 'off')); $this->updateSetting('hide_by_default', param($request, 'hide_by_default', 'off'));
$this->updateSetting('quota_enabled', param($request, 'quota_enabled', 'off')); $this->updateSetting('quota_enabled', param($request, 'quota_enabled', 'off'));
$user = $this->getUser($request, $this->session->get('user_id'));
$this->setSessionQuotaInfo($user->current_disk_quota, $user->max_disk_quota);
$this->updateSetting('default_user_quota', stringToBytes(param($request, 'default_user_quota', '1G'))); $this->updateSetting('default_user_quota', stringToBytes(param($request, 'default_user_quota', '1G')));
$this->updateSetting('copy_url_behavior', param($request, 'copy_url_behavior') === null ? 'default' : 'raw'); $this->updateSetting('copy_url_behavior', param($request, 'copy_url_behavior') === null ? 'default' : 'raw');

View file

@ -38,9 +38,8 @@ class UploadController extends Controller
* @param Response $response * @param Response $response
* *
* @return Response * @return Response
* @throws FileExistsException * @throws \Slim\Exception\HttpNotFoundException
* @throws \Exception * @throws \Slim\Exception\HttpUnauthorizedException
*
*/ */
public function upload(Request $request, Response $response): Response public function upload(Request $request, Response $response): Response
{ {
@ -109,7 +108,7 @@ class UploadController extends Controller
} while ($this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `code` = ?', $code)->fetch()->count > 0); } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `code` = ?', $code)->fetch()->count > 0);
$published = 1; $published = 1;
if (($this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'hide_by_default\'')->fetch()->value ?? 'off') === 'on') { if ($this->getSetting('hide_by_default') === 'on') {
$published = 0; $published = 0;
} }

View file

@ -12,14 +12,14 @@ class UserController extends Controller
const PER_PAGE = 15; const PER_PAGE = 15;
/** /**
* @param Response $response * @param Response $response
* @param int|null $page * @param int|null $page
* *
* @throws \Twig\Error\LoaderError * @return Response
* @throws \Twig\Error\RuntimeError * @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError * @throws \Twig\Error\SyntaxError
* *
* @return Response * @throws \Twig\Error\LoaderError
*/ */
public function index(Response $response, int $page = 0): Response public function index(Response $response, int $page = 0): Response
{ {
@ -32,31 +32,35 @@ class UserController extends Controller
return view()->render($response, return view()->render($response,
'user/index.twig', 'user/index.twig',
[ [
'users' => $users, 'users' => $users,
'next' => $page < floor($pages), 'next' => $page < floor($pages),
'previous' => $page >= 1, 'previous' => $page >= 1,
'current_page' => ++$page, 'current_page' => ++$page,
'quota_enabled' => $this->getSetting('quota_enabled'),
] ]
); );
} }
/** /**
* @param Response $response * @param Response $response
* *
* @throws \Twig\Error\LoaderError * @return Response
* @throws \Twig\Error\RuntimeError * @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError * @throws \Twig\Error\SyntaxError
* *
* @return Response * @throws \Twig\Error\LoaderError
*/ */
public function create(Response $response): Response public function create(Response $response): Response
{ {
return view()->render($response, 'user/create.twig'); return view()->render($response, 'user/create.twig', [
'default_user_quota' => humanFileSize($this->getSetting('default_user_quota'), 0, true),
'quota_enabled' => $this->getSetting('quota_enabled', 'off'),
]);
} }
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* *
* @return Response * @return Response
*/ */
@ -92,13 +96,26 @@ class UserController extends Controller
return redirect($response, route('user.create')); return redirect($response, route('user.create'));
} }
$maxUserQuota = -1;
if ($this->getSetting('quota_enabled') === 'on') {
$maxUserQuota = param($request, 'max_user_quota', humanFileSize($this->getSetting('default_user_quota'), 0, true));
if (!preg_match('/([0-9]+[K|M|G|T])|(\-1)/i', $maxUserQuota)) {
$this->session->alert(lang('invalid_quota', 'danger'));
return redirect($response, route('user.create'));
}
if ($maxUserQuota !== '-1') {
$maxUserQuota = stringToBytes($maxUserQuota);
}
}
do { do {
$userCode = humanRandomString(5); $userCode = humanRandomString(5);
} while ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `user_code` = ?', $userCode)->fetch()->count > 0); } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `user_code` = ?', $userCode)->fetch()->count > 0);
$token = $this->generateUserUploadToken(); $token = $this->generateUserUploadToken();
$this->database->query('INSERT INTO `users`(`email`, `username`, `password`, `is_admin`, `active`, `user_code`, `token`) VALUES (?, ?, ?, ?, ?, ?, ?)', [ $this->database->query('INSERT INTO `users`(`email`, `username`, `password`, `is_admin`, `active`, `user_code`, `token`, `max_disk_quota`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [
param($request, 'email'), param($request, 'email'),
param($request, 'username'), param($request, 'username'),
password_hash(param($request, 'password'), PASSWORD_DEFAULT), password_hash(param($request, 'password'), PASSWORD_DEFAULT),
@ -106,6 +123,7 @@ class UserController extends Controller
param($request, 'is_active') !== null ? 1 : 0, param($request, 'is_active') !== null ? 1 : 0,
$userCode, $userCode,
$token, $token,
$maxUserQuota,
]); ]);
$this->session->alert(lang('user_created', [param($request, 'username')]), 'success'); $this->session->alert(lang('user_created', [param($request, 'username')]), 'success');
@ -115,17 +133,17 @@ class UserController extends Controller
} }
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* @param $id * @param $id
* *
* @throws HttpNotFoundException * @return Response
* @throws \Twig\Error\LoaderError * @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError * @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError * @throws \Twig\Error\SyntaxError
* @throws HttpUnauthorizedException * @throws HttpUnauthorizedException
* *
* @return Response * @throws HttpNotFoundException
*/ */
public function edit(Request $request, Response $response, int $id): Response public function edit(Request $request, Response $response, int $id): Response
{ {
@ -133,19 +151,21 @@ class UserController extends Controller
return view()->render($response, 'user/edit.twig', [ return view()->render($response, 'user/edit.twig', [
'profile' => false, 'profile' => false,
'user' => $user, 'user' => $user,
'quota_enabled' => $this->getSetting('quota_enabled', 'off'),
'max_disk_quota' => $user->max_disk_quota > 0 ? humanFileSize($user->max_disk_quota, 0, true) : -1,
]); ]);
} }
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* @param int $id * @param int $id
*
* @throws HttpNotFoundException
* @throws HttpUnauthorizedException
* *
* @return Response * @return Response
* @throws HttpUnauthorizedException
*
* @throws HttpNotFoundException
*/ */
public function update(Request $request, Response $response, int $id): Response public function update(Request $request, Response $response, int $id): Response
{ {
@ -181,21 +201,35 @@ class UserController extends Controller
return redirect($response, route('user.edit', ['id' => $id])); return redirect($response, route('user.edit', ['id' => $id]));
} }
if ($this->getSetting('quota_enabled') === 'on') {
$maxUserQuota = param($request, 'max_user_quota', humanFileSize($this->getSetting('default_user_quota'), 0, true));
if (!preg_match('/([0-9]+[K|M|G|T])|(\-1)/i', $maxUserQuota)) {
$this->session->alert(lang('invalid_quota', 'danger'));
return redirect($response, route('user.create'));
}
if ($maxUserQuota !== '-1') {
$user->max_disk_quota = stringToBytes($maxUserQuota);
}
}
if (param($request, 'password') !== null && !empty(param($request, 'password'))) { if (param($request, 'password') !== null && !empty(param($request, 'password'))) {
$this->database->query('UPDATE `users` SET `email`=?, `username`=?, `password`=?, `is_admin`=?, `active`=? WHERE `id` = ?', [ $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `password`=?, `is_admin`=?, `active`=?, `max_disk_quota`=? WHERE `id` = ?', [
param($request, 'email'), param($request, 'email'),
param($request, 'username'), param($request, 'username'),
password_hash(param($request, 'password'), PASSWORD_DEFAULT), password_hash(param($request, 'password'), PASSWORD_DEFAULT),
param($request, 'is_admin') !== null ? 1 : 0, param($request, 'is_admin') !== null ? 1 : 0,
param($request, 'is_active') !== null ? 1 : 0, param($request, 'is_active') !== null ? 1 : 0,
$user->max_disk_quota,
$user->id, $user->id,
]); ]);
} else { } else {
$this->database->query('UPDATE `users` SET `email`=?, `username`=?, `is_admin`=?, `active`=? WHERE `id` = ?', [ $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `is_admin`=?, `active`=?, `max_disk_quota`=? WHERE `id` = ?', [
param($request, 'email'), param($request, 'email'),
param($request, 'username'), param($request, 'username'),
param($request, 'is_admin') !== null ? 1 : 0, param($request, 'is_admin') !== null ? 1 : 0,
param($request, 'is_active') !== null ? 1 : 0, param($request, 'is_active') !== null ? 1 : 0,
$user->max_disk_quota,
$user->id, $user->id,
]); ]);
} }
@ -210,14 +244,14 @@ class UserController extends Controller
} }
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* @param int $id * @param int $id
*
* @throws HttpNotFoundException
* @throws HttpUnauthorizedException
* *
* @return Response * @return Response
* @throws HttpUnauthorizedException
*
* @throws HttpNotFoundException
*/ */
public function delete(Request $request, Response $response, int $id): Response public function delete(Request $request, Response $response, int $id): Response
{ {
@ -238,14 +272,14 @@ class UserController extends Controller
} }
/** /**
* @param Request $request * @param Request $request
* @param Response $response * @param Response $response
* @param int $id * @param int $id
*
* @throws HttpNotFoundException
* @throws HttpUnauthorizedException
* *
* @return Response * @return Response
* @throws HttpUnauthorizedException
*
* @throws HttpNotFoundException
*/ */
public function refreshToken(Request $request, Response $response, int $id): Response public function refreshToken(Request $request, Response $response, int $id): Response
{ {

View file

@ -16,8 +16,7 @@ class InjectMiddleware extends Middleware
*/ */
public function __invoke(Request $request, RequestHandler $handler) public function __invoke(Request $request, RequestHandler $handler)
{ {
$head = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'custom_head\'')->fetch(); $this->view->getTwig()->addGlobal('customHead', $this->getSetting('custom_head'));
$this->view->getTwig()->addGlobal('customHead', $head->value ?? null);
return $handler->handle($request); return $handler->handle($request);
} }

View file

@ -16,10 +16,10 @@ class LangMiddleware extends Middleware
*/ */
public function __invoke(Request $request, RequestHandler $handler) public function __invoke(Request $request, RequestHandler $handler)
{ {
$forcedLang = $this->database->query('SELECT `value` FROM `settings` WHERE `key` = \'lang\'')->fetch(); $forcedLang = $this->getSetting('lang');
if ($forcedLang) { if ($forcedLang !== null) {
$this->lang::setLang($forcedLang->value); $this->lang::setLang($forcedLang);
$request = $request->withAttribute('forced_lang', $forcedLang->value); $request = $request->withAttribute('forced_lang', $forcedLang);
} }
return $handler->handle($request); return $handler->handle($request);

View file

@ -18,22 +18,21 @@ class RememberMiddleware extends Middleware
public function __invoke(Request $request, RequestHandler $handler) public function __invoke(Request $request, RequestHandler $handler)
{ {
if (!$this->session->get('logged', false) && !empty($request->getCookieParams()['remember'])) { if (!$this->session->get('logged', false) && !empty($request->getCookieParams()['remember'])) {
list($selector, $token) = explode(':', $request->getCookieParams()['remember']); [$selector, $token] = explode(':', $request->getCookieParams()['remember']);
$result = $this->database->query('SELECT `id`, `email`, `username`,`is_admin`, `active`, `remember_token` FROM `users` WHERE `remember_selector` = ? AND `remember_expire` > ? LIMIT 1', $user = $this->database->query('SELECT `id`, `email`, `username`,`is_admin`, `active`, `remember_token`, `current_disk_quota`, `max_disk_quota` FROM `users` WHERE `remember_selector` = ? AND `remember_expire` > ? LIMIT 1',
[$selector, date('Y-m-d\TH:i:s', time())] [$selector, date('Y-m-d\TH:i:s', time())]
)->fetch(); )->fetch();
if ($result && password_verify($token, $result->remember_token) && $result->active) { if ($user && password_verify($token, $user->remember_token) && $user->active) {
$this->session->set('logged', true); $this->session->set('logged', true);
$this->session->set('user_id', $result->id); $this->session->set('user_id', $user->id);
$this->session->set('username', $result->username); $this->session->set('username', $user->username);
$this->session->set('admin', $result->is_admin); $this->session->set('admin', $user->is_admin);
// TODO: update $this->setSessionQuotaInfo($user->current_disk_quota, $user->max_disk_quota);
$this->session->set('used_space', humanFileSize($this->getUsedSpaceByUser($result->id)));
} }
$this->refreshRememberCookie($result->id); $this->refreshRememberCookie($user->id);
} }
return $handler->handle($request); return $handler->handle($request);

View file

@ -120,6 +120,7 @@ return [
'register' => 'Register', 'register' => 'Register',
'register_success' => 'The account has been created, a confirmation email has been sent.', 'register_success' => 'The account has been created, a confirmation email has been sent.',
'default_user_quota' => 'Default User Quota', 'default_user_quota' => 'Default User Quota',
'max_user_quota' => 'Max User Quota',
'invalid_quota' => 'Invalid values as default user quota.', 'invalid_quota' => 'Invalid values as default user quota.',
'mail.activate_text' => "Hi %s!\nthank you for creating your account on %s (%s), click on the following link to activate it:\n\n%s", 'mail.activate_text' => "Hi %s!\nthank you for creating your account on %s (%s), click on the following link to activate it:\n\n%s",
'mail.activate_account' => '%s - Account Activation', 'mail.activate_account' => '%s - Account Activation',

View file

@ -35,8 +35,16 @@
<i class="fas fa-fw fa-user"></i> {{ session.get('username') }} <i class="fas fa-fw fa-user"></i> {{ session.get('username') }}
</a> </a>
<div class="dropdown-menu shadow-sm" aria-labelledby="userDropdown"> <div class="dropdown-menu shadow-sm" aria-labelledby="userDropdown">
<a class="dropdown-item disabled" href="javascript:void(0)">{{ lang('used') }}: {{ session.get('used_space') }}</a> <a class="dropdown-item disabled" href="javascript:void(0)">{{ lang('used') }}: {{ session.get('current_disk_quota') }}{% if session.get('max_disk_quota') %}/{{ session.get('max_disk_quota') }}{% endif %}</a>
{% if session.get('percent_disk_quota') is not null %}
<a class="dropdown-item disabled" href="javascript:void(0)">
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: {{ session.get('percent_disk_quota') }}%" aria-valuenow="{{ session.get('percent_disk_quota') }}" aria-valuemin="0" aria-valuemax="100">{{ session.get('percent_disk_quota') }}%</div>
</div>
</a>
{% endif %}
{% if session.get('admin') %} {% if session.get('admin') %}
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{{ route('switchView') }}"><i class="fas fa-fw fa-sync"></i> {{ lang('switch_to') }}: {{ session.get('gallery_view') is null or session.get('gallery_view') ? lang('gallery') : lang('table') }}</a> <a class="dropdown-item" href="{{ route('switchView') }}"><i class="fas fa-fw fa-sync"></i> {{ lang('switch_to') }}: {{ session.get('gallery_view') is null or session.get('gallery_view') ? lang('gallery') : lang('table') }}</a>
{% endif %} {% endif %}
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>

View file

@ -59,28 +59,24 @@
<div class="card-header"><i class="fas fa-cog fa-fw"></i> {{ lang('system_settings') }}</div> <div class="card-header"><i class="fas fa-cog fa-fw"></i> {{ lang('system_settings') }}</div>
<div class="card-body"> <div class="card-body">
<form method="post" action="{{ route('settings.save') }}"> <form method="post" action="{{ route('settings.save') }}">
<div class="form-group row"> <div class="form-group row">
<label for="register_enabled" class="col-sm-4 col-form-label">{{ lang('register_enabled') }}</label> <label for="register_enabled" class="col-sm-4 col-form-label">{{ lang('register_enabled') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input type="checkbox" name="register_enabled" data-toggle="toggle" {{ register_enabled == 'on' ? 'checked' }}> <input type="checkbox" name="register_enabled" data-toggle="toggle" {{ register_enabled == 'on' ? 'checked' }}>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="hide_by_default" class="col-sm-4 col-form-label">{{ lang('hide_by_default') }}</label> <label for="hide_by_default" class="col-sm-4 col-form-label">{{ lang('hide_by_default') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input type="checkbox" name="hide_by_default" data-toggle="toggle" {{ hide_by_default == 'on' ? 'checked' }}> <input type="checkbox" name="hide_by_default" data-toggle="toggle" {{ hide_by_default == 'on' ? 'checked' }}>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="copy_url_behavior" class="col-sm-4 col-form-label">{{ lang('copy_url_behavior') }}</label> <label for="copy_url_behavior" class="col-sm-4 col-form-label">{{ lang('copy_url_behavior') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input type="checkbox" name="copy_url_behavior" data-toggle="toggle" data-off="Default URL" data-on="Raw URL" data-onstyle="primary" data-offstyle="secondary" {{ copy_url_behavior == 'raw' ? 'checked' }}> <input type="checkbox" name="copy_url_behavior" data-toggle="toggle" data-off="Default URL" data-on="Raw URL" data-onstyle="primary" data-offstyle="secondary" {{ copy_url_behavior == 'raw' ? 'checked' }}>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="themes" class="col-sm-4 col-form-label">{{ lang('theme') }}</label> <label for="themes" class="col-sm-4 col-form-label">{{ lang('theme') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
@ -89,21 +85,19 @@
</select> </select>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="quota_enabled" class="col-sm-4 col-form-label">{{ lang('quota_enabled') }}</label> <label for="quota_enabled" class="col-sm-4 col-form-label">{{ lang('quota_enabled') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input type="checkbox" name="quota_enabled" data-toggle="toggle" {{ quota_enabled == 'on' ? 'checked' }}> <input type="checkbox" name="quota_enabled" data-toggle="toggle" {{ quota_enabled == 'on' ? 'checked' }}>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="default_user_quota" class="col-sm-4 col-form-label">{{ lang('default_user_quota') }}</label> <label for="default_user_quota" class="col-sm-4 col-form-label">{{ lang('default_user_quota') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input type="text" class="form-control" id="default_user_quota" name="default_user_quota" pattern="[0-9]+[K|M|G|T]" title="512M, 2G, 1T, ..." placeholder="1G" value="{{ default_user_quota }}"> <input type="text" class="form-control" id="default_user_quota" name="default_user_quota" pattern="[0-9]+[K|M|G|T]" title="512M, 2G, 1T, ..." placeholder="1G" value="{{ default_user_quota }}">
<small>512M, 2G, 1T, ...</small>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="lang" class="col-sm-4 col-form-label">{{ lang('enforce_language') }}</label> <label for="lang" class="col-sm-4 col-form-label">{{ lang('enforce_language') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
@ -116,7 +110,6 @@
<small>{{ lang('default_lang_behavior') }}</small> <small>{{ lang('default_lang_behavior') }}</small>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="custom_head" class="col-sm-4 col-form-label">{{ lang('custom_head_html') }}</label> <label for="custom_head" class="col-sm-4 col-form-label">{{ lang('custom_head_html') }}</label>
<div class="col-sm-8"> <div class="col-sm-8">
@ -124,7 +117,6 @@
<small>{{ lang('custom_head_html_hint') }}</small> <small>{{ lang('custom_head_html_hint') }}</small>
</div> </div>
</div> </div>
<button type="submit" class="btn btn-outline-success float-right mt-3"> <button type="submit" class="btn btn-outline-success float-right mt-3">
<i class="fas fa-save fa-fw"></i> {{ lang('apply') }} <i class="fas fa-save fa-fw"></i> {{ lang('apply') }}
</button> </button>

View file

@ -20,7 +20,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<form action="{{ route('upload') }}" method="post" id="upload-dropzone" class="dropzone"> <form action="{{ route('upload') }}?web=1" method="post" id="upload-dropzone" class="dropzone">
<div class="fallback"> <div class="fallback">
<input name="file" type="file" multiple> <input name="file" type="file" multiple>
</div> </div>

View file

@ -30,6 +30,15 @@
<input type="password" class="form-control" id="password" placeholder="{{ lang('password') }}" name="password" autocomplete="off" required> <input type="password" class="form-control" id="password" placeholder="{{ lang('password') }}" name="password" autocomplete="off" required>
</div> </div>
</div> </div>
{% if quota_enabled == 'on' %}
<div class="form-group row">
<label for="max_user_quota" class="col-sm-2 col-form-label">{{ lang('max_user_quota') }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="max_user_quota" name="max_user_quota" pattern="([0-9]+[K|M|G|T])|(\-1)" title="512M, 2G, 1T, ..." placeholder="1G" value="{{ default_user_quota }}" required>
<small>512M, 2G, 1T, ... (-1=∞)</small>
</div>
</div>
{% endif %}
<div class="form-group row"> <div class="form-group row">
<label for="is_admin" class="col-sm-2 col-form-label">{{ lang('is_admin') }}</label> <label for="is_admin" class="col-sm-2 col-form-label">{{ lang('is_admin') }}</label>
<div class="col-sm-10"> <div class="col-sm-10">

View file

@ -66,6 +66,15 @@
</div> </div>
</div> </div>
{% if not profile %} {% if not profile %}
{% if quota_enabled == 'on' %}
<div class="form-group row">
<label for="max_user_quota" class="col-sm-2 col-form-label">{{ lang('max_user_quota') }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="max_user_quota" name="max_user_quota" pattern="([0-9]+[K|M|G|T])|(\-1)" title="512M, 2G, 1T, ..." placeholder="1G" value="{{ max_disk_quota }}" required>
<small>512M, 2G, 1T, ... (-1=∞)</small>
</div>
</div>
{% endif %}
<div class="form-group row"> <div class="form-group row">
<label for="is_admin" class="col-sm-2 col-form-label">{{ lang('is_admin') }}</label> <label for="is_admin" class="col-sm-2 col-form-label">{{ lang('is_admin') }}</label>
<div class="col-sm-10"> <div class="col-sm-10">

View file

@ -35,7 +35,7 @@
<td> <td>
<pre>{{ user.user_code|default(lang('none')) }}</pre> <pre>{{ user.user_code|default(lang('none')) }}</pre>
</td> </td>
<td>{{ humanFileSize(user.current_disk_quota) }}</td> <td>{{ humanFileSize(user.current_disk_quota) }}{% if quota_enabled == 'on' %}/{{ user.max_disk_quota > 0 ? humanFileSize(user.max_disk_quota) : '∞' }}{% endif %}</td>
<td> <td>
{% if user.active %} {% if user.active %}
<span class="badge badge-success"><i class="fas fa-check"></i></span> <span class="badge badge-success"><i class="fas fa-check"></i></span>