added tags on the preview page

added a way to disable autotagging
Fixed issue with email content type
the uploads page previews are now with a link
Disabled logging of 404 errors
This commit is contained in:
Sergio Brighenti 2020-04-07 18:43:34 +02:00
parent afefbfa99d
commit 041bb9fd55
13 changed files with 107 additions and 41 deletions

View file

@ -21,6 +21,13 @@ class AdminController extends Controller
*/
public function system(Request $request, Response $response): Response
{
$settings = [];
foreach ($this->database->query('SELECT `key`, `value` FROM `settings`') as $setting) {
$settings[$setting->key] = $setting->value;
}
$settings['default_user_quota'] = humanFileSize($this->getSetting('default_user_quota', stringToBytes('1G')), 0, true);
return view()->render($response, 'dashboard/system.twig', [
'usersCount' => $usersCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `users`')->fetch()->count,
'mediasCount' => $mediasCount = $this->database->query('SELECT COUNT(*) AS `count` FROM `uploads`')->fetch()->count,
@ -32,14 +39,7 @@ class AdminController extends Controller
'forced_lang' => $request->getAttribute('forced_lang'),
'php_version' => phpversion(),
'max_memory' => ini_get('memory_limit'),
'register_enabled' => $this->getSetting('register_enabled', 'off'),
'hide_by_default' => $this->getSetting('hide_by_default', 'off'),
'copy_url_behavior' => $this->getSetting('copy_url_behavior', 'off'),
'quota_enabled' => $this->getSetting('quota_enabled', 'off'),
'default_user_quota' => humanFileSize($this->getSetting('default_user_quota', stringToBytes('1G')), 0, true),
'recaptcha_enabled' => $this->getSetting('recaptcha_enabled', 'off'),
'recaptcha_site_key' => $this->getSetting('recaptcha_site_key'),
'recaptcha_secret_key' => $this->getSetting('recaptcha_secret_key'),
'settings' => $settings,
]);
}

View file

