added admin panel with stats and logs

This commit is contained in:
Chris
2025-05-20 13:59:42 +02:00
parent c3c34efa13
commit 9beddcfd16
16 changed files with 493 additions and 354 deletions

35
DEV.md Normal file
View File

@@ -0,0 +1,35 @@
# Folder structure
All uploads will be created as folders with the name of the file in the `./data` directory.
```
data/
data/<file_name>/
data/<file_name>/<file_name> # the actual file eg abc1
data/<file_name>/meta.json # file containing the metadata
```
## Metadata file
The metadata file will contain data like in the following example:
```json
{
"mime": "image\/jpeg",
"size": 504921,
"size_human": "493.09 KB",
"original_filename": "PXL_20250511_122019042-POP_OUT.jpg",
"hash": "0gfmeo.jpg",
"sha1": "7dc14ad3f0c273ce0188aeef19a6104e81ba67dd",
"uploaded": 1747557347,
"ip": "::1",
"useragent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/136.0.0.0 Safari\/537.36",
"delete_code": "z94fd5tyto1u2bww23kec0f52irb7x49",
"delete_url": "http:\/\/localhost:8080\/delete_z94fd5tyto1u2bww23kec0f52irb7x49\/0gfmeo.jpg",
"remote_port": "35856"
}
```
# Redis index
If redis caching is enabled, this structure will be created on the fly:
- cache:byurl:<url> => <content controller>;<file_name> # cached response
- served:<file_name> => number of views # view count

View File

@@ -8,3 +8,4 @@
- [ ] Review reports
- [ ] Delete content if needed in a way that the user can't reupload it
- [ ] Add a way to delete content that is older than X days
- [ ] Bruteforce protection for admin login

View File

@@ -3,12 +3,11 @@ services:
pictshare:
image: 'HaschekSolutions/pictshare:3'
environment:
- SERVER_NAME=:80 # required by caddy
- URL=http://localhost:8080/
- MAX_UPLOAD_SIZE=20 #in MB
# Security settings
- ADMIN_PASSWORD= # password for the admin panel. if empty, admin panel is disabled
- ALLOWED_SUBNET= #IP address or subnet mask to allow upload to the server
- ALLOWED_SUBNET= #IP address or subnet mask to allow upload and access to the admin panel
- CONTENTCONTROLLERS= # limit uploaded file types
- MASTER_DELETE_CODE= # code to delete all files
- MASTER_DELETE_IP= # IP address to delete all files even without delete code
@@ -43,6 +42,7 @@ services:
- REDIS_CACHING=true
- REDIS_SERVER=/run/redis/redis.sock
- REDIS_PORT=0
- SERVER_NAME=:80 # required by caddy
ports:
- 8080:80
volumes:

View File

