Browse Source

Frontend done

kanadeko 7 years ago
parent
commit
a246fc8365
9 changed files with 216 additions and 106 deletions
  1. 19 6
      config.sample.js
  2. 1 1
      controllers/uploadController.js
  3. 19 0
      database/db.js
  4. 8 16
      lolisafe.js
  5. 75 0
      public/css/style.css
  6. 47 1
      public/error/404.html
  7. 30 73
      public/index.html
  8. 0 9
      routes.js
  9. 17 0
      routes/routes.js

+ 19 - 6
config.sample.js

@@ -1,5 +1,13 @@
 module.exports = {
 
+	/* 
+	NOTES:
+	
+		All folders specified on this file will be created automagically.
+		Most options shouldn't be touched, and the service should run straight up.
+
+	*/
+
 	// Port on which to run the server
 	port: 9999,
 
@@ -12,7 +20,8 @@ module.exports = {
 		// If not, which IP's should be able to access?
 		IPs: [
 			'::1',
-			'127.0.0.1'
+			'127.0.0.1',
+			'186.19.241.189'
 		]
 	},
 
@@ -23,20 +32,24 @@ module.exports = {
 		folder: 'uploads',
 
 		// Max file size allowed
-		maxsize: '512MB'
+		maxsize: '512MB',
+
+		// The length of the random generated name for the uploaded files
+		fileLength: 4,
+
+		// Prefix before linking an uploaded file. Ex: your-domain.com/prefix/k4n4.png
+		// Leave blank for no prefix
+		prefix: ''
 	},
 
 	// Folder where to store logs
 	logsFolder: 'logs',
 
-	// The length of the random generated name for the uploaded files
-	fileLength: 4,
-
 	// The following values shouldn't be touched
 	database: {
 		client: 'sqlite3',
 		connection: {
-			filename: './db'
+			filename: './database/db'
 		},
 		useNullAsDefault: true
 	}

+ 1 - 1
controllers/uploadController.js

@@ -11,7 +11,7 @@ const storage = multer.diskStorage({
 		cb(null, './' + config.uploads.folder + '/')
 	},
 	filename: function (req, file, cb) {
-		cb(null, randomstring.generate(config.fileLength) + path.extname(file.originalname))
+		cb(null, randomstring.generate(config.uploads.fileLength) + path.extname(file.originalname))
 	}
 })
 

+ 19 - 0
database/db.js

@@ -0,0 +1,19 @@
+
+let init = function(db){
+
+	// Create the tables we need to store galleries and files
+	db.schema.createTableIfNotExists('gallery', function (table) {
+		table.increments()
+		table.string('name')
+		table.timestamps()
+	}).then(() => {})
+
+	db.schema.createTableIfNotExists('files', function (table) {
+		table.increments()
+		table.string('file')
+		table.integer('galleryid')
+	}).then(() => {})
+
+}
+
+module.exports = init

+ 8 - 16
lolisafe.js

@@ -1,17 +1,22 @@
 const config = require('./config.js')
-const routes = require('./routes.js')
+const routes = require('./routes/routes.js')
 const express = require('express')
 const db = require('knex')(config.database)
 const fs = require('fs')
 const safe = express()
 
+require('./database/db.js')(db)
+
 fs.existsSync('./' + config.uploads.folder) || fs.mkdirSync('./' + config.uploads.folder)
 fs.existsSync('./' + config.logsFolder) || fs.mkdirSync('./' + config.logsFolder)
-fs.existsSync('db') || fs.writeFile('db', '')
 
 safe.enable('trust proxy')
 
-safe.use('/', express.static('./uploads'))
+let prefix = config.uploads.prefix
+if( prefix !== '' )
+	prefix = prefix + '/'
+
+safe.use('/' + prefix, express.static('./uploads'))
 safe.use('/', express.static('./public'))
 safe.use('/api'  , routes)
 
@@ -25,17 +30,4 @@ safe.use(function (err, req, res, next) {
 	res.status(500).end()
 })
 
-// Create the tables we need to store galleries and files
-db.schema.createTableIfNotExists('gallery', function (table) {
-	table.increments()
-	table.string('name')
-	table.timestamps()
-}).then(() => {})
-
-db.schema.createTableIfNotExists('files', function (table) {
-	table.increments()
-	table.string('file')
-	table.integer('galleryid')
-}).then(() => {})
-
 safe.listen(config.port, () => console.log(`loli-safe started on port ${config.port}`))

+ 75 - 0
public/css/style.css

