mirror of https://github.com/Requarks/wiki.git
29 changed files with 347 additions and 3982 deletions
Split View
Diff Options
-
20agent.js
-
2assets/js/app.js
-
37client/js/components/editor-image.js
-
144client/js/components/search.js
-
7config.sample.yml
-
6controllers/pages.js
-
5controllers/uploads.js
-
48controllers/ws.js
-
3427lib/mimes.json
-
0libs/auth.js
-
0libs/config.js
-
68libs/entries.js
-
0libs/git.js
-
0libs/internalAuth.js
-
0libs/local.js
-
0libs/markdown.js
-
2libs/mongo.js
-
15libs/uploads-agent.js
-
82libs/uploads.js
-
0libs/winston.js
-
0models/entry.js
-
0models/upl-file.js
-
5models/upl-folder.js
-
0models/user.js
-
133models/ws/search.js
-
120server.js
-
2views/layout.pug
-
22views/modals/editor-image.pug
-
184ws-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
@ -1,88 +1,84 @@ |
|||
"use strict"; |
|||
|
|||
jQuery( document ).ready(function( $ ) { |
|||
if($('#search-input').length) { |
|||
|
|||
if($('#search-input').length) { |
|||
$('#search-input').focus(); |
|||
|
|||
$('#search-input').focus(); |
|||
$('.searchresults').css('display', 'block'); |
|||
|
|||
$('.searchresults').css('display', 'block'); |
|||
|
|||
var vueHeader = new Vue({ |
|||
el: '#header-container', |
|||
data: { |
|||
searchq: '', |
|||
searchres: [], |
|||
searchsuggest: [], |
|||
searchload: 0, |
|||
searchactive: false, |
|||
searchmoveidx: 0, |
|||
searchmovekey: '', |
|||
searchmovearr: [] |
|||
var vueHeader = new Vue({ |
|||
el: '#header-container', |
|||
data: { |
|||
searchq: '', |
|||
searchres: [], |
|||
searchsuggest: [], |
|||
searchload: 0, |
|||
searchactive: false, |
|||
searchmoveidx: 0, |
|||
searchmovekey: '', |
|||
searchmovearr: [] |
|||
}, |
|||
watch: { |
|||
searchq: (val, oldVal) => { |
|||
vueHeader.searchmoveidx = 0; |
|||
if(val.length >= 3) { |
|||
vueHeader.searchactive = true; |
|||
vueHeader.searchload++; |
|||
socket.emit('search', { terms: val }, (data) => { |
|||
vueHeader.searchres = data.match; |
|||
vueHeader.searchsuggest = data.suggest; |
|||
vueHeader.searchmovearr = _.concat([], vueHeader.searchres, vueHeader.searchsuggest); |
|||
if(vueHeader.searchload > 0) { vueHeader.searchload--; } |
|||
}); |
|||
} else { |
|||
vueHeader.searchactive = false; |
|||
vueHeader.searchres = []; |
|||
vueHeader.searchsuggest = []; |
|||
vueHeader.searchmovearr = []; |
|||
vueHeader.searchload = 0; |
|||
} |
|||
}, |
|||
watch: { |
|||
searchq: (val, oldVal) => { |
|||
vueHeader.searchmoveidx = 0; |
|||
if(val.length >= 3) { |
|||
vueHeader.searchactive = true; |
|||
vueHeader.searchload++; |
|||
socket.emit('search', { terms: val }, (data) => { |
|||
vueHeader.searchres = data.match; |
|||
vueHeader.searchsuggest = data.suggest; |
|||
vueHeader.searchmovearr = _.concat([], vueHeader.searchres, vueHeader.searchsuggest); |
|||
if(vueHeader.searchload > 0) { vueHeader.searchload--; } |
|||
}); |
|||
} else { |
|||
vueHeader.searchactive = false; |
|||
vueHeader.searchres = []; |
|||
vueHeader.searchsuggest = []; |
|||
vueHeader.searchmovearr = []; |
|||
vueHeader.searchload = 0; |
|||
} |
|||
}, |
|||
searchmoveidx: (val, oldVal) => { |
|||
if(val > 0) { |
|||
vueHeader.searchmovekey = (vueHeader.searchmovearr[val - 1]) ? |
|||
'res.' + vueHeader.searchmovearr[val - 1]._id : |
|||
'sug.' + vueHeader.searchmovearr[val - 1]; |
|||
} else { |
|||
vueHeader.searchmovekey = ''; |
|||
} |
|||
searchmoveidx: (val, oldVal) => { |
|||
if(val > 0) { |
|||
vueHeader.searchmovekey = (vueHeader.searchmovearr[val - 1]) ? |
|||
'res.' + vueHeader.searchmovearr[val - 1]._id : |
|||
'sug.' + vueHeader.searchmovearr[val - 1]; |
|||
} else { |
|||
vueHeader.searchmovekey = ''; |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
useSuggestion: (sug) => { |
|||
vueHeader.searchq = sug; |
|||
}, |
|||
methods: { |
|||
useSuggestion: (sug) => { |
|||
vueHeader.searchq = sug; |
|||
}, |
|||
closeSearch: () => { |
|||
vueHeader.searchq = ''; |
|||
}, |
|||
moveSelectSearch: () => { |
|||
if(vueHeader.searchmoveidx < 1) { return; } |
|||
let i = vueHeader.searchmoveidx - 1; |
|||
closeSearch: () => { |
|||
vueHeader.searchq = ''; |
|||
}, |
|||
moveSelectSearch: () => { |
|||
if(vueHeader.searchmoveidx < 1) { return; } |
|||
let i = vueHeader.searchmoveidx - 1; |
|||
|
|||
if(vueHeader.searchmovearr[i]) { |
|||
window.location.assign('/' + vueHeader.searchmovearr[i]._id); |
|||
} else { |
|||
vueHeader.searchq = vueHeader.searchmovearr[i]; |
|||
} |
|||
if(vueHeader.searchmovearr[i]) { |
|||
window.location.assign('/' + vueHeader.searchmovearr[i]._id); |
|||
} else { |
|||
vueHeader.searchq = vueHeader.searchmovearr[i]; |
|||
} |
|||
|
|||
}, |
|||
moveDownSearch: () => { |
|||
if(vueHeader.searchmoveidx < vueHeader.searchmovearr.length) { |
|||
vueHeader.searchmoveidx++; |
|||
} |
|||
}, |
|||
moveUpSearch: () => { |
|||
if(vueHeader.searchmoveidx > 0) { |
|||
vueHeader.searchmoveidx--; |
|||
} |
|||
}, |
|||
moveDownSearch: () => { |
|||
if(vueHeader.searchmoveidx < vueHeader.searchmovearr.length) { |
|||
vueHeader.searchmoveidx++; |
|||
} |
|||
}, |
|||
moveUpSearch: () => { |
|||
if(vueHeader.searchmoveidx > 0) { |
|||
vueHeader.searchmoveidx--; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
$('main').on('click', vueHeader.closeSearch); |
|||
} |
|||
}); |
|||
|
|||
} |
|||
$('main').on('click', vueHeader.closeSearch); |
|||
|
|||
}); |
|||
} |
@ -0,0 +1,48 @@ |
|||
"use strict"; |
|||
|
|||
module.exports = (socket) => { |
|||
|
|||
//-----------------------------------------
|
|||
// SEARCH
|
|||
//-----------------------------------------
|
|||
|
|||
socket.on('search', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
entries.search(data.terms).then((results) => { |
|||
cb(results); |
|||
}); |
|||
}); |
|||
|
|||
//-----------------------------------------
|
|||
// UPLOADS
|
|||
//-----------------------------------------
|
|||
|
|||
socket.on('uploadsGetFolders', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
upl.getUploadsFolders().then((f) => { |
|||
cb(f); |
|||
}) |
|||
}); |
|||
|
|||
socket.on('uploadsCreateFolder', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
upl.createUploadsFolder(data.foldername).then((f) => { |
|||
cb(f); |
|||
}); |
|||
}); |
|||
|
|||
socket.on('uploadsGetImages', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
upl.getUploadsFiles('image', data.folder).then((f) => { |
|||
cb(f); |
|||
}); |
|||
}); |
|||
|
|||
socket.on('uploadsDeleteFile', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
upl.deleteUploadsFile(data.uid).then((f) => { |
|||
cb(f); |
|||
}); |
|||
}); |
|||
|
|||
}; |
3427
lib/mimes.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,133 +0,0 @@ |
|||
"use strict"; |
|||
|
|||
const Promise = require('bluebird'), |
|||
_ = require('lodash'), |
|||
path = require('path'); |
|||
|
|||
/** |
|||
* Search Model |
|||
*/ |
|||
module.exports = { |
|||
|
|||
_si: null, |
|||
|
|||
/** |
|||
* Initialize Search model |
|||
* |
|||
* @param {Object} appconfig The application config |
|||
* @return {Object} Search model instance |
|||
*/ |
|||
init(appconfig) { |
|||
|
|||
let self = this; |
|||
|
|||
return self; |
|||
|
|||
}, |
|||
|
|||
find(terms) { |
|||
|
|||
let self = this; |
|||
terms = _.chain(terms) |
|||
.deburr() |
|||
.toLower() |
|||
.trim() |
|||
.replace(/[^a-z0-9 ]/g, '') |
|||
.split(' ') |
|||
.filter((f) => { return !_.isEmpty(f); }) |
|||
.join(' ') |
|||
.value(); |
|||
|
|||
return db.Entry.find( |
|||
{ $text: { $search: terms } }, |
|||
{ score: { $meta: "textScore" }, title: 1 } |
|||
) |
|||
.sort({ score: { $meta: "textScore" } }) |
|||
.limit(10) |
|||
.exec() |
|||
.then((hits) => { |
|||
|
|||
/*if(hits.length < 5) { |
|||
return self._si.matchAsync({ |
|||
beginsWith: terms, |
|||
threshold: 3, |
|||
limit: 5, |
|||
type: 'simple' |
|||
}).then((matches) => { |
|||
|
|||
return { |
|||
match: hits, |
|||
suggest: matches |
|||
}; |
|||
|
|||
}); |
|||
} else {*/ |
|||
return { |
|||
match: hits, |
|||
suggest: [] |
|||
}; |
|||
//}
|
|||
|
|||
}).catch((err) => { |
|||
|
|||
if(err.type === 'NotFoundError') { |
|||
return { |
|||
match: [], |
|||
suggest: [] |
|||
}; |
|||
} else { |
|||
winston.error(err); |
|||
} |
|||
|
|||
}); |
|||
|
|||
}, |
|||
|
|||
/** |
|||
* Delete an entry from the index |
|||
* |
|||
* @param {String} The entry path |
|||
* @return {Promise} Promise of the operation |
|||
*/ |
|||
delete(entryPath) { |
|||
|
|||
let self = this; |
|||
/*let hasResults = false; |
|||
|
|||
return new Promise((resolve, reject) => { |
|||
|
|||
self._si.search({ |
|||
query: { |
|||
AND: { 'entryPath': [entryPath] } |
|||
} |
|||
}).on('data', (results) => { |
|||
|
|||
hasResults = true; |
|||
|
|||
if(results.totalHits > 0) { |
|||
let delIds = _.map(results.hits, 'id'); |
|||
self._si.del(delIds).on('end', () => { return resolve(true); }); |
|||
} else { |
|||
resolve(true); |
|||
} |
|||
|
|||
}).on('error', (err) => { |
|||
|
|||
if(err.type === 'NotFoundError') { |
|||
resolve(true); |
|||
} else { |
|||
winston.error(err); |
|||
reject(err); |
|||
} |
|||
|
|||
}).on('end', () => { |
|||
if(!hasResults) { |
|||
resolve(true); |
|||
} |
|||
}); |
|||
|
|||
});*/ |
|||
|
|||
} |
|||
|
|||
}; |
@ -1,184 +0,0 @@ |
|||
// ===========================================
|
|||
// REQUARKS WIKI - WebSocket Server
|
|||
// 1.0.0
|
|||
// Licensed under AGPLv3
|
|||
// ===========================================
|
|||
|
|||
global.ROOTPATH = __dirname; |
|||
global.PROCNAME = 'WS'; |
|||
|
|||
// ----------------------------------------
|
|||
// Load Winston
|
|||
// ----------------------------------------
|
|||
|
|||
var _isDebug = process.env.NODE_ENV === 'development'; |
|||
global.winston = require('./lib/winston')(_isDebug); |
|||
|
|||
// ----------------------------------------
|
|||
// Fetch internal handshake key
|
|||
// ----------------------------------------
|
|||
|
|||
if(!process.argv[2] || process.argv[2].length !== 40) { |
|||
winston.error('[WS] Illegal process start. Missing handshake key.'); |
|||
process.exit(1); |
|||
} |
|||
global.internalAuth = require('./lib/internalAuth').init(process.argv[2]);; |
|||
|
|||
// ----------------------------------------
|
|||
// Load global modules
|
|||
// ----------------------------------------
|
|||
|
|||
winston.info('[WS] WS Server is initializing...'); |
|||
|
|||
var appconfig = require('./models/config')('./config.yml'); |
|||
global.db = require('./models/mongo').init(appconfig); |
|||
global.upl = require('./models/ws/uploads').init(appconfig); |
|||
global.entries = require('./models/entries').init(appconfig); |
|||
global.mark = require('./models/markdown'); |
|||
global.search = require('./models/ws/search').init(appconfig); |
|||
|
|||
// ----------------------------------------
|
|||
// Load local modules
|
|||
// ----------------------------------------
|
|||
|
|||
var _ = require('lodash'); |
|||
var express = require('express'); |
|||
var path = require('path'); |
|||
var http = require('http'); |
|||
var socketio = require('socket.io'); |
|||
var moment = require('moment'); |
|||
|
|||
// ----------------------------------------
|
|||
// Define Express App
|
|||
// ----------------------------------------
|
|||
|
|||
global.app = express(); |
|||
|
|||
// ----------------------------------------
|
|||
// Controllers
|
|||
// ----------------------------------------
|
|||
|
|||
app.get('/', function(req, res){ |
|||
res.send('Requarks Wiki WebSocket server'); |
|||
}); |
|||
|
|||
// ----------------------------------------
|
|||
// Start WebSocket server
|
|||
// ----------------------------------------
|
|||
|
|||
winston.info('[SERVER] Starting WebSocket server on port ' + appconfig.wsPort + '...'); |
|||
|
|||
app.set('port', appconfig.wsPort); |
|||
var server = http.Server(app); |
|||
var io = socketio(server); |
|||
|
|||
server.on('error', (error) => { |
|||
if (error.syscall !== 'listen') { |
|||
throw error; |
|||
} |
|||
|
|||
switch (error.code) { |
|||
case 'EACCES': |
|||
console.error('Listening on port ' + appconfig.port + ' requires elevated privileges!'); |
|||
process.exit(1); |
|||
break; |
|||
case 'EADDRINUSE': |
|||
console.error('Port ' + appconfig.port + ' is already in use!'); |
|||
process.exit(1); |
|||
break; |
|||
default: |
|||
throw error; |
|||
} |
|||
}); |
|||
|
|||
server.listen(appconfig.wsPort, () => { |
|||
winston.info('[WS] WebSocket server started successfully! [RUNNING]'); |
|||
}); |
|||
|
|||
io.on('connection', (socket) => { |
|||
|
|||
//-----------------------------------------
|
|||
// SEARCH
|
|||
//-----------------------------------------
|
|||
|
|||
socket.on('searchAdd', (data) => { |
|||
if(internalAuth.validateKey(data.auth)) { |
|||
search.add(data.content); |
|||
} |
|||
}); |
|||
|
|||
socket.on('searchDel', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
if(internalAuth.validateKey(data.auth)) { |
|||
search.delete(data.entryPath); |
|||
} |
|||
}); |
|||
|
|||
socket.on('search', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
search.find(data.terms).then((results) => { |
|||
cb(results); |
|||
}); |
|||
}); |
|||
|
|||
//-----------------------------------------
|
|||
// UPLOADS
|
|||
//-----------------------------------------
|
|||
|
|||
socket.on('uploadsSetFolders', (data) => { |
|||
if(internalAuth.validateKey(data.auth)) { |
|||
upl.setUploadsFolders(data.content); |
|||
} |
|||
}); |
|||
|
|||
socket.on('uploadsGetFolders', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
cb(upl.getUploadsFolders()); |
|||
}); |
|||
|
|||
socket.on('uploadsValidateFolder', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
if(internalAuth.validateKey(data.auth)) { |
|||
cb(upl.validateUploadsFolder(data.content)); |
|||
} |
|||
}); |
|||
|
|||
socket.on('uploadsCreateFolder', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
upl.createUploadsFolder(data.foldername).then((fldList) => { |
|||
cb(fldList); |
|||
}); |
|||
}); |
|||
|
|||
socket.on('uploadsSetFiles', (data) => { |
|||
if(internalAuth.validateKey(data.auth)) { |
|||
upl.setUploadsFiles(data.content); |
|||
} |
|||
}); |
|||
|
|||
socket.on('uploadsAddFiles', (data) => { |
|||
if(internalAuth.validateKey(data.auth)) { |
|||
upl.addUploadsFiles(data.content); |
|||
} |
|||
}); |
|||
|
|||
socket.on('uploadsGetImages', (data, cb) => { |
|||
cb = cb || _.noop; |
|||
cb(upl.getUploadsFiles('image', data.folder)); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
// ----------------------------------------
|
|||
// Shutdown gracefully
|
|||
// ----------------------------------------
|
|||
|
|||
process.on('disconnect', () => { |
|||
winston.warn('[WS] Lost connection to main server. Exiting... [' + moment().toISOString() + ']'); |
|||
server.close(); |
|||
process.exit(); |
|||
}); |
|||
|
|||
process.on('exit', () => { |
|||
server.stop(); |
|||
}); |
Write
Preview
Loading…
Cancel
Save