@@ -29,13 +29,38 @@ function architect($u)
{
$forbidden = true;
}
return renderTemplate('main.html.php',['forbidden'=>$forbidden]);
return renderTemplate('index.html.php',['main'=>renderTemplate('main.html.php',['forbidden'=>$forbidden])]);
}
// admin logic
if($u[0] == 'admin' && defined('ADMIN_PASSWORD') && ADMIN_PASSWORD != '')
{
// block checks
if (defined('ALLOWED_SUBNET') && ALLOWED_SUBNET != '' && !isIPInRange(getUserIP(), ALLOWED_SUBNET))
return;
else if (defined('MASTER_DELETE_IP') && MASTER_DELETE_IP != '' && !isIPInRange(getUserIP(), MASTER_DELETE_IP))
return;
session_start();
switch($u[1]){
case 'stats':
if(!$_SESSION['admin'])
header('Location: /admin');
return renderTemplate('index.html.php',['main'=>renderTemplate('admin.stats.html.php',['stats'=>getStats()])]);
case 'logs':
if(!$_SESSION['admin'])
header('Location: /admin');
switch($u[2])
{
case 'app':
return renderTemplate('index.html.php',['main'=>renderTemplate('admin.logs-table.html.php',['type'=>'app','logs'=>getLogs('app',$u[3])])]);
case 'error':
return renderTemplate('index.html.php',['main'=>renderTemplate('admin.logs-table.html.php',['type'=>'error','logs'=>getLogs('error',$u[3])])]);
case 'views':
return renderTemplate('index.html.php',['main'=>renderTemplate('admin.logs-table.html.php',['type'=>'views','logs'=>getLogs('views',$u[3])])]);
default:
return renderTemplate('index.html.php',['main'=>renderTemplate('admin.logs.html.php')]);
}
default:
if($_REQUEST['password'] && $_REQUEST['password']== ADMIN_PASSWORD)
{
$_SESSION['admin'] = true;
@@ -48,7 +73,10 @@ function architect($u)
session_destroy();
}
}
return renderTemplate('admin.html.php');
return renderTemplate('index.html.php',['main'=>renderTemplate('admin.html.php')]);
}
}
//check cache
@@ -59,7 +87,7 @@ function architect($u)
{
list($cc, $hash) = explode(';', $cache_data);
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
addToLog("Cache hit: ".getUserIP()." viewed $hash\t".$_SERVER['HTTP_USER_AGENT'], ROOT.DS.'logs/views.log');
addToLog(getUserIP()."\tviewed\t$hash\tFrom cache. Agent:\t".$_SERVER['HTTP_USER_AGENT']."\tref:\t".$_SERVER['HTTP_REFERER'], ROOT.DS.'logs/views.log');
$GLOBALS['redis']->incr("served:$hash");
return (new $cc())->handleHash($hash,$u);
}
@@ -73,7 +101,7 @@ function architect($u)
{
$hash = $el;
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
addToLog(getUserIP()." viewed $hash\tIt was locally found\t".$_SERVER['HTTP_USER_AGENT'], ROOT.DS.'logs/views.log');
addToLog(getUserIP()."\tviewed\t$hash\tIt was locally found. Agent:\t".$_SERVER['HTTP_USER_AGENT']."\tref:\t".$_SERVER['HTTP_REFERER'], ROOT.DS.'logs/views.log');
break;
}
// if we don't have a hash yet but the element looks like it could be a hash
@@ -93,7 +121,7 @@ function architect($u)
storeFile(ROOT.DS.'tmp'.DS.$hash,$hash,true);
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
addToLog(getUserIP()." viewed $hash\tIt was found in Storage Controller $contr\t".$_SERVER['HTTP_USER_AGENT'], ROOT.DS.'logs/views.log');
addToLog(getUserIP()."\tviewed\t$hash\tIt was found in Storage Controller $contr. Agent:\t".$_SERVER['HTTP_USER_AGENT']."\tref:\t".$_SERVER['HTTP_REFERER'], ROOT.DS.'logs/views.log');
break; // we break here because we already have the file. no need to check other storage controllers
}
@@ -110,7 +138,7 @@ function architect($u)
unlink(ROOT.DS.'tmp'.DS.$el.'.enc');
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
addToLog(getUserIP()." viewed $hash\tIt was found encrypted in Storage Controller $contr\t".$_SERVER['HTTP_USER_AGENT'], ROOT.DS.'logs/views.log');
addToLog(getUserIP()."\tviewed\t$hash\tIt was found encrypted in Storage Controller $contr. Agent:\t".$_SERVER['HTTP_USER_AGENT']."\tref:\t".$_SERVER['HTTP_REFERER'], ROOT.DS.'logs/views.log');
break; // we break here because we already have the file. no need to check other storage controllers
}
@@ -125,7 +153,7 @@ function architect($u)
if((new $cc)::ctype=='dynamic' && in_array((new $cc)->getRegisteredExtensions()[0],$u) )
{
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
addToLog(getUserIP()." requested ".implode("/",$u)."\tIt's a dynamic image handled by $cc\t".$_SERVER['HTTP_USER_AGENT'], ROOT.DS.'logs/views.log');
addToLog(getUserIP()." requested ".implode("/",$u)."\tIt's a dynamic image handled by $cc. Agent:\t".$_SERVER['HTTP_USER_AGENT']."\tref:\t".$_SERVER['HTTP_REFERER'], ROOT.DS.'logs/views.log');
$hash = true;
break;
}
@@ -833,7 +861,7 @@ function getDeleteCodeOfHash($hash)
function getMetadataOfHash($hash)
{
$metadata = array();
$metadata = [];
$metadatafile = getDataDir().DS.$hash.DS.'meta.json';
if(file_exists($metadatafile))
{
@@ -1108,3 +1136,39 @@ function addToLog($data,$logfile=ROOT.DS.'logs/app.log')
fwrite($fp,date("d.m.y H:i")."\t[".getURL()."] | ".$data."\n");
fclose($fp);
}
function getStats(){
$stats = array();
$stats['total_files'] = 0;
$stats['total_size'] = 0;
$stats['total_files'] = count(glob(getDataDir().DS.'*', GLOB_ONLYDIR));
foreach (glob(getDataDir().DS.'*') as $dir) {
if (is_dir($dir)) {
$stats['hashes'][basename($dir)] = [
'size' => filesize($dir.DS.basename($dir)),
'files' => count(glob($dir.DS.'*')),
'views' => $GLOBALS['redis']->get('served:'.basename($dir)),
'metadata' => getMetadataOfHash(basename($dir)),
];
}
}
return $stats;
}
function getLogs($type='app',$filter=false)
{
$logs = array();
$logfile = ROOT.DS.'logs/'.$type.'.log';
if($type && file_exists($logfile))
{
$handle = fopen($logfile, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
if($filter && strpos($line,$filter)===false) continue;
$logs[] = $line;
}
fclose($handle);
}
}
return $logs;
}