@@ -0,0 +1,75 @@
+/* ------------------
+		HOME
+------------------ */
+
+#b {
+	-webkit-animation-delay: 0.5s;
+	animation-delay: 0.5s;
+	-webkit-animation-duration: 1.5s;
+	animation-duration: 1.5s;
+	-webkit-animation-fill-mode: both;
+	animation-fill-mode: both;
+	-webkit-animation-name: floatUp;
+	animation-name: floatUp;
+	-webkit-animation-timing-function: cubic-bezier(0, 0.71, 0.29, 1);
+	animation-timing-function: cubic-bezier(0, 0.71, 0.29, 1);
+	border-radius: 24px;
+	display: inline-block;
+	height: 240px;
+	margin-bottom: 40px;
+	position: relative;
+	vertical-align: top;
+	width: 240px;
+	box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
+}
+
+div#dropzone {
+	border: 1px solid #dbdbdb;
+	background-color: rgba(0, 0, 0, 0);
+    border-color: #ff3860;
+    color: #ff3860;
+    display: flex;
+    width: 100%;
+    border-radius: 3px;
+    box-shadow: none;
+    height: 2.5em;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    user-select: none;
+    justify-content: center;
+    padding-left: .75em;
+    padding-right: .75em;
+    text-align: center;
+    cursor: pointer;   
+}
+
+div#dropzone:hover {
+	background-color: #ff3860;
+    border-color: #ff3860;
+    color: #fff;
+}
+img.logo { height: 200px; margin-top: 20px; }
+.dz-preview .dz-details { display: flex; }
+.dz-preview .dz-details .dz-size, .dz-preview .dz-details .dz-filename { flex: 1 }
+.dz-preview img, .dz-preview .dz-success-mark, .dz-preview .dz-error-mark { display: none }
+
+@keyframes floatUp {
+	0% {
+		opacity: 0;
+		box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0);
+		-webkit-transform: scale(0.86);
+		transform: scale(0.86);
+	}
+	25% { opacity: 100; }
+	67% {
+		box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
+		-webkit-transform: scale(1);
+		transform: scale(1);
+	}
+	100% {
+		box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
+		-webkit-transform: scale(1);
+		transform: scale(1);
+	}
+}

+ 47 - 1
public/error/404.html

@@ -1 +1,47 @@
-404
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>loli-safe</title>
+
+        <link href='//fonts.googleapis.com/css?family=Lato:100' rel='stylesheet' type='text/css'>
+
+        <style>
+            html, body {
+                height: 100%;
+            }
+
+            body {
+                margin: 0;
+                padding: 0;
+                width: 100%;
+                color: #B0BEC5;
+                display: table;
+                font-weight: 100;
+                font-family: 'Lato';
+            }
+
+            .container {
+                text-align: center;
+                display: table-cell;
+                vertical-align: middle;
+            }
+
+            .content {
+                text-align: center;
+                display: inline-block;
+            }
+
+            .title {
+                font-size: 72px;
+                margin-bottom: 40px;
+            }
+        </style>
+    </head>
+    <body>
+        <div class="container">
+            <div class="content">
+                <div class="title">Page not found.</div>
+            </div>
+        </div>
+    </body>
+</html>

+ 30 - 73
public/index.html

@@ -3,62 +3,8 @@
 	<head>
 		<title>loli-safe - A self hosted upload service</title>
 		<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.3.0/css/bulma.min.css">
-		<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/min/dropzone.min.css">
+		<link rel="stylesheet" type="text/css" href="/css/style.css">
 		<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.3.0/min/dropzone.min.js"></script>
-		
-		<style type="text/css">
-			#b {
-				-webkit-animation-delay: 0.5s;
-				animation-delay: 0.5s;
-				-webkit-animation-duration: 1.5s;
-				animation-duration: 1.5s;
-				-webkit-animation-fill-mode: both;
-				animation-fill-mode: both;
-				-webkit-animation-name: floatUp;
-				animation-name: floatUp;
-				-webkit-animation-timing-function: cubic-bezier(0, 0.71, 0.29, 1);
-				animation-timing-function: cubic-bezier(0, 0.71, 0.29, 1);
-				border-radius: 24px;
-				display: inline-block;
-				height: 240px;
-				margin-bottom: 40px;
-				position: relative;
-				vertical-align: top;
-				width: 240px;
-				box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
-			}
-			img.logo {
-				height: 200px;
-				margin-top: 20px;
-			}
-
-			.dz-preview .dz-details { display: flex; }
-			.dz-preview .dz-details .dz-size, .dz-preview .dz-details .dz-filename { flex: 1 }
-			.dz-preview img, .dz-preview .dz-success-mark, .dz-preview .dz-error-mark { display: none }
-
-			@keyframes floatUp {
-				0% {
-					opacity: 0;
-					box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0);
-					-webkit-transform: scale(0.86);
-					transform: scale(0.86);
-				}
-				25% {
-					opacity: 100;
-				}
-				67% {
-					box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
-					-webkit-transform: scale(1);
-					transform: scale(1);
-				}
-				100% {
-					box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);
-					-webkit-transform: scale(1);
-					transform: scale(1);
-				}
-			}
-
-		</style>
 	</head>
 
 	<body>