@ -33,7 +33,7 @@ class MediaController extends Controller
*/
public function show(Request $request, Response $response, string $userCode, string $mediaCode, string $token = null): Response
{
$media = $this->getMedia($userCode, $mediaCode);
$media = $this->getMedia($userCode, $mediaCode, true);
if (!$media || (!$media->published && $this->session->get('user_id') !== $media->user_id && !$this->session->get('admin', false))) {
throw new HttpNotFoundException($request);
@ -112,7 +112,7 @@ class MediaController extends Controller
*/
public function getRaw(Request $request, Response $response, string $userCode, string $mediaCode, ?string $ext = null): Response
{
$media = $this->getMedia($userCode, $mediaCode);
$media = $this->getMedia($userCode, $mediaCode, false);
if (!$media || !$media->published && $this->session->get('user_id') !== $media->user_id && !$this->session->get('admin', false)) {
throw new HttpNotFoundException($request);
@ -144,7 +144,7 @@ class MediaController extends Controller
*/
public function download(Request $request, Response $response, string $userCode, string $mediaCode): Response
{
$media = $this->getMedia($userCode, $mediaCode);
$media = $this->getMedia($userCode, $mediaCode, false);
if (!$media || !$media->published && $this->session->get('user_id') !== $media->user_id && !$this->session->get('admin', false)) {
throw new HttpNotFoundException($request);
@ -230,7 +230,7 @@ class MediaController extends Controller
*/
public function deleteByToken(Request $request, Response $response, string $userCode, string $mediaCode, string $token): Response
{
$media = $this->getMedia($userCode, $mediaCode);
$media = $this->getMedia($userCode, $mediaCode, false);
if (!$media) {
throw new HttpNotFoundException($request);
@ -286,16 +286,28 @@ class MediaController extends Controller
* @param $userCode
* @param $mediaCode
*
* @param bool $withTags
* @return mixed
*/
protected function getMedia($userCode, $mediaCode)
protected function getMedia($userCode, $mediaCode, $withTags = false)
{
$mediaCode = pathinfo($mediaCode)['filename'];
return $this->database->query('SELECT `uploads`.*, `users`.*, `users`.`id` AS `userId`, `uploads`.`id` AS `mediaId` FROM `uploads` INNER JOIN `users` ON `uploads`.`user_id` = `users`.`id` WHERE `user_code` = ? AND `uploads`.`code` = ? LIMIT 1', [
$media = $this->database->query('SELECT `uploads`.*, `users`.*, `users`.`id` AS `userId`, `uploads`.`id` AS `mediaId` FROM `uploads` INNER JOIN `users` ON `uploads`.`user_id` = `users`.`id` WHERE `user_code` = ? AND `uploads`.`code` = ? LIMIT 1', [
$userCode,
$mediaCode,
])->fetch();
if (!$withTags || !$media) {
return $media;
}
$media->tags = [];
foreach ($this->database->query('SELECT `tags`.`id`, `tags`.`name` FROM `uploads_tags` INNER JOIN `tags` ON `uploads_tags`.`tag_id` = `tags`.`id` WHERE `uploads_tags`.`upload_id` = ?', $media->mediaId) as $tag) {
$media->tags[$tag->id] = $tag->name;
}
return $media;
}
/**

View file

@ -29,6 +29,7 @@ class SettingController extends Controller
// registrations
$this->updateSetting('register_enabled', param($request, 'register_enabled', 'off'));
$this->updateSetting('auto_tagging', param($request, 'auto_tagging', 'off'));
// quota
$this->updateSetting('quota_enabled', param($request, 'quota_enabled', 'off'));

View file

@ -200,7 +200,9 @@ class UploadController extends Controller
]);
$mediaId = $this->database->getPdo()->lastInsertId();
$this->autoTag($mediaId, $storagePath);
if ($this->getSetting('auto_tagging') === 'on') {
$this->autoTag($mediaId, $storagePath);
}
$this->json['message'] = 'OK';
$this->json['url'] = urlFor("/{$user->user_code}/{$code}.{$fileInfo['extension']}");
@ -225,7 +227,7 @@ class UploadController extends Controller
$query = make(TagQuery::class);
$query->addTag($type, $mediaId);
if ($type === 'application') {
if ($type === 'application' || $subtype === 'gif') {
$query->addTag($subtype, $mediaId);
}
}

View file

@ -103,7 +103,7 @@ class UserController extends Controller
if (param($request, 'send_notification') !== null) {
$resetToken = null;
if (!empty(param($request, 'password'))) {
if (empty(param($request, 'password'))) {
$resetToken = bin2hex(random_bytes(16));
$this->database->query('UPDATE `users` SET `reset_token`=? WHERE `id` = ?', [
@ -284,7 +284,7 @@ class UserController extends Controller
*/
private function sendCreateNotification($request, $resetToken = null)
{
if (empty(param($request, 'password'))) {
if ($resetToken === null && !empty(param($request, 'password'))) {
$message = lang('mail.new_account_text_with_pw', [
param($request, 'username'),
$this->config['app_name'],

View file

@ -2,7 +2,10 @@
namespace App\Exception\Handlers;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Handlers\ErrorHandler;
use Throwable;
class AppErrorHandler extends ErrorHandler
{
@ -10,4 +13,15 @@ class AppErrorHandler extends ErrorHandler
{
resolve('logger')->error($error);
}
public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails): ResponseInterface
{
$response = parent::__invoke($request, $exception, $displayErrorDetails, $logErrors, $logErrorDetails);
if ($response->getStatusCode() !== 404) {
$this->writeToErrorLog();
}
return $response;
}
}

View file

@ -117,7 +117,7 @@ class Mail
$this->addRequiredHeader('X-Mailer: PHP/'.phpversion());
$this->addRequiredHeader('MIME-Version: 1.0');
$this->addRequiredHeader('Content-Type: text/html; charset=iso-8859-1');
$this->addRequiredHeader('Content-Type: text/plain; charset=iso-8859-1');
$this->headers .= $this->additionalHeaders;

View file

@ -112,7 +112,7 @@ $errorHandler = new AppErrorHandler($app->getCallableResolver(), $app->getRespon
$errorHandler->registerErrorRenderer('text/html', HtmlErrorRenderer::class);
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware($config['debug'], true, true);
$errorMiddleware = $app->addErrorMiddleware($config['debug'], false, true);
$errorMiddleware->setDefaultErrorHandler($errorHandler);
// Load the application routes

View file

@ -172,4 +172,5 @@ Click on the following link to go to the login page:
'ldap_cant_connect' => 'Can\'t connect to the LDAP auth server.',
'upload_max_file_size' => 'The max file size is currently %s.',
'no_tags' => 'No tags added',
'auto_tagging' => 'Auto upload tagging',
];

View file

@ -48,7 +48,7 @@
</div>
</div>
{% if isDisplayableImage(media.mimetype) %}
<div class="content-image rounded-top" style="background-image: url({{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension ~ '/raw?height=267') }});"></div>
<div class="content-image" style="background-image: url({{ urlFor('/' ~ media.user_code ~ '/' ~ media.code ~ '.' ~ media.extension ~ '/raw?height=267') }});"></div>
{% else %}
<div class="text-center" style="font-size: 178px;"><i class="far {{ mime2font(media.mimetype) }} mb-4 mt-4"></i></div>
{% endif %}

View file

@ -62,7 +62,13 @@
<div class="form-group row">
<label for="register_enabled" class="col-sm-4 col-form-label">{{ lang('register_enabled') }}</label>
<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" {{ settings.register_enabled == 'on' ? 'checked' }}>
</div>
</div>
<div class="form-group row">
<label for="auto_tagging" class="col-sm-4 col-form-label">{{ lang('auto_tagging') }}</label>
<div class="col-sm-8">
<input type="checkbox" name="auto_tagging" data-toggle="toggle" {{ settings.auto_tagging == 'on' ? 'checked' }}>
</div>
</div>
<div class="form-group row">
@ -88,7 +94,7 @@
<div class="form-group row">
<label for="custom_head" class="col-sm-4 col-form-label">{{ lang('custom_head_html') }}</label>
<div class="col-sm-8">
<textarea name="custom_head" class="form-control text-monospace">{{ customHead|raw }}</textarea>
<textarea name="custom_head" class="form-control text-monospace">{{ settings.customHead|raw }}</textarea>
<small>{{ lang('custom_head_html_hint') }}</small>
</div>
</div>
@ -96,13 +102,13 @@
<div class="form-group row">
<label for="quota_enabled" class="col-sm-4 col-form-label">{{ lang('quota_enabled') }}</label>
<div class="col-sm-8">
<input type="checkbox" name="quota_enabled" data-toggle="toggle" {{ quota_enabled == 'on' ? 'checked' }} onchange="document.getElementById('default_user_quota').toggleAttribute('readonly')">
<input type="checkbox" name="quota_enabled" data-toggle="toggle" {{ settings.quota_enabled == 'on' ? 'checked' }} onchange="document.getElementById('default_user_quota').toggleAttribute('readonly')">
</div>
</div>
<div class="form-group row">
<label for="default_user_quota" class="col-sm-4 col-form-label">{{ lang('default_user_quota') }}</label>
<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 }}" {{ quota_enabled == 'off' ? 'readonly' }}>
<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="{{ settings.default_user_quota }}" {{ settings.quota_enabled == 'off' ? 'readonly' }}>
<small>512M, 2G, 1T, ...</small>
</div>
</div>
@ -110,20 +116,20 @@
<div class="form-group row">
<label for="recaptcha_enabled" class="col-sm-4 col-form-label">{{ lang('recaptcha_enabled') }}</label>
<div class="col-sm-8">
<input type="checkbox" name="recaptcha_enabled" data-toggle="toggle" {{ recaptcha_enabled == 'on' ? 'checked' }} onchange="document.getElementById('recaptcha_site_key').toggleAttribute('readonly');document.getElementById('recaptcha_secret_key').toggleAttribute('readonly')">
<input type="checkbox" name="recaptcha_enabled" data-toggle="toggle" {{ settings.recaptcha_enabled == 'on' ? 'checked' }} onchange="document.getElementById('recaptcha_site_key').toggleAttribute('readonly');document.getElementById('recaptcha_secret_key').toggleAttribute('readonly')">
<br><small>{{ lang('only_recaptcha_v3') }}</small>
</div>
</div>
<div class="form-group row">
<label for="recaptcha_site_key" class="col-sm-4 col-form-label">{{ lang('recaptcha_site_key') }}</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="recaptcha_site_key" name="recaptcha_site_key" value="{{ recaptcha_site_key }}" {{ recaptcha_enabled == 'off' ? 'readonly' }}>
<input type="text" class="form-control" id="recaptcha_site_key" name="recaptcha_site_key" value="{{ settings.recaptcha_site_key }}" {{ settings.recaptcha_enabled == 'off' ? 'readonly' }}>
</div>
</div>
<div class="form-group row">
<label for="recaptcha_secret_key" class="col-sm-4 col-form-label">{{ lang('recaptcha_secret_key') }}</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="recaptcha_secret_key" name="recaptcha_secret_key" value="{{ recaptcha_secret_key }}" {{ recaptcha_enabled == 'off' ? 'readonly' }}>
<input type="text" class="form-control" id="recaptcha_secret_key" name="recaptcha_secret_key" value="{{ settings.recaptcha_secret_key }}" {{ settings.recaptcha_enabled == 'off' ? 'readonly' }}>
</div>
</div>
<button type="submit" class="btn btn-outline-success float-right mt-3">

View file

@ -43,29 +43,23 @@
</div>
</form>
{% endif %}
{% set typeMatched = false %}
{% if type is same as ('image') %}
{% set typeMatched = true %}
<div class="row mb-2">
<div class="col-md-12">
<img src="{{ url }}/raw" class="img-thumbnail rounded mx-auto d-block" alt="{{ media.filename }}">
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
{{ media.filename }}
</div>
</div>
{% elseif type is same as ('text') %}
{% set typeMatched = true %}
<div class="row mb-2">
<div class="col-md-12">
<pre><code>{{ media.text }}</code></pre>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
{{ media.filename }}
</div>
</div>
{% elseif type is same as ('audio') %}
{% set typeMatched = true %}
<div class="media-player media-audio">
<audio id="player" autoplay controls loop preload="auto">
<source src="{{ url }}/raw" type="{{ media.mimetype }}">
@ -74,6 +68,7 @@
</audio>
</div>
{% elseif type is same as ('video') %}
{% set typeMatched = true %}
<div class="media-player">
<video id="player" autoplay controls loop preload="auto">
<source src="{{ url }}/raw" type="{{ media.mimetype }}">
@ -82,11 +77,13 @@
</video>
</div>
{% elseif media.mimetype is same as ('application/pdf') %}
{% set typeMatched = true %}
<object type="{{ media.mimetype }}" data="{{ url }}/raw" class="pdf-viewer">
Your browser does not support PDF previews.
<a href="{{ url }}/download" class="btn btn-dark btn-lg"><i class="fas fa-cloud-download-alt fa-fw"></i> Download</a>
</object>
{% else %}
{% endif %}
{% if not typeMatched %}
<div class="text-center">
<div class="row mb-3">
<div class="col-md-12">
@ -98,17 +95,41 @@
<b>{{ media.filename }}</b>
</div>
</div>
<div class="row mb-4">
<div class="row">
<div class="col-md-12">
{{ media.size }}
</div>
</div>
<div class="row">
{% if media.tags is not empty %}
<div class="row mt-1 mb-2">
<div class="col-md-12 text-center">
{% for tag_id, tag_name in media.tags %}
<span class="badge badge-pill badge-primary shadow-sm mr-1" title="{{ tag_name }}">{{ tag_name }}</span>
{% endfor %}
</div>
</div>
{% endif %}
<div class="row mt-3">
<div class="col-md-12">
<a href="{{ url }}/download" class="btn btn-dark btn-lg"><i class="fas fa-cloud-download-alt fa-fw"></i> Download</a>
</div>
</div>
</div>
{% else %}
<div class="row mt-1">
<div class="col-md-12 text-center">
{{ media.filename }}
</div>
</div>
{% if media.tags is not empty %}
<div class="row mt-2">
<div class="col-md-12 text-center">
{% for tag_id, tag_name in media.tags %}
<span class="badge badge-pill badge-primary shadow-sm mr-1" title="{{ tag_name }}">{{ tag_name }}</span>
{% endfor %}
</div>
</div>
{% endif %}
{% endif %}
</div>
</div>

View file

@ -11,6 +11,15 @@ var app = {
var text = Math.round(uploadProgress) + '%';
$('#uploadProgess').css({'width': text}).text(text);
},
queuecomplete: function () {
$('#uploadProgess').css({'width': '0%'}).text('');
},
success: function (file, response) {
$(file.previewElement)
.find('.dz-filename')
.children()
.html('<a href="' + response.url + '">' + file.name + '</a>');
},
timeout: 0
};
},