View File

@@ -1,70 +1,13 @@
<!DOCTYPE html>
<!--[if IEMobile 7 ]> <html class="no-js iem7"> <![endif]-->
<!--[if (gt IEMobile 7)|!(IEMobile)]><!-->
<html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PictShare - the smart CDN</title>
<!-- Bootstrap -->
<link href="/css/bootstrap.min.css" rel="stylesheet">
<!-- PictShare overwrites -->
<link href="/css/pictshare.css" rel="stylesheet">
<link href="/css/dropzone.css" rel="stylesheet">
<link href="/css/hljs-dracula.css" rel="stylesheet">
<!-- github-fork-ribbon-css
https://simonwhitaker.github.io/github-fork-ribbon-css/ -->
<link href="/css/gh-fork-ribbon.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var maxUploadFileSize = <?php echo (int)(ini_get('upload_max_filesize')); ?>
</script>
<meta name="description" content="Free image sharing, linking and tracking">
<meta name="keywords" content="image, share, hosting, free">
<meta name="robots" content="index, follow">
<meta name="copyright" content="Haschek Solutions">
<meta name="language" content="EN,DE">
<meta name="author" content="Haschek Solutions">
<meta name="distribution" content="global">
<meta name="rating" content="general">
</HEAD>
<BODY>
<div class="container" id="headcontainer">
<div class="row">
<div class="col-md-8">
<a href="/"><img src="/css/imgs/logo/horizontalv3.png" /></a>
</div>
</div>
</div>
<div class="container">
<h2>Admin Panel</h2>
<?php if (!$_SESSION['admin']) { ?>
<h2>Admin Panel</h2>
<?php if (!$_SESSION['admin']) { ?>
<form method="post" action="/admin">
<div class="input-group mb-3">
<input type="password" class="form-control" name="password" placeholder="Password" aria-label="Password" aria-describedby="btn-addn">
<button class="btn btn-outline-secondary" type="submit" id="btn-addn">Login</button>
</div>
</form>
<?php } ?>
<?php if ($_SESSION['admin']) { ?>
<?php } ?>
<?php if ($_SESSION['admin']) { ?>
<div class="alert alert-success" role="alert">You are logged in as admin</div>
<form method="post" action="/admin">
<button type="submit" name="logout" class="btn btn-danger">Logout</button>
@@ -72,22 +15,11 @@
<ul class="nav">
<li class="nav-item">
<a class="nav-link" aria-current="page" href="#">Stats</a>
<a class="nav-link" aria-current="page" href="/admin/stats">Stats</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Review</a>
<a class="nav-link" href="/admin/logs">Logs</a>
</li>
</ul>
<?php } ?>
</div>
<div class="container">
<footer class="text-center">(c)<?php echo date("y"); ?> by<br /><a href="https://haschek.solutions" target="_blank"><img height="30" src="/css/imgs/hs_logo.png" /></a></footer>
</div>
<script src="/js/pictshare.js"></script>
</BODY>
</HTML>
<?php } ?>

