Sergio Brighenti пре 6 година
родитељ
комит
2465fdd172

+ 1 - 0
Gruntfile.js

@@ -53,6 +53,7 @@ module.exports = function (grunt) {
                     {expand: true, cwd: 'node_modules/@fortawesome/fontawesome-free', src: ['css/**', 'js/**'], dest: 'static/fontawesome'},
                     {expand: true, cwd: 'node_modules/bootstrap/dist', src: ['**'], dest: 'static/bootstrap'},
                     {expand: true, cwd: 'node_modules/clipboard/dist', src: ['**'], dest: 'static/clipboardjs'},
+                    {expand: true, cwd: 'node_modules/video.js/dist', src: ['video.min.js', 'video-js.min.css'], dest: 'static/videojs'},
                     {expand: true, cwd: 'node_modules/highlightjs', src: ['styles/**/*', 'highlight.pack.min.js'], dest: 'static/highlightjs'},
                     {expand: true, cwd: 'node_modules/jquery/dist', src: ['jquery.min.js'], dest: 'static/jquery'}
                 ],

+ 1 - 1
app/Controllers/LoginController.php

@@ -32,7 +32,7 @@ class LoginController extends Controller
 	public function login(Request $request, Response $response): Response
 	{
 
-		$result = DB::query('SELECT `id`,`username`, `password`,`is_admin`, `active` FROM `users` WHERE `username` = ? LIMIT 1', $request->getParam('username'))->fetch();
+		$result = DB::query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$request->getParam('username'), $request->getParam('username')])->fetch();
 
 		if (!$result || !password_verify($request->getParam('password'), $result->password)) {
 			Session::alert('Wrong credentials', 'danger');

+ 1 - 3
app/Controllers/UploadController.php

@@ -63,10 +63,8 @@ class UploadController extends Controller
 			$storagePath,
 		]);
 
-		$base_url = $this->settings['base_url'];
-
 		$json['message'] = 'OK.';
-		$json['url'] = "$base_url/$user->user_code/$code.$fileInfo[extension]";
+		$json['url'] = urlFor("/$user->user_code/$code.$fileInfo[extension]");
 
 		$this->logger->info("User $user->username uploaded new media.", [$this->database->raw()->lastInsertId()]);
 

+ 0 - 154
install/index.php