@@ -78,15 +24,7 @@
 					<div class="columns">
 						<div class="column"></div>
 						<div class="column">
-							<a class="button is-danger is-outlined is-fullwidth" id="upload-button">Upload files</a>
-						</div>
-						<div class="column"></div>
-					</div>
-
-					<div class="columns">
-						<div class="column"></div>
-						<div class="column">
-							<div class="notification" id="dropzone">Or drag and drop files here</div>
+							<div id="dropzone">Click here or drag and drop files</div>
 						</div>
 						<div class="column"></div>
 					</div>
@@ -112,7 +50,25 @@
 		</section>
 
 		<script type="text/javascript">
+
+			var maxSize = '512';
+			var urlPrefix = '';
+
+			var xhr = new XMLHttpRequest();
+			xhr.onreadystatechange = function() {
+				if (xhr.readyState == XMLHttpRequest.DONE) {
+					if(xhr.responseText.maxFileSize)
+						maxSize = xhr.responseText.maxFileSize
+					if(xhr.responseText.urlPrefix)
+						urlPrefix = xhr.responseText.urlPrefix + '/'
+				}
+			}
+			xhr.open('GET', '/api/info', true);
+			xhr.send(null);
+
 			window.onload = function () {
+
+
 				var previewNode = document.querySelector("#template");
 				previewNode.id = "";
 				var previewTemplate = previewNode.parentNode.innerHTML;
@@ -121,7 +77,7 @@
 				var dropzone = new Dropzone('div#dropzone', { 
 					url: '/api/upload',
 					paramName: 'file',
-					maxFilesize: 512,
+					maxFilesize: maxSize,
 					parallelUploads: 2,
 					uploadMultiple: false,
 					previewsContainer: 'div#uploads',
@@ -137,14 +93,15 @@
 				});
 
 				dropzone.on("success", function(file, response) {
-      				// Handle the responseText here. For example, add the text to the preview element:
-      				a = document.createElement('a');
-      				a.href = 'https://i.kanacchi.moe/' + response.filename;
-      				a.innerHTML = response.filename;
-
-      				file.previewTemplate.querySelector(".progress").style.display = 'none';
-      				file.previewTemplate.querySelector(".link").appendChild(a);
-    			});
+					// Handle the responseText here. For example, add the text to the preview element:
+					a = document.createElement('a');
+					a.href = window.location.origin + '/' + urlPrefix + response.filename;
+					a.target = '_blank';
+					a.innerHTML = response.filename;
+
+					file.previewTemplate.querySelector(".progress").style.display = 'none';
+					file.previewTemplate.querySelector(".link").appendChild(a);
+				});
 
 			};
 		</script>

+ 0 - 9
routes.js

@@ -1,9 +0,0 @@
-const routes            	= require('express').Router()
-const uploadController    	= require('./controllers/uploadController')
-const galleryController      = require('./controllers/galleryController')
-
-routes.post ('/upload', (req, res, next) => uploadController.upload(req, res, next))
-routes.get  ('/gallery', (req, res, next) => galleryController.list(req, res, next))
-routes.get  ('/gallery/test', (req, res, next) => galleryController.test(req, res, next))
-
-module.exports = routes

+ 17 - 0
routes/routes.js

@@ -0,0 +1,17 @@
+const config = require('../config.js')
+const routes = require('express').Router()
+const uploadController = require('../controllers/uploadController')
+const galleryController = require('../controllers/galleryController')
+
+routes.get  ('/info', (req, res, next) => {
+	res.json({
+		maxFileSize: config.uploads.maxsize.slice(0, -2),
+		urlPrefix: config.uploads.prefix
+	})
+})
+
+routes.post ('/upload', (req, res, next) => uploadController.upload(req, res, next))
+routes.get  ('/gallery', (req, res, next) => galleryController.list(req, res, next))
+routes.get  ('/gallery/test', (req, res, next) => galleryController.test(req, res, next))
+
+module.exports = routes