Implemented custom queries

This commit is contained in:
Sergio Brighenti 2019-01-13 21:27:10 +01:00
parent ca361c8eef
commit 2b8671f0c6
10 changed files with 276 additions and 42 deletions

View file

@ -1,5 +1,7 @@
## v2.4
+ Added function to remove orphaned files.
+ Switch between tab and gallery mode using an admin account.
+ Multiple uploads sorting methods.
+ Internal refactoring and improvements
## v2.3.1

View file

@ -22,7 +22,7 @@ class AdminController extends Controller
$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;
$medias = $this->database->query('SELECT `users`.`user_code`, `uploads`.`code`, `uploads`.`storage_path` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id`')->fetchAll();
$medias = $this->database->query('SELECT `uploads`.`storage_path` FROM `uploads`')->fetchAll();
$totalSize = 0;

View file

@ -2,7 +2,7 @@
namespace App\Controllers;
use League\Flysystem\FileNotFoundException;
use App\Database\Queries\MediaQuery;
use Slim\Http\Request;
use Slim\Http\Response;
@ -39,36 +39,33 @@ class DashboardController extends Controller
$page = isset($args['page']) ? (int)$args['page'] : 0;
$page = max(0, --$page);
if ($this->session->get('admin', false)) {
$medias = $this->database->query('SELECT `uploads`.*, `users`.`user_code`, `users`.`username` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id` ORDER BY `timestamp` DESC LIMIT ? OFFSET ?', [self::PER_PAGE_ADMIN, $page * self::PER_PAGE_ADMIN])->fetchAll();
$pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count / self::PER_PAGE_ADMIN;
} else {
$medias = $this->database->query('SELECT `uploads`.*,`users`.`user_code`, `users`.`username` FROM `uploads` INNER JOIN `users` ON `uploads`.`user_id` = `users`.`id` WHERE `user_id` = ? ORDER BY `timestamp` DESC LIMIT ? OFFSET ?', [$this->session->get('user_id'), self::PER_PAGE, $page * self::PER_PAGE])->fetchAll();
$pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads` WHERE `user_id` = ?', $this->session->get('user_id'))->fetch()->count / self::PER_PAGE;
}
$query = new MediaQuery($this->database, $this->session->get('admin', false));
$filesystem = storage();
foreach ($medias as $media) {
try {
$media->size = humanFileSize($filesystem->getSize($media->storage_path));
$media->mimetype = $filesystem->getMimetype($media->storage_path);
} catch (FileNotFoundException $e) {
$media->size = null;
$media->mimetype = null;
}
$media->extension = pathinfo($media->filename, PATHINFO_EXTENSION);
}
$query->orderBy(MediaQuery::ORDER_NAME)
->withUserId($this->session->get('user_id'))
->run($page);
return $this->view->render(
$response,
$this->session->get('admin', false) ? 'dashboard/admin.twig' : 'dashboard/home.twig',
($this->session->get('admin', false) && $this->session->get('gallery_view', true)) ? 'dashboard/admin.twig' : 'dashboard/home.twig',
[
'medias' => $medias,
'next' => $page < floor($pages),
'medias' => $query->getMedia(),
'next' => $page < floor($query->getPages()),
'previous' => $page >= 1,
'current_page' => ++$page,
]
);
}
/**
* @param Request $request
* @param Response $response
* @param $args
* @return Response
*/
public function switchView(Request $request, Response $response, $args): Response
{
$this->session->set('gallery_view', !$this->session->get('gallery_view', true));
return redirect($response, 'home');
}
}

View file

@ -0,0 +1,201 @@
<?php
namespace App\Database\Queries;
use App\Database\DB;
use League\Flysystem\FileNotFoundException;
use League\Flysystem\Plugin\ListFiles;
class MediaQuery
{
const PER_PAGE = 21;
const PER_PAGE_ADMIN = 25;
const ORDER_TIME = 0;
const ORDER_NAME = 1;
const ORDER_SIZE = 2;
/** @var DB */
protected $db;
/** @var bool */
protected $isAdmin;
protected $userId;
/** @var int */
protected $orderBy;
/** @var string */
protected $orderMode;
/** @var string */
protected $text;
private $pages;
private $media;
/**
* MediaQuery constructor.
* @param DB $db
* @param bool $isAdmin
*/
public function __construct(DB $db, bool $isAdmin)
{
$this->db = $db;
$this->isAdmin = $isAdmin;
}
/**
* @param $id
* @return $this
*/
public function withUserId($id)
{
$this->userId = $id;
return $this;
}
/**
* @param string|null $type
* @param string $mode
* @return $this
*/
public function orderBy(string $type = null, $mode = 'ASC')
{
$this->orderBy = ($type === null) ? self::ORDER_TIME : $type;
$this->orderMode = (strtoupper($mode) === 'ASC') ? 'ASC' : 'DESC';
return $this;
}
/**
* @param string $text
* @return $this
*/
public function search(string $text)
{
$this->text = $text;
return $this;
}
/**
* @param int $page
*/
public function run(int $page)
{
if ($this->orderBy == self::ORDER_SIZE) {
$this->runWithOrderBySize($page);
return;
}
$queryPages = 'SELECT COUNT(*) AS `count` FROM `uploads`';
if ($this->isAdmin) {
$queryMedia = 'SELECT `uploads`.*, `users`.`user_code`, `users`.`username` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id` %s LIMIT ? OFFSET ?';
} else {
$queryMedia = 'SELECT `uploads`.*,`users`.`user_code`, `users`.`username` FROM `uploads` INNER JOIN `users` ON `uploads`.`user_id` = `users`.`id` WHERE `user_id` = ? %s LIMIT ? OFFSET ?';
$queryPages .= ' WHERE `user_id` = ?';
}
switch ($this->orderBy) {
case self::ORDER_NAME:
$queryMedia = sprintf($queryMedia, 'ORDER BY `filename` ' . $this->orderMode);
break;
default:
case self::ORDER_TIME:
$queryMedia = sprintf($queryMedia, 'ORDER BY `timestamp` ' . $this->orderMode);
break;
}
if ($this->isAdmin) {
$this->media = $this->db->query($queryMedia, [self::PER_PAGE_ADMIN, $page * self::PER_PAGE_ADMIN])->fetchAll();
$this->pages = $this->db->query($queryPages)->fetch()->count / self::PER_PAGE_ADMIN;
} else {
$this->media = $this->db->query($queryMedia, [$this->userId, self::PER_PAGE, $page * self::PER_PAGE])->fetchAll();
$this->pages = $this->db->query($queryPages, $this->userId)->fetch()->count / self::PER_PAGE;
}
$filesystem = storage();
foreach ($this->media as $media) {
try {
$media->size = humanFileSize($filesystem->getSize($media->storage_path));
$media->mimetype = $filesystem->getMimetype($media->storage_path);
} catch (FileNotFoundException $e) {
$media->size = null;
$media->mimetype = null;
}
$media->extension = pathinfo($media->filename, PATHINFO_EXTENSION);
}
}
/**
* @param int $page
*/
private function runWithOrderBySize(int $page)
{
$filesystem = storage();
$filesystem->addPlugin(new ListFiles());
if ($this->isAdmin) {
$files = $filesystem->listFiles('/', true);
$this->pages = count($files) / self::PER_PAGE_ADMIN;
$offset = $page * self::PER_PAGE_ADMIN;
$limit = self::PER_PAGE_ADMIN;
} else {
$userCode = $this->db->query('SELECT `user_code` FROM `users` WHERE `id` = ?', [$this->userId])->fetch()->user_code;
$files = $filesystem->listFiles($userCode);
$this->pages = count($files) / self::PER_PAGE;
$offset = $page * self::PER_PAGE;
$limit = self::PER_PAGE;
}
array_multisort(array_column($files, 'size'), ($this->orderMode === 'ASC') ? SORT_ASC : SORT_DESC, SORT_NUMERIC, $files);
$files = array_slice($files, $offset, $limit);
$paths = array_column($files, 'path');
$medias = $this->db->query('SELECT `uploads`.*, `users`.`user_code`, `users`.`username` FROM `uploads` LEFT JOIN `users` ON `uploads`.`user_id` = `users`.`id` WHERE `uploads`.`storage_path` IN ("' . implode('","', $paths) . '")')->fetchAll();
$paths = array_flip($paths);
foreach ($medias as $media) {
$paths[$media->storage_path] = $media;
}
$this->media = [];
foreach ($files as $file) {
$media = $paths[$file['path']];
$media->size = humanFileSize($file['size']);
try {
$media->mimetype = $filesystem->getMimetype($file['path']);
} catch (FileNotFoundException $e) {
$media->mimetype = null;
}
$media->extension = $file['extension'];
$this->media[] = $media;
}
}
/**
* @return mixed
*/
public function getMedia()
{
return $this->media;
}
/**
* @return mixed
*/
public function getPages()
{
return $this->pages;
}
}