@@ -1,154 +0,0 @@
-<?php
-require __DIR__ . '/../vendor/autoload.php';
-
-use App\Database\DB;
-use App\Web\Session;
-use Slim\App;
-use Slim\Container;
-use Slim\Http\Request;
-use Slim\Http\Response;
-
-define('PLATFORM_VERSION', json_decode(file_get_contents(__DIR__ . '/../composer.json'))->version);
-
-$config = [
-	'base_url' => isset($_SERVER['HTTPS']) ? 'https://' . $_SERVER['HTTP_HOST'] : 'http://' . $_SERVER['HTTP_HOST'],
-	'storage_dir' => 'storage',
-	'displayErrorDetails' => true,
-	'db' => [
-		'connection' => 'sqlite',
-		'dsn' => 'resources/database/xbackbone.db',
-		'username' => null,
-		'password' => null,
-	],
-];
-
-$container = new Container(['settings' => $config]);
-
-Session::init('xbackbone_session');
-
-$container['view'] = function ($container) use (&$config) {
-	$view = new \Slim\Views\Twig(__DIR__ . '/templates', [
-		'cache' => false,
-		'autoescape' => 'html',
-		'debug' => $config['displayErrorDetails'],
-		'auto_reload' => $config['displayErrorDetails'],
-	]);
-
-	// Instantiate and add Slim specific extension
-	$router = $container->get('router');
-	$uri = \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER));
-	$view->addExtension(new Slim\Views\TwigExtension($router, $uri));
-
-	$view->getEnvironment()->addGlobal('config', $config);
-	$view->getEnvironment()->addGlobal('request', $container->get('request'));
-	$view->getEnvironment()->addGlobal('alerts', Session::getAlert());
-	$view->getEnvironment()->addGlobal('session', Session::all());
-	$view->getEnvironment()->addGlobal('PLATFORM_VERSION', PLATFORM_VERSION);
-	return $view;
-};
-
-function migrate($config)
-{
-	$firstMigrate = false;
-	if ($config['db']['connection'] === 'sqlite' && !file_exists(__DIR__ . '/../' . $config['db']['dsn'])) {
-		touch(__DIR__ . '/../' . $config['db']['dsn']);
-		$firstMigrate = true;
-	}
-
-	try {
-		DB::query('SELECT 1 FROM `migrations` LIMIT 1');
-	} catch (PDOException $exception) {
-		$firstMigrate = true;
-	}
-
-	if ($firstMigrate) {
-		DB::raw()->exec(file_get_contents(__DIR__ . '/../resources/schemas/migrations.sql'));
-	}
-
-	$files = glob(__DIR__ . '/../resources/schemas/' . DB::driver() . '/*.sql');
-
-	$names = array_map(function ($path) {
-		return basename($path);
-	}, $files);
-
-	$in = str_repeat('?, ', count($names) - 1) . '?';
-
-	$inMigrationsTable = DB::query("SELECT * FROM `migrations` WHERE `name` IN ($in)", $names)->fetchAll();
-
-
-	foreach ($files as $file) {
-
-		$continue = false;
-		$exists = false;
-
-		foreach ($inMigrationsTable as $migration) {
-			if (basename($file) === $migration->name && $migration->migrated) {
-				$continue = true;
-				break;
-			} else if (basename($file) === $migration->name && !$migration->migrated) {
-				$exists = true;
-				break;
-			}
-		}
-		if ($continue) continue;
-
-		$sql = file_get_contents($file);
-		try {
-			DB::raw()->exec($sql);
-			if (!$exists) {
-				DB::query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 1]);
-			} else {
-				DB::query('UPDATE `migrations` SET `migrated`=? WHERE `name`=?', [1, basename($file)]);
-			}
-		} catch (PDOException $exception) {
-			if (!$exists) {
-				DB::query('INSERT INTO `migrations` VALUES (?,?)', [basename($file), 0]);
-			}
-			throw $exception;
-		}
-	}
-}
-
-$app = new App($container);
-
-$app->get('/', function (Request $request, Response $response) {
-
-	$installed = file_exists(__DIR__ . '/../config.php');
-
-	return $this->view->render($response, 'install.twig', ['installed' => $installed]);
-});
-
-$app->post('/', function (Request $request, Response $response) use (&$config) {
-	$installed = true;
-	if (!file_exists(__DIR__ . '/../config.php')) {
-		$installed = false;
-
-		$config['base_url'] = $request->getParam('base_url');
-		$config['storage_dir'] = $request->getParam('storage_dir');
-		$config['displayErrorDetails'] = false;
-		$config['db']['connection'] = $request->getParam('connection');
-		$config['db']['dsn'] = $request->getParam('dsn');
-		$config['db']['username'] = $request->getParam('db_user');
-		$config['db']['password'] = $request->getParam('db_password');
-
-
-		file_put_contents(__DIR__ . '/../config.php', '<?php' . PHP_EOL . 'return ' . var_export($config, true) . ';');
-	}
-
-	$dsn = $config['db']['connection'] === 'sqlite' ? __DIR__ . '/../' . $config['db']['dsn'] : $config['db']['dsn'];
-
-	DB::setDsn($config['db']['connection'] . ':' . $dsn, $config['db']['username'], $config['db']['password']);
-
-	migrate($config);
-
-	if (!$installed) {
-		DB::query("INSERT INTO `users` (`email`, `username`, `password`, `is_admin`, `user_code`) VALUES (?, 'admin', ?, 1, ?)", [$request->getParam('email'), password_hash($request->getParam('password'), PASSWORD_DEFAULT), substr(md5(microtime()), rand(0, 26), 5)]);
-	}
-
-	cleanDirectory(__DIR__ . '/../resources/cache');
-	cleanDirectory(__DIR__ . '/../resources/sessions');
-
-	return $response->withRedirect('../?afterInstall=true');
-});
-
-$app->run();

+ 0 - 153
install/templates/install.twig

