Browse Source

Implemented custom queries

Sergio Brighenti 6 years ago
parent
commit
2b8671f0c6

+ 2 - 0
CHANGELOG.md

@@ -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

+ 1 - 1
app/Controllers/AdminController.php

@@ -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;
 

+ 20 - 23
app/Controllers/DashboardController.php

@@ -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;
-		}
-
-		$filesystem = storage();
+		$query = new MediaQuery($this->database, $this->session->get('admin', false));
 
-		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');
+	}
 }

+ 201 - 0
app/Database/Queries/MediaQuery.php

@@ -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;
+	}
+}

+ 21 - 0
app/helpers.php

@@ -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();
+	}
 }

+ 15 - 9
app/routes.php

@@ -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');

+ 9 - 9
composer.lock

@@ -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": [],

+ 3 - 0
resources/lang/en.lang.php

@@ -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',
 ];

+ 3 - 0
resources/lang/it.lang.php

@@ -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',
 ];

+ 1 - 0
resources/templates/comp/navbar.twig

@@ -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>