View File

@@ -0,0 +1,15 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/admin">Admin</a></li>
<li class="breadcrumb-item"><a href="/admin/logs">Logs</a></li>
<li class="breadcrumb-item active" aria-current="page"><?=$type?></li>
</ol>
</nav>
<h1><?= ucfirst($type) ?></h1>
<pre>
<code><?php foreach($logs as $log):
echo $log;
endforeach; ?></code>
</pre>

View File

@@ -0,0 +1,10 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/admin">Admin</a></li>
<li class="breadcrumb-item active" aria-current="page">Logs</li>
</ol>
</nav>
<a class="btn btn-primary" href="/admin/logs/app">General App logs</a>
<a class="btn btn-primary" href="/admin/logs/views">Views</a>
<a class="btn btn-primary" href="/admin/logs/error">Errors</a>

View File

@@ -0,0 +1,41 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/admin">Admin</a></li>
<li class="breadcrumb-item active" aria-current="page">Stats</li>
</ol>
</nav>
<h1>Stats</h1>
<div class="table-responsive">
<table class="table table-hover" data-toggle="table" data-search="true">
<thead>
<tr>
<th scope="col" data-sortable="true">Hash</th>
<th scope="col" data-sortable="true">Views</th>
<th scope="col" data-sortable="true">Original Filename</th>
<th scope="col" data-sortable="true">MIME type</th>
<th scope="col" data-sortable="true">Created at</th>
<th scope="col" data-sortable="true">Uploader IP</th>
<?php if(defined('LOG_VIEWS') && LOG_VIEWS==true): ?>
<th scope="col" data-sortable="true">List views</th>
<?php endif; ?>
</tr>
</thead>
<tbody>
<?php foreach($stats['hashes'] as $hash => $data): ?>
<tr>
<th scope="row"><a href="/<?=$hash?>"><?=$hash?></a></th>
<td><?=$data['views']?:0?></td>
<td><?=$data['metadata']['original_filename']?></td>
<td><?=$data['metadata']['mime']?></td>
<td><?=date("Y-m-d H:i",$data['metadata']['uploaded'])?></td>
<td><?=$data['metadata']['ip']?></td>
<?php if(defined('LOG_VIEWS') && LOG_VIEWS==true): ?>
<td scope="col" data-sortable="true"><a class="btn btn-secondary" href="/admin/logs/views/<?=$hash?>">View logs</a></td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PictShare - the smart CDN</title>
<!-- Bootstrap -->
<link href="/css/bootstrap.min.css" rel="stylesheet">
<!-- PictShare overwrites -->
<link href="/css/pictshare.css" rel="stylesheet">
<link href="/css/dropzone.css" rel="stylesheet">
<link href="/css/bootstrap-table.min.css" rel="stylesheet">
<link href="/css/hljs-dracula.css" rel="stylesheet">
<!-- github-fork-ribbon-css
https://simonwhitaker.github.io/github-fork-ribbon-css/ -->
<link href="/css/gh-fork-ribbon.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var maxUploadFileSize = <?php echo (int)(ini_get('upload_max_filesize')); ?>
</script>
<meta name="description" content="Free image sharing, linking and tracking">
<meta name="keywords" content="image, share, hosting, free">
<meta name="robots" content="index, follow">
<meta name="copyright" content="Haschek Solutions">
<meta name="language" content="EN,DE">
<meta name="author" content="Haschek Solutions">
<meta name="distribution" content="global">
<meta name="rating" content="general">
</HEAD>
<BODY>
<div class="container" id="headcontainer">
<div class="row">
<div class="col-md-8">
<a href="/"><img src="/css/imgs/logo/horizontalv3.png" /></a>
</div>
</div>
</div>
<div id="main" class="container hv-100">
<?=$main;?>
</div>
<div class="footer">
<div class="container text-center">
<p>created by <a href="https://haschek.solutions" target="_blank"><img height="30" src="/css/imgs/hs_logo.png" /></a></p>
</div>
</div>
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap-table.min.js"></script>
<script src="/js/dropzone.js"></script>
<script src="/js/highlight.pack.js"></script>
<script src="/js/pictshare.js"></script>
</BODY>
</HTML>