@@ -1,153 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-    <title>Installing XBackBone | XBackBone</title>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-    <meta name="description" content="A lightweight PHP backend for ShareX">
-
-    <link href="{{ request.uri }}../static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
-    <link href="{{ request.uri }}../static/highlightjs/styles/monokai.css" rel="stylesheet">
-    <link href="{{ request.uri }}../static/app/app.css" rel="stylesheet">
-
-    <script src="{{ request.uri }}../static/jquery/jquery.min.js"></script>
-    <script src="{{ request.uri }}../static/bootstrap/js/bootstrap.bundle.min.js"></script>
-    <script src="{{ request.uri }}../static/fontawesome/js/all.min.js"></script>
-    <script src="{{ request.uri }}../static/highlightjs/highlight.pack.min.js"></script>
-    <script src="{{ request.uri }}../static/clipboardjs/clipboard.min.js"></script>
-    <script src="{{ request.uri }}../static/app/app.js"></script>
-    <style>
-        html,
-        body {
-            height: 100%;
-        }
-
-        body {
-            display: -ms-flexbox;
-            display: -webkit-box;
-            display: flex;
-            -ms-flex-align: center;
-            -ms-flex-pack: center;
-            -webkit-box-align: center;
-            align-items: center;
-            -webkit-box-pack: center;
-            justify-content: center;
-            padding-bottom: 40px;
-            background-color: #f5f5f5;
-            margin-bottom: 0;
-        }
-    </style>
-</head>
-<body>
-<div class="container">
-    <div class="row justify-content-center">
-        <div class="col-md-8">
-            <div class="card mt-3">
-                <div class="card-header">Install XBackBone</div>
-                <div class="card-body">
-                    <form method="post" action="">
-                        {% if not installed %}
-                            <div class="form-group row">
-                                <label for="base_url" class="col-sm-3 col-form-label">Base URL</label>
-                                <div class="col-sm-9">
-                                    <input type="text" class="form-control" id="base_url" name="base_url" value="{{ config.base_url }}" autocomplete="off" required>
-                                    <small>No trailing slash.</small>
-                                </div>
-                            </div>
-                            <hr>
-                            <div class="form-group row">
-                                <label for="connection" class="col-sm-3 col-form-label">SQL Engine</label>
-                                <div class="col-sm-9">
-                                    <select name="connection" id="connection" required class="form-control">
-                                        <option value="sqlite" selected>SQLite</option>
-                                        <option value="mysql">MySQL</option>
-                                    </select>
-                                </div>
-                            </div>
-
-                            <div class="form-group row">
-                                <label for="dsn" class="col-sm-3 col-form-label">Database Source Name (DSN)</label>
-                                <div class="col-sm-9">
-                                    <input type="text" class="form-control" id="dsn" name="dsn" value="{{ config.db.dsn }}" autocomplete="off" required>
-                                </div>
-                            </div>
-
-                            <div class="form-group row">
-                                <label for="db_user" class="col-sm-3 col-form-label">Database Username</label>
-                                <div class="col-sm-9">
-                                    <input type="text" class="form-control" id="db_user" name="db_user" autocomplete="off" disabled>
-                                </div>
-                            </div>
-
-                            <div class="form-group row">
-                                <label for="db_password" class="col-sm-3 col-form-label">Database Password</label>
-                                <div class="col-sm-9">
-                                    <input type="password" class="form-control" id="db_password" name="db_password" autocomplete="off" disabled>
-                                </div>
-                            </div>
-                            <hr>
-                            <div class="form-group row">
-                                <label for="storage_dir" class="col-sm-3 col-form-label">Storage Directory</label>
-                                <div class="col-sm-9">
-                                    <input type="text" class="form-control" id="storage_dir" name="storage_dir" value="{{ config.storage_dir }}" autocomplete="off" required>
-                                    <small>Must be a writable directory</small>
-                                </div>
-                            </div>
-                            <hr>
-                            <div class="form-group row">
-                                <label for="email" class="col-sm-3 col-form-label">Admin email</label>
-                                <div class="col-sm-9">
-                                    <input type="email" class="form-control" id="email" placeholder="email@example.com" name="email" autocomplete="off" required>
-                                </div>
-                            </div>
-
-                            <div class="form-group row">
-                                <label for="password" class="col-sm-3 col-form-label">Admin password</label>
-                                <div class="col-sm-9">
-                                    <input type="password" class="form-control" id="password" placeholder="Password" name="password" autocomplete="off" required>
-                                </div>
-                            </div>
-
-                            <div class="form-group row justify-content-md-end">
-                                <div class="col-sm-9">
-                                    <button type="submit" class="btn btn-outline-success">
-                                        <i class="fas fa-save fa-fw"></i> Configure & Install
-                                    </button>
-                                </div>
-                            </div>
-
-                        {% else %}
-                            <div class="form-group row">
-                                <div class="col-sm-12 d-flex justify-content-center">
-                                    <button type="submit" class="btn btn-lg btn-outline-primary">
-                                        <i class="fas fa-sync fa-fw"></i> Update database
-                                    </button>
-                                </div>
-                            </div>
-                        {% endif %}
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-<script>
-    $(document).ready(function () {
-        $('#connection').change(function () {
-            switch ($(this).val()) {
-                case 'sqlite':
-                    $('#dsn').val('resources/database/xbackbone.db');
-                    $('#db_user').val('').prop('disabled', 'disabled');
-                    $('#db_password').val('').prop('disabled', 'disabled');
-                    break;
-                case 'mysql':
-                    $('#dsn').val('host=localhost;port=3306;dbname=xbackbone');
-                    $('#db_user').val('db_user').prop('disabled', '');
-                    $('#db_password').val('').prop('disabled', '');
-                    break;
-            }
-        });
-    })
-</script>
-</body>
-</html>

+ 6 - 2
resources/templates/auth/login.twig

@@ -4,7 +4,11 @@
 
 {% block head %}
     <style>
