mirror of https://github.com/Requarks/wiki.git
NGPixel
8 years ago
12 changed files with 367 additions and 119 deletions
Split View
Diff Options
-
84agent.js
-
2assets/js/app.js
-
67client/js/components/editor-image.js
-
10controllers/pages.js
-
15controllers/uploads.js
-
2models/entries.js
-
17models/git.js
-
64models/localdata.js
-
176models/uploads.js
-
1package.json
-
32views/error-notexist.pug
-
16ws-server.js
2
assets/js/app.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,176 @@ |
|||
"use strict"; |
|||
|
|||
var path = require('path'), |
|||
Promise = require('bluebird'), |
|||
fs = Promise.promisifyAll(require('fs-extra')), |
|||
readChunk = require('read-chunk'), |
|||
fileType = require('file-type'), |
|||
farmhash = require('farmhash'), |
|||
moment = require('moment'), |
|||
chokidar = require('chokidar'), |
|||
_ = require('lodash'); |
|||
|
|||
/** |
|||
* Uploads |
|||
* |
|||
* @param {Object} appconfig The application configuration |
|||
*/ |
|||
module.exports = { |
|||
|
|||
_uploadsPath: './repo/uploads', |
|||
_uploadsThumbsPath: './data/thumbs', |
|||
|
|||
_watcher: null, |
|||
|
|||
/** |
|||
* Initialize Uploads model |
|||
* |
|||
* @param {Object} appconfig The application config |
|||
* @return {Object} Uploads model instance |
|||
*/ |
|||
init(appconfig) { |
|||
|
|||
let self = this; |
|||
|
|||
self._uploadsPath = path.resolve(ROOTPATH, appconfig.datadir.repo, 'uploads'); |
|||
self._uploadsThumbsPath = path.resolve(ROOTPATH, appconfig.datadir.db, 'thumbs'); |
|||
|
|||
return self; |
|||
|
|||
}, |
|||
|
|||
watch() { |
|||
|
|||
let self = this; |
|||
|
|||
self._watcher = chokidar.watch(self._uploadsPath, { |
|||
persistent: true, |
|||
ignoreInitial: true, |
|||
cwd: self._uploadsPath, |
|||
depth: 1, |
|||
awaitWriteFinish: true |
|||
}); |
|||
|
|||
self._watcher.on('add', (p) => { |
|||
|
|||
let pInfo = lcdata.parseUploadsRelPath(p); |
|||
return self.processFile(pInfo.folder, pInfo.filename).then((mData) => { |
|||
ws.emit('uploadsAddFiles', { |
|||
auth: WSInternalKey, |
|||
content: mData |
|||
}); |
|||
}).then(() => { |
|||
return git.commitUploads(); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}, |
|||
|
|||
processFile(fldName, f) { |
|||
|
|||
let self = this; |
|||
|
|||
let fldPath = path.join(self._uploadsPath, fldName); |
|||
let fPath = path.join(fldPath, f); |
|||
let fPathObj = path.parse(fPath); |
|||
let fUid = farmhash.fingerprint32(fldName + '/' + f); |
|||
|
|||
return fs.statAsync(fPath).then((s) => { |
|||
|
|||
if(!s.isFile()) { return false; } |
|||
|
|||
// Get MIME info
|
|||
|
|||
let mimeInfo = fileType(readChunk.sync(fPath, 0, 262)); |
|||
|
|||
// Images
|
|||
|
|||
if(s.size < 3145728) { // ignore files larger than 3MB
|
|||
if(_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], mimeInfo.mime)) { |
|||
return self.getImageMetadata(fPath).then((mData) => { |
|||
|
|||
let cacheThumbnailPath = path.parse(path.join(self._uploadsThumbsPath, fUid + '.png')); |
|||
let cacheThumbnailPathStr = path.format(cacheThumbnailPath); |
|||
|
|||
mData = _.pick(mData, ['format', 'width', 'height', 'density', 'hasAlpha', 'orientation']); |
|||
mData.uid = fUid; |
|||
mData.category = 'image'; |
|||
mData.mime = mimeInfo.mime; |
|||
mData.folder = fldName; |
|||
mData.filename = f; |
|||
mData.basename = fPathObj.name; |
|||
mData.filesize = s.size; |
|||
mData.uploadedOn = moment().utc(); |
|||
|
|||
// Generate thumbnail
|
|||
|
|||
return fs.statAsync(cacheThumbnailPathStr).then((st) => { |
|||
return st.isFile(); |
|||
}).catch((err) => { |
|||
return false; |
|||
}).then((thumbExists) => { |
|||
|
|||
return (thumbExists) ? mData : fs.ensureDirAsync(cacheThumbnailPath.dir).then(() => { |
|||
return self.generateThumbnail(fPath, cacheThumbnailPathStr); |
|||
}).return(mData); |
|||
|
|||
}); |
|||
|
|||
}) |
|||
} |
|||
} |
|||
|
|||
// Other Files
|
|||
|
|||
return { |
|||
uid: fUid, |
|||
category: 'file', |
|||
mime: mimeInfo.mime, |
|||
folder: fldName, |
|||
filename: f, |
|||
basename: fPathObj.name, |
|||
filesize: s.size, |
|||
uploadedOn: moment().utc() |
|||
}; |
|||
|
|||
}); |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* Generate thumbnail of image |
|||
* |
|||
* @param {String} sourcePath The source path |
|||
* @return {Promise<Object>} Promise returning the resized image info |
|||
*/ |
|||
generateThumbnail(sourcePath, destPath) { |
|||
|
|||
let sharp = require('sharp'); |
|||
|
|||
return sharp(sourcePath) |
|||
.withoutEnlargement() |
|||
.resize(150,150) |
|||
.background('white') |
|||
.embed() |
|||
.flatten() |
|||
.toFormat('png') |
|||
.toFile(destPath); |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* Gets the image metadata. |
|||
* |
|||
* @param {String} sourcePath The source path |
|||
* @return {Object} The image metadata. |
|||
*/ |
|||
getImageMetadata(sourcePath) { |
|||
|
|||
let sharp = require('sharp'); |
|||
|
|||
return sharp(sourcePath).metadata(); |
|||
|
|||
} |
|||
|
|||
}; |
@ -0,0 +1,32 @@ |
|||
doctype html |
|||
html |
|||
head |
|||
meta(http-equiv='X-UA-Compatible', content='IE=edge') |
|||
meta(charset='UTF-8') |
|||
meta(name='viewport', content='width=device-width, initial-scale=1') |
|||
meta(name='theme-color', content='#009688') |
|||
meta(name='msapplication-TileColor', content='#009688') |
|||
meta(name='msapplication-TileImage', content='/favicons/ms-icon-144x144.png') |
|||
title= appconfig.title |
|||
|
|||
// Favicon |
|||
each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180] |
|||
link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href='/favicons/apple-icon-' + favsize + 'x' + favsize + '.png') |
|||
link(rel='icon', type='image/png', sizes='192x192', href='/favicons/android-icon-192x192.png') |
|||
each favsize in [32, 96, 16] |
|||
link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png') |
|||
link(rel='manifest', href='/manifest.json') |
|||
|
|||
// CSS |
|||
link(type='text/css', rel='stylesheet', href='/css/libs.css') |
|||
link(type='text/css', rel='stylesheet', href='/css/app.css') |
|||
|
|||
body(class='server-error') |
|||
section.hero.is-dark.is-fullheight |
|||
.hero-body |
|||
.container |
|||
a(href='/'): img(src='/favicons/android-icon-96x96.png') |
|||
h1.title(style={ 'margin-top': '30px'})= message |
|||
h2.subtitle(style={ 'margin-bottom': '50px'}) Would you like to create this entry? |
|||
a.button.is-dark.is-inverted(href='/create/' + newpath, style={'margin-right': '5px'}) Create |
|||
a.button.is-dark.is-inverted(href='/') Go Home |
Write
Preview
Loading…
Cancel
Save