View file

@ -158,6 +158,11 @@ if (!function_exists('isBot')) {
}
if (!function_exists('mime2font')) {
/**
* Convert get the icon from the file mimetype
* @param $mime
* @return mixed|string
*/
function mime2font($mime)
{
$classes = [
@ -177,6 +182,7 @@ if (!function_exists('mime2font')) {
'application/vnd.oasis.opendocument.presentation' => 'fa-file-powerpoint',
'text/plain' => 'fa-file-alt',
'text/html' => 'fa-file-code',
'text/x-php' => 'fa-file-code',
'application/json' => 'fa-file-code',
'application/gzip' => 'fa-file-archive',
'application/zip' => 'fa-file-archive',
@ -189,4 +195,19 @@ if (!function_exists('mime2font')) {
}
return 'fa-file';
}
}
if (!function_exists('dd')) {
/**
* Dumps all the giver vars and halt the execution.
*/
function dd()
{
echo '<pre>';
array_map(function ($x) {
print_r($x);
}, func_get_args());
echo '</pre>';
die();
}
}

View file

@ -2,18 +2,24 @@
// Auth routes
$app->group('', function () {
$this->get('/home[/page/{page}]', \App\Controllers\DashboardController::class . ':home')->setName('home');
$this->get('/system/deleteOrphanFiles', \App\Controllers\AdminController::class . ':deleteOrphanFiles')->add(\App\Middleware\AdminMiddleware::class)->setName('system.deleteOrphanFiles');
$this->get('/system/themes', \App\Controllers\ThemeController::class . ':getThemes')->add(\App\Middleware\AdminMiddleware::class)->setName('theme');
$this->post('/system/theme/apply', \App\Controllers\ThemeController::class . ':applyTheme')->add(\App\Middleware\AdminMiddleware::class)->setName('theme.apply');
$this->get('/system', \App\Controllers\AdminController::class . ':system')->add(\App\Middleware\AdminMiddleware::class)->setName('system');
$this->group('', function () {
$this->get('/home/switchView', \App\Controllers\DashboardController::class . ':switchView')->setName('switchView');
$this->get('/system/deleteOrphanFiles', \App\Controllers\AdminController::class . ':deleteOrphanFiles')->setName('system.deleteOrphanFiles');
$this->get('/system/themes', \App\Controllers\ThemeController::class . ':getThemes')->setName('theme');
$this->post('/system/theme/apply', \App\Controllers\ThemeController::class . ':applyTheme')->setName('theme.apply');
$this->get('/system', \App\Controllers\AdminController::class . ':system')->setName('system');
$this->get('/users[/page/{page}]', \App\Controllers\UserController::class . ':index')->setName('user.index');
$this->get('/user/create', \App\Controllers\UserController::class . ':create')->setName('user.create');
$this->post('/user/create', \App\Controllers\UserController::class . ':store')->setName('user.store');
$this->get('/user/{id}/edit', \App\Controllers\UserController::class . ':edit')->setName('user.edit');
$this->post('/user/{id}', \App\Controllers\UserController::class . ':update')->setName('user.update');
$this->get('/user/{id}/delete', \App\Controllers\UserController::class . ':delete')->setName('user.delete');
})->add(\App\Middleware\AdminMiddleware::class);
$this->group('/user', function () {
$this->get('/create', \App\Controllers\UserController::class . ':create')->setName('user.create');
$this->post('/create', \App\Controllers\UserController::class . ':store')->setName('user.store');
$this->get('/{id}/edit', \App\Controllers\UserController::class . ':edit')->setName('user.edit');
$this->post('/{id}', \App\Controllers\UserController::class . ':update')->setName('user.update');
$this->get('/{id}/delete', \App\Controllers\UserController::class . ':delete')->setName('user.delete');
})->add(\App\Middleware\AdminMiddleware::class);
$this->get('/profile', \App\Controllers\UserController::class . ':profile')->setName('profile');

18
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "265c1ca72d526b36b50fcec633b5807f",
"content-hash": "3ffe3637bbcca9dc78923aca4ffdbbe6",
"packages": [
{
"name": "container-interop/container-interop",
@ -859,32 +859,32 @@
},
{
"name": "twig/twig",
"version": "v2.5.0",
"version": "v2.6.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "6a5f676b77a90823c2d4eaf76137b771adf31323"
"reference": "a11dd39f5b6589e14f0ff3b36675d06047c589b1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/6a5f676b77a90823c2d4eaf76137b771adf31323",
"reference": "6a5f676b77a90823c2d4eaf76137b771adf31323",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a11dd39f5b6589e14f0ff3b36675d06047c589b1",
"reference": "a11dd39f5b6589e14f0ff3b36675d06047c589b1",
"shasum": ""
},
"require": {
"php": "^7.0",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "~1.0"
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0",
"symfony/debug": "^2.7",
"symfony/phpunit-bridge": "^3.3"
"symfony/phpunit-bridge": "^3.4.19|^4.1.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5-dev"
"dev-master": "2.6-dev"
}
},
"autoload": {
@ -922,7 +922,7 @@
"keywords": [
"templating"
],
"time": "2018-07-13T07:18:09+00:00"
"time": "2018-12-16T10:36:48+00:00"
}
],
"packages-dev": [],

View file

@ -86,4 +86,7 @@ return [
'cannot_demote' => 'You cannot demote yourself.',
'cannot_write_file' => 'The destination path is not writable.',
'deleted_orphans' => 'Successfully deleted %d orphaned files.',
'switch_to' => 'Switch to',
'gallery' => 'Gallery',
'table' => 'Table',
];

View file

@ -86,4 +86,7 @@ return [
'cannot_demote' => 'Non puoi degradare te stesso. ',
'cannot_write_file' => 'Il percorso di destinazione non è scrivibile.',
'deleted_orphans' => 'Eliminati %d file orfani.',
'switch_to' => 'Vedi come',
'gallery' => 'Galleria',
'table' => 'Tabella',
];

View file

@ -31,6 +31,7 @@
</a>
<div class="dropdown-menu shadow-sm" aria-labelledby="userDropdown">
<a class="dropdown-item disabled" href="javascript:void(0)">{{ lang('used') }}: {{ session.used_space }}</a>
<a class="dropdown-item" href="{{ route('switchView') }}"><i class="fas fa-fw fa-sync"></i> {{ lang('switch_to') }}: {{ session.gallery_view is null or session.gallery_view ? lang('gallery') : lang('table') }}</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{{ route('profile') }}"><i class="fas fa-fw fa-user"></i> {{ lang('profile') }}</a>
<a class="dropdown-item" href="{{ route('logout') }}"><i class="fas fa-fw fa-sign-out-alt"></i> {{ lang('logout') }}</a>