+        html {
+            height: 100%;
+        }
         body {
+            height: 100%;
             display: -ms-flexbox;
             display: -webkit-box;
             display: flex;
@@ -32,8 +36,8 @@
             </div>
             <div class="row">
                 <div class="col-md-12">
-                    <label for="inputEmail" class="sr-only">Username</label>
-                    <input type="text" id="username" class="form-control" placeholder="Username" name="username" required autofocus>
+                    <label for="inputEmail" class="sr-only">Username or E-Mail</label>
+                    <input type="text" id="username" class="form-control" placeholder="Username or E-Mail" name="username" required autofocus>
                     <label for="password" class="sr-only">Password</label>
                     <input type="password" id="password" class="form-control" placeholder="Password" name="password" required>
                 </div>

+ 2 - 0
resources/templates/base.twig

@@ -8,6 +8,7 @@
     
     <link href="{{ config.base_url }}/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
     <link href="{{ config.base_url }}/static/highlightjs/styles/monokai.css" rel="stylesheet">
+    <link href="{{ config.base_url }}/static/videojs/video-js.min.css" rel="stylesheet">
     <link href="{{ config.base_url }}/static/app/app.css" rel="stylesheet">
 	
 	<script src="{{ config.base_url }}/static/jquery/jquery.min.js"></script>
@@ -15,6 +16,7 @@
     <script src="{{ config.base_url }}/static/fontawesome/js/all.min.js"></script>
     <script src="{{ config.base_url }}/static/highlightjs/highlight.pack.min.js"></script>
     <script src="{{ config.base_url }}/static/clipboardjs/clipboard.min.js"></script>
+    <script src="{{ config.base_url }}/static/videojs/video.min.js"></script>
     <script src="{{ config.base_url }}/static/app/app.js"></script>
     <script>hljs.initHighlightingOnLoad();</script>
     <script>

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

@@ -1,4 +1,4 @@
-<nav class="navbar navbar-dark bg-primary navbar-expand-md mb-4">
+<nav class="navbar navbar-dark bg-primary navbar-expand-md mb-4 box-shadow">
     <div class="container">
         <a class="navbar-brand" href="{{ config.base_url }}">{{ config.app_name }}</a>
         <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">

+ 2 - 2
resources/templates/dashboard/pager.twig → resources/templates/comp/pager.twig

@@ -3,7 +3,7 @@
         <ul class="pagination justify-content-center">
             {% if previous %}
                 <li class="page-item">
-                    <a class="page-link" href="{{ config.base_url }}/home/page/{{ current_page-1 }}"><i class="fas fa-angle-left fa-fw"></i>
+                    <a class="page-link" href="{{ config.base_url }}/{{ path }}/page/{{ current_page-1 }}"><i class="fas fa-angle-left fa-fw"></i>
                         Previous</a>
                 </li>
             {% else %}
@@ -13,7 +13,7 @@
 
             {% if next %}
                 <li class="page-item">
-                    <a class="page-link" href="{{ config.base_url }}/home/page/{{ current_page+1 }}">Next
+                    <a class="page-link" href="{{ config.base_url }}/{{ path }}/page/{{ current_page+1 }}">Next
                         <i class="fas fa-angle-right fa-fw"></i></a>
                 </li>
             {% else %}

+ 67 - 63
resources/templates/dashboard/admin.twig

@@ -9,71 +9,75 @@
     <div class="container">
         {% include 'comp/alert.twig' %}
         {% if medias|length > 0 %}
-            {% include 'dashboard/pager.twig' %}
-            <div class="row">
-                <div class="col-md-12">
-                    <div class="table-responsive">
-                        <table class="table table-hover">
-                            <thead>
-                            <tr>
-                                <th>Preview</th>
-                                <th>Filename</th>
-                                <th>Size</th>
-                                <th>Public</th>
-                                <th>Owner</th>
-                                <th>Date</th>
-                                <th></th>
-                            </tr>
-                            </thead>
-                            <tbody>
-                            {% for media in medias %}
-                                <tr id="media_{{ media.id }}">
-                                    <td>
-                                        {% if media.mimetype starts with 'image' %}
-                                            {% if media.username is not null %}
-                                                <img src="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}/raw?width=128"
-                                                     class="img-fluid rounded admin-img">
-                                            {% else %}
-                                                <img src="{{ config.base_url }}/upload/{{ media.id }}/raw" class="img-fluid rounded admin-img">
-                                            {% endif %}
-                                        {% else %}
-                                            <i class="far fa-file fa-2x"></i>
-                                        {% endif %}
-                                    </td>
-                                    <td>{{ media.filename }}</td>
-                                    <td>{{ media.size }}</td>
-                                    <td id="published_{{ media.id }}">
-                                        {% if media.published %}
-                                            <span class="badge badge-success"><i class="fas fa-check"></i></span>
-                                        {% else %}
-                                            <span class="badge badge-danger"><i class="fas fa-times"></i></span>
-                                        {% endif %}
-                                    </td>
-                                    <td>{{ media.username|default('<None>') }}</td>
-                                    <td>{{ media.timestamp|date("d/m/Y H:i:s") }}</td>
-                                    <td class="text-right">
-                                        <div class="btn-group">
-                                            {% if media.username is not null %}
-                                                <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}" class="btn btn-outline-dark" data-toggle="tooltip" title="Open" target="_blank"><i class="fas fa-external-link-alt"></i></a>
-                                                <a href="javascript:void(0)" class="btn btn-outline-success btn-clipboard" data-toggle="tooltip" title="Copy link" data-clipboard-text="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}"><i class="fas fa-link"></i></a>
-                                            {% else %}
-                                                <a href="{{ config.base_url }}/upload/{{ media.id }}/raw" class="btn btn-outline-dark" data-toggle="tooltip" title="Raw" target="_blank"><i class="fas fa-external-link-alt"></i></a>
-                                            {% endif %}
+            <div class="card box-shadow">
+                <div class="card-body">
+                    {% include 'comp/pager.twig' with {'path': 'home'} %}
+                    <div class="row">
+                        <div class="col-md-12">
+                            <div class="table-responsive">
+                                <table class="table table-hover">
+                                    <thead>
+                                    <tr>
+                                        <th>Preview</th>
+                                        <th>Filename</th>
+                                        <th>Size</th>
+                                        <th>Public</th>
+                                        <th>Owner</th>
+                                        <th>Date</th>
+                                        <th></th>
+                                    </tr>
+                                    </thead>
+                                    <tbody>
+                                    {% for media in medias %}
+                                        <tr id="media_{{ media.id }}">
+                                            <td>
+                                                {% if media.mimetype starts with 'image' %}
+                                                    {% if media.username is not null %}
+                                                        <img src="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}/raw?width=128"
+                                                             class="img-fluid rounded admin-img">
+                                                    {% else %}
+                                                        <img src="{{ config.base_url }}/upload/{{ media.id }}/raw" class="img-fluid rounded admin-img">
+                                                    {% endif %}
+                                                {% else %}
+                                                    <i class="far fa-file fa-2x"></i>
+                                                {% endif %}
+                                            </td>
+                                            <td>{{ media.filename }}</td>
+                                            <td>{{ media.size }}</td>
+                                            <td id="published_{{ media.id }}">
+                                                {% if media.published %}
+                                                    <span class="badge badge-success"><i class="fas fa-check"></i></span>
+                                                {% else %}
+                                                    <span class="badge badge-danger"><i class="fas fa-times"></i></span>
+                                                {% endif %}
+                                            </td>
+                                            <td>{{ media.username|default('<None>') }}</td>
+                                            <td>{{ media.timestamp|date("d/m/Y H:i:s") }}</td>
+                                            <td class="text-right">
+                                                <div class="btn-group">
+                                                    {% if media.username is not null %}
+                                                        <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}" class="btn btn-outline-dark" data-toggle="tooltip" title="Open" target="_blank"><i class="fas fa-external-link-alt"></i></a>
+                                                        <a href="javascript:void(0)" class="btn btn-outline-success btn-clipboard" data-toggle="tooltip" title="Copy link" data-clipboard-text="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}"><i class="fas fa-link"></i></a>
+                                                    {% else %}
+                                                        <a href="{{ config.base_url }}/upload/{{ media.id }}/raw" class="btn btn-outline-dark" data-toggle="tooltip" title="Raw" target="_blank"><i class="fas fa-external-link-alt"></i></a>
+                                                    {% endif %}
 