View File

@@ -1,61 +1,8 @@
<!DOCTYPE html>
<!--[if IEMobile 7 ]> <html class="no-js iem7"> <![endif]-->
<!--[if (gt IEMobile 7)|!(IEMobile)]><!-->
<html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PictShare - the smart CDN</title>
<!-- Bootstrap -->
<link href="/css/bootstrap.min.css" rel="stylesheet">
<!-- PictShare overwrites -->
<link href="/css/pictshare.css" rel="stylesheet">
<link href="/css/dropzone.css" rel="stylesheet">
<link href="/css/hljs-dracula.css" rel="stylesheet">
<!-- github-fork-ribbon-css
https://simonwhitaker.github.io/github-fork-ribbon-css/ -->
<link href="/css/gh-fork-ribbon.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var maxUploadFileSize = <?php echo (int)(ini_get('upload_max_filesize')); ?>
</script>
<meta name="description" content="Free image sharing, linking and tracking">
<meta name="keywords" content="image, share, hosting, free">
<meta name="robots" content="index, follow">
<meta name="copyright" content="Haschek Solutions">
<meta name="language" content="EN,DE">
<meta name="author" content="Haschek Solutions">
<meta name="distribution" content="global">
<meta name="rating" content="general">
</HEAD>
<BODY>
<a class="github-fork-ribbon left-top" href="https://github.com/HaschekSolutions/pictshare" data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a>
<div class="container" id="headcontainer">
<div class="row">
<div class="col-md-8">
<a href="/"><img src="/css/imgs/logo/horizontalv3.png" /></a>
<?php
if (file_exists(ROOT . DS . 'notice.txt'))
<?php
if (file_exists(ROOT . DS . 'notice.txt'))
echo '<div class="alert alert-warning" role="alert">' . file_get_contents(ROOT . DS . 'notice.txt') . '</div>';
?>
<div class="well">
?>
<div class="well">
<?php if ($forbidden === true) { ?>
<h2>Upload forbidden</h2>
@@ -65,10 +12,10 @@
<?php } else { ?>
<div id="uploadinfo"></div>
<p>
Max Upload size: <?=(int)(ini_get('upload_max_filesize'))?>MB / File<br/>
Max Upload size: <?= (int)(ini_get('upload_max_filesize')) ?>MB / File<br />
Allowed file types: <?= implode(', ', getAllContentFiletypes()) ?>
<?php
if (defined('UPLOAD_CODE') && UPLOAD_CODE != ''):?>
if (defined('UPLOAD_CODE') && UPLOAD_CODE != ''): ?>
<br>Upload Code: <input type="password" id="uploadcode" />
<?php endif; ?>
</p>
@@ -78,21 +25,17 @@
</div>
</form>
<?php } ?>
</div>
</div>
</div>
</div>
</div>
<h2 id="api" class="section-heading">Using PictShare</h2>
<div class="container">
<h2 id="api" class="section-heading">Using PictShare</h2>
<div class="row">
<div class="row">
<div class="col-6">
<h3>Basics</h3>
<p>
When you upload an image you'll get a link like this:<pre><code class="url"><?= getURL() ?>abcef123.jpg</code></pre>
When you upload an image you'll get a link like this:
<pre><code class="url"><?= getURL() ?>abcef123.jpg</code></pre>
You can modify the size of the image by adding a size parameter to the URL. For example this will render the image in 800x600:
<pre><code class="url"><?= getURL() ?>800x600/abcef123.jpg</code></pre>
</p>
@@ -105,16 +48,12 @@
<p>There are many more of these <a target="_blank" href="https://github.com/HaschekSolutions/pictshare/blob/master/rtfm/MODIFIERS.md">modifiers</a> and even <a target="_blank" href="https://github.com/HaschekSolutions/pictshare/blob/master/rtfm/IMAGEFILTERS.md">filters</a> available</p>
</div>
</div>
</div>
<hr class="no-print border border-primary border-2 opacity-50">
</div>
<hr class="no-print border border-primary border-2 opacity-50">
<div class="container">
<h2 id="api" class="section-heading">Using the API</h2>
<div class="row">
<h2 id="api" class="section-heading">Using the API</h2>
<div class="row">
<div class="col-6">
<h2>Basics</h2>
@@ -220,18 +159,4 @@
</div>
</div>
</div>
<div class="container">
<footer>(c)<?php echo date("y"); ?> by<br /><a href="https://haschek.solutions" target="_blank"><img height="30" src="/css/imgs/hs_logo.png" /></a></footer>
</div>
<script src="/js/dropzone.js"></script>
<script src="/js/highlight.pack.js"></script>
<script src="/js/pictshare.js"></script>
</BODY>
</HTML>
</div>