-                                            {% if media.published %}
-                                                <a href="javascript:void(0)" class="btn btn-outline-warning publish-toggle" data-toggle="tooltip" title="Unpublish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-times-circle"></i></a>
-                                            {% else %}
-                                                <a href="javascript:void(0)" class="btn btn-outline-info publish-toggle" data-toggle="tooltip" title="Publish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-check-circle"></i></a>
-                                            {% endif %}
-                                            <a href="javascript:void(0)" class="btn btn-outline-danger media-delete" data-link="{{ config.base_url }}/upload/{{ media.id }}/delete" data-id="{{ media.id }}" data-toggle="tooltip" title="Delete"><i class="fas fa-trash"></i></a>
-                                        </div>
-                                    </td>
-                                </tr>
-                            {% endfor %}
-                            </tbody>
-                        </table>
+                                                    {% if media.published %}
+                                                        <a href="javascript:void(0)" class="btn btn-outline-warning publish-toggle" data-toggle="tooltip" title="Unpublish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-times-circle"></i></a>
+                                                    {% else %}
+                                                        <a href="javascript:void(0)" class="btn btn-outline-info publish-toggle" data-toggle="tooltip" title="Publish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-check-circle"></i></a>
+                                                    {% endif %}
+                                                    <a href="javascript:void(0)" class="btn btn-outline-danger media-delete" data-link="{{ config.base_url }}/upload/{{ media.id }}/delete" data-id="{{ media.id }}" data-toggle="tooltip" title="Delete"><i class="fas fa-trash"></i></a>
+                                                </div>
+                                            </td>
+                                        </tr>
+                                    {% endfor %}
+                                    </tbody>
+                                </table>
+                            </div>
+                            {% include 'comp/pager.twig' with {'path': 'home'} %}
+                        </div>
                     </div>
-                    {% include 'dashboard/pager.twig' %}
                 </div>
             </div>
         {% else %}

+ 37 - 33
resources/templates/dashboard/home.twig

@@ -9,44 +9,48 @@
     <div class="container">
         {% include 'comp/alert.twig' %}
         {% if medias|length > 0 %}
-            {% include 'dashboard/pager.twig' %}
-            <div class="row">
-                {% for media in medias %}
-                    <div class="col-md-4" id="media_{{ media.id }}">
-                        <div class="card mb-4 box-shadow">
-                            {% if media.mimetype starts with 'image' %}
-                                <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}" target="_blank">
-                                    <img class="card-img-top user-img" src="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}/raw?width=348&height=192" alt="{{ media.filename }}">
-                                </a>
-                            {% else %}
-                                <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}" target="_blank">
-                                    <div class="card-header text-center"><i class="far fa-file fa-10x"></i></div>
-                                </a>
-                            {% endif %}
-                            <div class="card-body">
-                                <p class="card-text">{{ media.filename }}<small class="float-right">{{ media.size }}</small></p>
-                                <div class="d-flex justify-content-between align-items-center">
-                                    <div class="btn-group">
-                                        <button type="button" class="btn btn-sm btn-outline-success btn-clipboard" data-toggle="tooltip" title="Copy link" data-clipboard-text="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}">
-                                            <i class="fas fa-link"></i>
-                                        </button>
-                                        {% if media.published %}
-                                            <a href="javascript:void(0)" class="btn btn-sm btn-outline-warning publish-toggle" data-toggle="tooltip" title="Unpublish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-times-circle"></i></a>
-                                        {% else %}
-                                            <a href="javascript:void(0)" class="btn btn-sm btn-outline-info publish-toggle" data-toggle="tooltip" title="Publish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-check-circle"></i></a>
-                                        {% endif %}
-                                        <button type="button" class="btn btn-sm btn-outline-danger media-delete" data-link="{{ config.base_url }}/upload/{{ media.id }}/delete" data-id="{{ media.id }}" data-toggle="tooltip" title="Delete">
-                                            <i class="fas fa-trash"></i>
-                                        </button>
+            <div class="card box-shadow">
+                <div class="card-body">
+                    {% include 'comp/pager.twig' with {'path': 'home'} %}
+                    <div class="row">
+                        {% for media in medias %}
+                            <div class="col-md-4" id="media_{{ media.id }}">
+                                <div class="card mb-4 box-shadow">
+                                    {% if media.mimetype starts with 'image' %}
+                                        <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}" target="_blank">
+                                            <img class="card-img-top user-img" src="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}/raw?width=348&height=192" alt="{{ media.filename }}">
+                                        </a>
+                                    {% else %}
+                                        <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}" target="_blank">
+                                            <div class="card-header text-center"><i class="far fa-file fa-10x"></i></div>
+                                        </a>
+                                    {% endif %}
+                                    <div class="card-body">
+                                        <p class="card-text">{{ media.filename }}<small class="float-right">{{ media.size }}</small></p>
+                                        <div class="d-flex justify-content-between align-items-center">
+                                            <div class="btn-group">
+                                                <button type="button" class="btn btn-sm btn-outline-success btn-clipboard" data-toggle="tooltip" title="Copy link" data-clipboard-text="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ media.extension }}">
+                                                    <i class="fas fa-link"></i>
+                                                </button>
+                                                {% if media.published %}
+                                                    <a href="javascript:void(0)" class="btn btn-sm btn-outline-warning publish-toggle" data-toggle="tooltip" title="Unpublish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-times-circle"></i></a>
+                                                {% else %}
+                                                    <a href="javascript:void(0)" class="btn btn-sm btn-outline-info publish-toggle" data-toggle="tooltip" title="Publish" data-id="{{ media.id }}" data-published="{{ media.published }}"><i class="fas fa-check-circle"></i></a>
+                                                {% endif %}
+                                                <button type="button" class="btn btn-sm btn-outline-danger media-delete" data-link="{{ config.base_url }}/upload/{{ media.id }}/delete" data-id="{{ media.id }}" data-toggle="tooltip" title="Delete">
+                                                    <i class="fas fa-trash"></i>
+                                                </button>
+                                            </div>
+                                            <small class="text-muted">{{ media.timestamp|date("d/m/Y H:i:s") }}</small>
+                                        </div>
                                     </div>
-                                    <small class="text-muted">{{ media.timestamp|date("d/m/Y H:i:s") }}</small>
                                 </div>
                             </div>
-                        </div>
+                        {% endfor %}
                     </div>
-                {% endfor %}
+                    {% include 'comp/pager.twig' with {'path': 'home'} %}
+                </div>
             </div>
-            {% include 'dashboard/pager.twig' %}
         {% else %}
             <div class="text-center text-muted"><i>No medias found.</i></div>
         {% endif %}

+ 6 - 6
resources/templates/dashboard/system.twig

@@ -9,7 +9,7 @@
     <div class="container">
         <div class="row">
             <div class="col-xl-3 col-sm-6 mb-3">
-                <div class="card bg-success text-white h-100">
+                <div class="card bg-success text-white h-100 box-shadow">
                     <div class="card-body bg-success">
                         <div class="rotate">
                             <i class="fas fa-users fa-3x"></i>
@@ -20,7 +20,7 @@
                 </div>
             </div>
             <div class="col-xl-3 col-sm-6 mb-3">
-                <div class="card bg-danger text-white h-100">
+                <div class="card bg-danger text-white h-100 box-shadow">
                     <div class="card-body bg-danger">
                         <div class="rotate">
                             <i class="fas fa-weight fa-3x"></i>