10
web/css/bootstrap-table.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -6,6 +6,7 @@ body {
background-image: url('imgs/bg.png');
background-repeat: no-repeat;
background-color: #fff;
padding-bottom: 60px; /* Space for the footer */
}
#headcontainer
@@ -33,3 +34,12 @@ body {
.box__error {
display: none;
}
.footer {
position: fixed;
bottom: 0;
width: 100%;
height: 60px; /* Set the fixed height of the footer here */
line-height: 60px; /* Vertically center the text there */
background-color: #f5f5f5;
}

10
web/js/bootstrap-table.min.js vendored Normal file

File diff suppressed because one or more lines are too long

7
web/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
web/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -2,19 +2,20 @@ Dropzone.autoDiscover = false;
hljs.initHighlightingOnLoad();
document.addEventListener("DOMContentLoaded", function () {
if (document.getElementById("dropzone") != null) {
var myDropzone = new Dropzone("#dropzone");
if (typeof maxUploadFileSize !== "undefined")
myDropzone.options.maxFilesize = maxUploadFileSize;
myDropzone.options.timeout = 0;
myDropzone.on("sending", function(file, xhr, formData) {
myDropzone.on("sending", function (file, xhr, formData) {
var uploadCodeElem = document.getElementById("uploadcode");
if (uploadCodeElem)
formData.append("uploadcode", uploadCodeElem.value);
});
myDropzone.on('error', function(file, response) {
myDropzone.on('error', function (file, response) {
var uploadInfo = document.getElementById("uploadinfo");
if (response == null || response == "null") {
uploadInfo.insertAdjacentHTML("beforeend",
@@ -59,7 +60,7 @@ document.addEventListener("DOMContentLoaded", function () {
} else {
if (response.status == 'ok') {
uploadInfo.insertAdjacentHTML("beforeend",
renderMessage(file.name+" uploaded as <a target='_blank' href='/" + response.hash + "'>" + response.hash + "</a>","URL: <a target='_blank' href='" + response.url + "'>" + response.url + "</a> <button class='btn btn-primary btn-sm' onClick='navigator.clipboard.writeText(\"" + response.url + "\");'>Copy URL</button>","success")
renderMessage(file.name + " uploaded as <a target='_blank' href='/" + response.hash + "'>" + response.hash + "</a>", "URL: <a target='_blank' href='" + response.url + "'>" + response.url + "</a> <button class='btn btn-primary btn-sm' onClick='navigator.clipboard.writeText(\"" + response.url + "\");'>Copy URL</button>", "success")
);
} else if (response.status == 'err') {
uploadInfo.insertAdjacentHTML("beforeend",
@@ -82,10 +83,11 @@ document.addEventListener("DOMContentLoaded", function () {
}
}
};
}
});
function renderMessage(title,message,type){
if(!type)
function renderMessage(title, message, type) {
if (!type)
type = "danger";
return `<div class='alert alert-${type}' role='alert'><strong>${title}</strong><br/>${message}</div>`;
}