@@ -31,7 +31,7 @@
                 </div>
             </div>
             <div class="col-xl-3 col-sm-6 mb-3">
-                <div class="card bg-warning text-white h-100">
+                <div class="card bg-warning text-white h-100 box-shadow">
                     <div class="card-body bg-warning">
                         <div class="rotate">
                             <i class="fas fa-upload fa-3x"></i>
@@ -42,7 +42,7 @@
                 </div>
             </div>
             <div class="col-xl-3 col-sm-6 mb-3">
-                <div class="card bg-dark text-white h-100">
+                <div class="card bg-dark text-white h-100 box-shadow">
                     <div class="card-body bg-dark">
                         <div class="rotate">
                             <i class="fas fa-unlink fa-3x"></i>
@@ -55,7 +55,7 @@
         </div>
         <div class="row">
             <div class="col-md-8">
-                <div class="card">
+                <div class="card box-shadow">
                     <div class="card-header"><i class="fas fa-paint-brush fa-fw"></i> Theme</div>
                     <div class="card-body">
                         <form method="post" action="{{ config.base_url }}/system/theme/apply">
@@ -78,7 +78,7 @@
                 </div>
             </div>
             <div class="col-md-4">
-                <div class="card">
+                <div class="card box-shadow">
                     <div class="card-header"><i class="fas fa-cog fa-fw"></i> System Information</div>
                     <div class="card-body">
                         <strong>Max upload size:</strong>

+ 3 - 5
resources/templates/upload/public.twig

@@ -48,11 +48,10 @@
                         </div>
                     </div>
                 {% elseif type starts with 'video' %}
-                    <video width="100%" controls>
+                    <video width="100%"  class="video-js" controls preload="auto">
                         <source src="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ extension }}/raw" type="{{ type }}">
                         Your browser does not support HTML5 video.
-                        <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ extension }}/download" class="btn btn-dark btn-lg"><i class="fas fa-cloud-download-alt fa-fw"></i>
-                            Download</a>
+                        <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ extension }}/download" class="btn btn-dark btn-lg"><i class="fas fa-cloud-download-alt fa-fw"></i> Download</a>
                     </video>
                 {% else %}
                     <div class="text-center">
@@ -68,8 +67,7 @@
                         </div>
                         <div class="row">
                             <div class="col-md-12">
-                                <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ extension }}/download" class="btn btn-dark btn-lg"><i class="fas fa-cloud-download-alt fa-fw"></i>
-                                    Download</a>
+                                <a href="{{ config.base_url }}/{{ media.user_code }}/{{ media.code }}.{{ extension }}/download" class="btn btn-dark btn-lg"><i class="fas fa-cloud-download-alt fa-fw"></i> Download</a>
                             </div>
                         </div>
                     </div>

+ 1 - 1
resources/templates/user/create.twig

@@ -9,7 +9,7 @@
         {% include 'comp/alert.twig' %}
         <div class="row justify-content-center">
             <div class="col-md-8">
-                <div class="card">
+                <div class="card box-shadow">
                     <div class="card-header">Create User</div>
                     <div class="card-body">
                         <form method="post" action="{{ config.base_url }}/user/create">

+ 1 - 1
resources/templates/user/edit.twig

@@ -9,7 +9,7 @@
         {% include 'comp/alert.twig' %}
         <div class="row justify-content-center">
             <div class="col-md-8">
-                <div class="card">
+                <div class="card box-shadow">
                     {% if not profile %}
                         <div class="card-header">Edit User</div>
                     {% endif %}

+ 62 - 80
resources/templates/user/index.twig

@@ -6,87 +6,69 @@
     {% include 'comp/navbar.twig' %}
     <div class="container">
         {% include 'comp/alert.twig' %}
-        <div class="text-right">
-            <a href="{{ config.base_url }}/user/create" class="btn btn-outline-success mb-3"><i class="fas fa-plus"></i>
-                Add User</a>
-        </div>
-        <div class="table-responsive">
-            <table class="table table-hover">
-                <thead>
-                <tr>
-                    <th>ID</th>
-                    <th>Email</th>
-                    <th>Username</th>
-                    <th>User Code</th>
-                    <th>Token</th>
-                    <th>Active</th>
-                    <th>Admin</th>
-                    <th>Registration Date</th>
-                    <th></th>
-                </tr>
-                </thead>
-                <tbody>
-                {% for user in users %}
-                    <tr>
-                        <td>#{{ user.id }}</td>
-                        <td>{{ user.email }}</td>
-                        <td>{{ user.username }}</td>
-                        <td>
-                            <pre>{{ user.user_code|default('None') }}</pre>
-                        </td>
-                        <td>
-                            <pre>{{ user.token|default('None') }}</pre>
-                        </td>
-                        <td>
-                            {% if user.active %}
-                                <span class="badge badge-success"><i class="fas fa-check"></i></span>
-                            {% else %}
-                                <span class="badge badge-danger"><i class="fas fa-times"></i></span>
-                            {% endif %}
-                        </td>
-                        <td>
-                            {% if user.is_admin %}
-                                <span class="badge badge-success"><i class="fas fa-check"></i></span>
-                            {% else %}
-                                <span class="badge badge-danger"><i class="fas fa-times"></i></span>
-                            {% endif %}
-                        </td>
-                        <td>
-                            {{ user.registration_date|date("d/m/Y H:i:s") }}
-                        </td>
-                        <td class="text-right">
-                            <div class="btn-group">
-                                <a href="{{ config.base_url }}/user/{{ user.id }}/edit" class="btn btn-outline-warning" data-toggle="tooltip" title="Edit"><i class="fas fa-pencil-alt"></i></a>
-                                <a href="#" class="btn btn-outline-danger user-delete" data-link="{{ config.base_url }}/user/{{ user.id }}/delete" data-toggle="tooltip" title="Delete"><i class="fas fa-trash"></i></a>
-                            </div>
-                        </td>
-                    </tr>
-                {% endfor %}
-                </tbody>
-            </table>
+        <div class="card box-shadow">
+            <div class="card-body">
+                <div class="text-right">
+                    <a href="{{ config.base_url }}/user/create" class="btn btn-outline-success mb-3"><i class="fas fa-plus"></i>Add User</a>
+                </div>
+                <div class="table-responsive">
+                    <table class="table table-hover">
+                        <thead>
+                        <tr>
+                            <th>ID</th>
+                            <th>Email</th>
+                            <th>Username</th>
+                            <th>User Code</th>
+                            <th>Token</th>
+                            <th>Active</th>
+                            <th>Admin</th>
+                            <th>Registration Date</th>
+                            <th></th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        {% for user in users %}
+                            <tr>
+                                <td>#{{ user.id }}</td>
+                                <td>{{ user.email }}</td>
+                                <td>{{ user.username }}</td>
+                                <td>
+                                    <pre>{{ user.user_code|default('None') }}</pre>
+                                </td>
+                                <td>
+                                    <pre>{{ user.token|default('None') }}</pre>
+                                </td>
+                                <td>
+                                    {% if user.active %}
+                                        <span class="badge badge-success"><i class="fas fa-check"></i></span>
+                                    {% else %}
+                                        <span class="badge badge-danger"><i class="fas fa-times"></i></span>
+                                    {% endif %}
+                                </td>
+                                <td>
+                                    {% if user.is_admin %}
+                                        <span class="badge badge-success"><i class="fas fa-check"></i></span>
+                                    {% else %}
+                                        <span class="badge badge-danger"><i class="fas fa-times"></i></span>
+                                    {% endif %}
+                                </td>
+                                <td>
+                                    {{ user.registration_date|date("d/m/Y H:i:s") }}
+                                </td>
+                                <td class="text-right">
+                                    <div class="btn-group">
+                                        <a href="{{ config.base_url }}/user/{{ user.id }}/edit" class="btn btn-outline-warning" data-toggle="tooltip" title="Edit"><i class="fas fa-pencil-alt"></i></a>
+                                        <a href="#" class="btn btn-outline-danger user-delete" data-link="{{ config.base_url }}/user/{{ user.id }}/delete" data-toggle="tooltip" title="Delete"><i class="fas fa-trash"></i></a>
+                                    </div>
+                                </td>
+                            </tr>
+                        {% endfor %}
+                        </tbody>
+                    </table>
+                </div>
+                {% include 'comp/pager.twig' with {'path': 'users'} %}
+            </div>
         </div>
-        <nav>
-            <ul class="pagination justify-content-center">
-                {% if previous %}
-                    <li class="page-item">
-                        <a class="page-link" href="{{ config.base_url }}/users/page/{{ current_page-1 }}"><i class="fas fa-angle-left fa-fw"></i>
-                            Previous</a>
-                    </li>
-                {% else %}
-                    <li class="page-item disabled"><a class="page-link" href="#"><i class="fas fa-angle-left fa-fw"></i>
-                            Previous</a></li>
-                {% endif %}
-
-                {% if next %}
-                    <li class="page-item">
-                        <a class="page-link" href="{{ config.base_url }}/users/page/{{ current_page+1 }}">Next
-                            <i class="fas fa-angle-right fa-fw"></i></a></li>
-                {% else %}
-                    <li class="page-item disabled"><a class="page-link" href="#">Next
-                            <i class="fas fa-angle-right fa-fw"></i></a></li>
-                {% endif %}
-            </ul>
-        </nav>
     </div>
     <div class="modal fade" id="modalDelete" tabindex="-1" role="dialog" aria-hidden="true">
         <div class="modal-dialog modal-sm">

+ 2 - 2
src/css/app.css

@@ -1,13 +1,13 @@
 
 html {
     position: relative;
-    height: 100%;
+    min-height: 100%;
 }
 
 body {
-    height: 100%;
     margin-bottom: 40px;
     font-size: 1rem;
+    background-color: #f5f5f5;
 }
 
 .form-signin {