port most backend functionality, further cleanups, basic electron support
This commit is contained in:
parent
8dc48a84ba
commit
08b81d5ff4
189
app.js
189
app.js
@ -1,172 +1,33 @@
|
||||
"use strict";
|
||||
const spacedeck = require('./spacedeck')
|
||||
|
||||
const db = require('./models/db.js');
|
||||
require("log-timestamp");
|
||||
const electron = require('electron')
|
||||
const electronApp = electron.app
|
||||
const BrowserWindow = electron.BrowserWindow
|
||||
let mainWindow
|
||||
|
||||
const config = require('config');
|
||||
const redis = require('./helpers/redis');
|
||||
const websockets = require('./helpers/websockets');
|
||||
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
|
||||
const _ = require('underscore');
|
||||
const favicon = require('serve-favicon');
|
||||
const logger = require('morgan');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser');
|
||||
|
||||
//const mongoose = require('mongoose');
|
||||
|
||||
const swig = require('swig');
|
||||
const i18n = require('i18n-2');
|
||||
const helmet = require('helmet');
|
||||
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const serveStatic = require('serve-static');
|
||||
|
||||
const isProduction = app.get('env') === 'production';
|
||||
|
||||
console.log("Booting Spacedeck Open… (environment: " + app.get('env') + ")");
|
||||
|
||||
app.use(logger(isProduction ? 'combined' : 'dev'));
|
||||
|
||||
i18n.expressBind(app, {
|
||||
locales: ["en", "de", "fr"],
|
||||
defaultLocale: "en",
|
||||
cookieName: "spacedeck_locale",
|
||||
devMode: (app.get('env') == 'development')
|
||||
});
|
||||
|
||||
swig.setDefaults({
|
||||
varControls: ["[[", "]]"] // otherwise it's not compatible with vue.js
|
||||
});
|
||||
|
||||
swig.setFilter('cdn', function(input, idx) {
|
||||
return input;
|
||||
});
|
||||
|
||||
app.engine('html', swig.renderFile);
|
||||
app.set('view engine', 'html');
|
||||
|
||||
if (isProduction) {
|
||||
app.set('views', path.join(__dirname, 'build', 'views'));
|
||||
app.use(favicon(path.join(__dirname, 'build', 'assets', 'images', 'favicon.png')));
|
||||
app.use(express.static(path.join(__dirname, 'build', 'assets')));
|
||||
} else {
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.use(favicon(path.join(__dirname, 'public', 'images', 'favicon.png')));
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
function createWindow () {
|
||||
mainWindow = new BrowserWindow({width: 1200, height: 700})
|
||||
mainWindow.loadURL("http://localhost:9666")
|
||||
mainWindow.on('closed', function () {
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
app.use(bodyParser.json({
|
||||
limit: '50mb'
|
||||
}));
|
||||
electronApp.on('ready', createWindow)
|
||||
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: false,
|
||||
limit: '50mb'
|
||||
}));
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(helmet.frameguard())
|
||||
app.use(helmet.xssFilter())
|
||||
app.use(helmet.hsts({
|
||||
maxAge: 7776000000,
|
||||
includeSubdomains: true
|
||||
}))
|
||||
app.disable('x-powered-by');
|
||||
app.use(helmet.noSniff())
|
||||
|
||||
//app.use(require("./middlewares/error_helpers"));
|
||||
app.use(require("./middlewares/session"));
|
||||
//app.use(require("./middlewares/cors"));
|
||||
//app.use(require("./middlewares/i18n"));
|
||||
app.use("/api", require("./middlewares/api_helpers"));
|
||||
app.use('/api/spaces/:id', require("./middlewares/space_helpers"));
|
||||
app.use('/api/spaces/:id/artifacts/:artifact_id', require("./middlewares/artifact_helpers"));
|
||||
|
||||
app.use('/api/users', require('./routes/api/users'));
|
||||
app.use('/api/memberships', require('./routes/api/memberships'));
|
||||
|
||||
const spaceRouter = require('./routes/api/spaces');
|
||||
app.use('/api/spaces', spaceRouter);
|
||||
|
||||
spaceRouter.use('/:id/artifacts', require('./routes/api/space_artifacts'));
|
||||
spaceRouter.use('/:id/memberships', require('./routes/api/space_memberships'));
|
||||
spaceRouter.use('/:id/messages', require('./routes/api/space_messages'));
|
||||
spaceRouter.use('/:id/digest', require('./routes/api/space_digest'));
|
||||
spaceRouter.use('/:id', require('./routes/api/space_exports'));
|
||||
|
||||
app.use('/api/sessions', require('./routes/api/sessions'));
|
||||
//app.use('/api/webgrabber', require('./routes/api/webgrabber'));
|
||||
app.use('/', require('./routes/root'));
|
||||
|
||||
if (config.get('storage_local_path')) {
|
||||
app.use('/storage', serveStatic(config.get('storage_local_path')+"/"+config.get('storage_bucket'), {
|
||||
maxAge: 24*3600
|
||||
}));
|
||||
// Quit when all windows are closed.
|
||||
electronApp.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
electronApp.quit()
|
||||
}
|
||||
})
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
//app.use(require('./middlewares/404'));
|
||||
if (app.get('env') == 'development') {
|
||||
app.set('view cache', false);
|
||||
swig.setDefaults({cache: false});
|
||||
} else {
|
||||
app.use(require('./middlewares/500'));
|
||||
electronApp.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
|
||||
module.exports = app;
|
||||
|
||||
// CONNECT TO DATABASE
|
||||
db.init();
|
||||
|
||||
// START WEBSERVER
|
||||
const port = 9666;
|
||||
|
||||
const server = http.Server(app).listen(port, () => {
|
||||
|
||||
if ("send" in process) {
|
||||
process.send('online');
|
||||
}
|
||||
|
||||
}).on('listening', () => {
|
||||
|
||||
const host = server.address().address;
|
||||
const port = server.address().port;
|
||||
console.log('Spacedeck Open listening at http://%s:%s', host, port);
|
||||
|
||||
}).on('error', (error) => {
|
||||
|
||||
if (error.syscall !== 'listen') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
console.error(bind + ' requires elevated privileges');
|
||||
process.exit(1);
|
||||
break;
|
||||
case 'EADDRINUSE':
|
||||
console.error(bind + ' is already in use');
|
||||
process.exit(1);
|
||||
break;
|
||||
default:
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
//WEBSOCKETS & WORKER
|
||||
websockets.startWebsockets(server);
|
||||
redis.connectRedis();
|
||||
|
||||
process.on('message', (message) => {
|
||||
console.log("Process message:", message);
|
||||
if (message === 'shutdown') {
|
||||
console.log("Exiting Spacedeck.");
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var swig = require('swig');
|
||||
var AWS = require('aws-sdk');
|
||||
//var AWS = require('aws-sdk');
|
||||
|
||||
module.exports = {
|
||||
sendMail: (to_email, subject, body, options) => {
|
||||
@ -29,9 +29,9 @@ module.exports = {
|
||||
options: options
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
//if (process.env.NODE_ENV === 'development') {
|
||||
console.log("Email: to " + to_email + " in production.\nreply_to: " + reply_to + "\nsubject: " + subject + "\nbody: \n" + htmlText + "\n\n plaintext:\n" + plaintext);
|
||||
} else {
|
||||
/*} else {
|
||||
AWS.config.update({region: 'eu-west-1'});
|
||||
var ses = new AWS.SES();
|
||||
|
||||
@ -56,6 +56,6 @@ module.exports = {
|
||||
if (err) console.error("Error sending email:", err);
|
||||
else console.log("Email sent.");
|
||||
});
|
||||
}
|
||||
}*/
|
||||
}
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ const config = require('config');
|
||||
|
||||
const WebSocketServer = require('ws').Server;
|
||||
|
||||
const RedisConnection = require('ioredis');
|
||||
//const RedisConnection = require('ioredis');
|
||||
const async = require('async');
|
||||
const _ = require("underscore");
|
||||
const crypto = require('crypto');
|
||||
|
@ -10,8 +10,8 @@ module.exports = (req, res, next) => {
|
||||
req.i18n.setLocaleFromCookie();
|
||||
}
|
||||
|
||||
if (req.user && req.user.preferences.language) {
|
||||
req.i18n.setLocale(req.user.preferences.language);
|
||||
if (req.user && req.user.prefs_language) {
|
||||
req.i18n.setLocale(req.user.prefs_language);
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
47
models/db.js
47
models/db.js
@ -198,6 +198,48 @@ module.exports = {
|
||||
}),
|
||||
|
||||
init: function() {
|
||||
User = this.User;
|
||||
Session = this.Session;
|
||||
Space = this.Space;
|
||||
Artifact = this.Artifact;
|
||||
Message = this.Message;
|
||||
Membership = this.Membership;
|
||||
|
||||
Space.belongsTo(User, {
|
||||
foreignKey: {
|
||||
name: 'creator_id'
|
||||
},
|
||||
as: 'creator'
|
||||
});
|
||||
|
||||
Artifact.belongsTo(User, {
|
||||
foreignKey: {
|
||||
name: 'user_id'
|
||||
},
|
||||
as: 'user'
|
||||
});
|
||||
|
||||
Artifact.belongsTo(Space, {
|
||||
foreignKey: {
|
||||
name: 'space_id'
|
||||
},
|
||||
as: 'space'
|
||||
});
|
||||
|
||||
Message.belongsTo(User, {
|
||||
foreignKey: {
|
||||
name: 'user_id'
|
||||
},
|
||||
as: 'user'
|
||||
});
|
||||
|
||||
Message.belongsTo(Space, {
|
||||
foreignKey: {
|
||||
name: 'space_id'
|
||||
},
|
||||
as: 'space'
|
||||
});
|
||||
|
||||
sequelize.sync();
|
||||
},
|
||||
|
||||
@ -222,7 +264,6 @@ module.exports = {
|
||||
});
|
||||
} else {
|
||||
// reached the top
|
||||
|
||||
var role = prevRole;
|
||||
space.memberships = currentMemberships;
|
||||
|
||||
@ -252,10 +293,10 @@ module.exports = {
|
||||
},
|
||||
|
||||
findUserBySessionToken: (token, cb) => {
|
||||
db.Session.findOne({where: {token: token}})
|
||||
Session.findOne({where: {token: token}})
|
||||
.then(session => {
|
||||
if (!session) cb(null, null)
|
||||
else db.User.findOne({where: {_id: session.user_id}})
|
||||
else User.findOne({where: {_id: session.user_id}})
|
||||
.then(user => {
|
||||
cb(null, user)
|
||||
})
|
||||
|
48
package.json
48
package.json
@ -3,8 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "nodemon -e .js,.html bin/www",
|
||||
"test": "mocha"
|
||||
"start": "electron ."
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.8.0"
|
||||
@ -12,48 +11,26 @@
|
||||
"dependencies": {
|
||||
"archiver": "1.3.0",
|
||||
"async": "2.3.0",
|
||||
"aws-sdk": "2.39.0",
|
||||
"basic-auth": "1.1.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "~1.17.1",
|
||||
"cheerio": "0.22.0",
|
||||
"config": "1.25.1",
|
||||
"cookie-parser": "~1.4.3",
|
||||
"csurf": "1.9.0",
|
||||
"debug": "~2.6.3",
|
||||
"electron": "^1.8.4",
|
||||
"execSync": "latest",
|
||||
"express": "~4.13.0",
|
||||
"extract-zip": "^1.6.6",
|
||||
"file-type": "^7.6.0",
|
||||
"glob": "7.1.1",
|
||||
"gm": "1.23.0",
|
||||
"googleapis": "18.0.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-concat": "2.6.0",
|
||||
"gulp-express": "0.3.0",
|
||||
"gulp-nodemon": "*",
|
||||
"gulp-sass": "^2.0.3",
|
||||
"gulp-uglify": "^1.5.1",
|
||||
"gulp-util": "^3.0.6",
|
||||
"helmet": "^3.5.0",
|
||||
"i18n-2": "0.6.3",
|
||||
"ioredis": "2.5.0",
|
||||
"lodash": "^4.3.0",
|
||||
"log-timestamp": "latest",
|
||||
"md5": "2.2.1",
|
||||
"mime-types": "^2.1.18",
|
||||
"morgan": "1.8.1",
|
||||
"mock-aws-s3": "^2.6.0",
|
||||
"moment": "^2.19.3",
|
||||
"mongoose": "4.9.3",
|
||||
"morgan": "1.8.1",
|
||||
"node-phantom-simple": "2.2.4",
|
||||
"node-sass-middleware": "0.11.0",
|
||||
"pdfkit": "0.8.0",
|
||||
"phantomjs-prebuilt": "2.1.14",
|
||||
"pm2": "latest",
|
||||
"qr-image": "3.2.0",
|
||||
"raven": "1.2.0",
|
||||
"read-chunk": "^2.1.0",
|
||||
"request": "2.81.0",
|
||||
"sanitize-html": "^1.11.1",
|
||||
@ -66,29 +43,10 @@
|
||||
"underscore": "1.8.3",
|
||||
"uuid": "^3.2.1",
|
||||
"validator": "7.0.0",
|
||||
"weak": "1.0.1",
|
||||
"ws": "2.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"express": "^4.13.3",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-clean": "^0.3.2",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-express": "^0.3.0",
|
||||
"gulp-fingerprint": "^0.3.2",
|
||||
"gulp-nodemon": "^2.0.4",
|
||||
"gulp-rev": "^7.1.2",
|
||||
"gulp-rev-all": "^0.9.7",
|
||||
"gulp-rev-replace": "^0.4.3",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-uglify": "^2.1.2",
|
||||
"nodemon": "1.11.0",
|
||||
"should": "^11.2.1",
|
||||
"supertest": "^3.0.0",
|
||||
"winston": "^2.3.1"
|
||||
},
|
||||
"main": "app.js",
|
||||
"description": "",
|
||||
"main": "Gulpfile.js",
|
||||
"directories": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -13,18 +13,16 @@ SpacedeckAccount = {
|
||||
methods: {
|
||||
show_account: function(user) {
|
||||
this.activate_dropdown('account');
|
||||
this.load_subscription();
|
||||
this.load_billing();
|
||||
},
|
||||
|
||||
account_save_user_digest: function(val) {
|
||||
this.user.preferences.daily_digest = val;
|
||||
this.user.prefs_email_digest = val;
|
||||
this.save_user(function() {
|
||||
});
|
||||
},
|
||||
|
||||
account_save_user_notifications: function(val) {
|
||||
this.user.preferences.email_notifications = val;
|
||||
this.user.prefs_email_notifications = val;
|
||||
this.save_user(function() {
|
||||
});
|
||||
},
|
||||
|
@ -170,7 +170,6 @@ var SpacedeckRoutes = {
|
||||
location.href = "/";
|
||||
} else {
|
||||
this.active_view = "account";
|
||||
this.load_subscription();
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ function boot_spacedeck() {
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
document.addEventListener("DOMContentLoaded",function() {
|
||||
window.smoke = smoke;
|
||||
window.alert = smoke.alert;
|
||||
|
||||
|
@ -6,12 +6,10 @@ require('../../models/db');
|
||||
var async = require('async');
|
||||
var fs = require('fs');
|
||||
var _ = require("underscore");
|
||||
var mongoose = require("mongoose");
|
||||
var request = require('request');
|
||||
var url = require("url");
|
||||
var path = require("path");
|
||||
var crypto = require('crypto');
|
||||
var qr = require('qr-image');
|
||||
var glob = require('glob');
|
||||
var gm = require('gm');
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
var config = require('config');
|
||||
const db = require('../../models/db');
|
||||
|
||||
var redis = require('../../helpers/redis');
|
||||
var mailer = require('../../helpers/mailer');
|
||||
var uploader = require('../../helpers/uploader');
|
||||
var space_render = require('../../helpers/space-render');
|
||||
@ -12,13 +11,11 @@ var async = require('async');
|
||||
var moment = require('moment');
|
||||
var fs = require('fs');
|
||||
var _ = require("underscore");
|
||||
var mongoose = require("mongoose");
|
||||
var archiver = require('archiver');
|
||||
var request = require('request');
|
||||
var url = require("url");
|
||||
var path = require("path");
|
||||
var crypto = require('crypto');
|
||||
var qr = require('qr-image');
|
||||
var glob = require('glob');
|
||||
var gm = require('gm');
|
||||
var sanitizeHtml = require('sanitize-html');
|
||||
|
@ -14,7 +14,6 @@ var phantom = require('../../helpers/phantom');
|
||||
var async = require('async');
|
||||
var fs = require('fs');
|
||||
var _ = require("underscore");
|
||||
var mongoose = require("mongoose");
|
||||
var archiver = require('archiver');
|
||||
var request = require('request');
|
||||
var url = require("url");
|
||||
@ -52,8 +51,7 @@ var roleMapping = {
|
||||
router.get('/', function(req, res, next) {
|
||||
db.Message.findAll({where:{
|
||||
space_id: req.space._id
|
||||
}})
|
||||
//.populate('user', userMapping)
|
||||
}, include: ['user']})
|
||||
.then(function(messages) {
|
||||
res.status(200).json(messages);
|
||||
});
|
||||
@ -65,6 +63,7 @@ router.post('/', function(req, res, next) {
|
||||
|
||||
if (req.user) {
|
||||
attrs.user = req.user;
|
||||
attrs.user_id = req.user._id;
|
||||
} else {
|
||||
attrs.user = null;
|
||||
}
|
||||
@ -72,7 +71,7 @@ router.post('/', function(req, res, next) {
|
||||
var msg = attrs;
|
||||
msg._id = uuidv4();
|
||||
|
||||
db.Message.create(msg, function() {
|
||||
db.Message.create(msg).then(function() {
|
||||
if (msg.message.length <= 1) return;
|
||||
// TODO reimplement notifications
|
||||
res.distributeCreate("Message", msg);
|
||||
@ -82,19 +81,12 @@ router.post('/', function(req, res, next) {
|
||||
router.delete('/:message_id', function(req, res, next) {
|
||||
db.Message.findOne({where:{
|
||||
"_id": req.params.message_id
|
||||
}}, function(msg) {
|
||||
}}).then(function(msg) {
|
||||
if (!msg) {
|
||||
res.sendStatus(404);
|
||||
} else {
|
||||
msg.destroy(function(err) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
if (msg) {
|
||||
msg.destroy().then(function() {
|
||||
res.distributeDelete("Message", msg);
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -17,7 +17,6 @@ var slug = require('slug');
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
var _ = require("underscore");
|
||||
var mongoose = require("mongoose");
|
||||
var request = require('request');
|
||||
var url = require("url");
|
||||
var path = require("path");
|
||||
@ -67,6 +66,7 @@ router.get('/', function(req, res, next) {
|
||||
return m.space_id;
|
||||
});
|
||||
|
||||
// TODO port
|
||||
var q = {
|
||||
"space_type": "folder",
|
||||
"$or": [{
|
||||
@ -81,13 +81,11 @@ router.get('/', function(req, res, next) {
|
||||
}]
|
||||
};
|
||||
|
||||
Space
|
||||
.find(q)
|
||||
.populate('creator', userMapping)
|
||||
.exec(function(err, spaces) {
|
||||
if (err) console.error(err);
|
||||
db.Space
|
||||
.findAll({where: q})
|
||||
.then(function(spaces) {
|
||||
var updatedSpaces = spaces.map(function(s) {
|
||||
var spaceObj = s.toObject();
|
||||
var spaceObj = s; //.toObject();
|
||||
return spaceObj;
|
||||
});
|
||||
|
||||
@ -104,18 +102,17 @@ router.get('/', function(req, res, next) {
|
||||
return s.space_type == "folder";
|
||||
})
|
||||
var uniqueFolders = _.unique(onlyFolders, (s) => {
|
||||
return s._id.toString();
|
||||
return s._id;
|
||||
})
|
||||
|
||||
res.status(200).json(uniqueFolders);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (req.query.search) {
|
||||
|
||||
db.Membership.findAll({where:{
|
||||
user: req.user._id
|
||||
user_id: req.user._id
|
||||
}}).then(memberships => {
|
||||
|
||||
var validMemberships = memberships.filter(function(m) {
|
||||
@ -131,21 +128,15 @@ router.get('/', function(req, res, next) {
|
||||
|
||||
// TODO FIXME port
|
||||
var q = { where: {
|
||||
"$or": [{"creator_id": req.user._id},
|
||||
{"_id": {"$in": spaceIds}},
|
||||
{"parent_space_id": {"$in": spaceIds}}],
|
||||
name: new RegExp(req.query.search, "i")}
|
||||
};
|
||||
[Op.or]: [{"creator_id": req.user._id},
|
||||
{"_id": {[Op.in]: spaceIds}},
|
||||
{"parent_space_id": {[Op.in]: spaceIds}}],
|
||||
name: {[Op.like]: "%"+req.query.search+"%"}
|
||||
}, include: ['creator']};
|
||||
|
||||
db.Space
|
||||
.findAll(q)
|
||||
//.populate('creator', userMapping)
|
||||
.then(function(spaces) {
|
||||
if (err) console.error(err);
|
||||
var updatedSpaces = spaces.map(function(s) {
|
||||
var spaceObj = s.toObject();
|
||||
return spaceObj;
|
||||
});
|
||||
res.status(200).json(spaces);
|
||||
});
|
||||
});
|
||||
@ -170,8 +161,7 @@ router.get('/', function(req, res, next) {
|
||||
db.Space
|
||||
.findAll({where:{
|
||||
parent_space_id: req.query.parent_space_id
|
||||
}})
|
||||
//.populate('creator', userMapping)
|
||||
}, include:['creator']})
|
||||
.then(function(spaces) {
|
||||
res.status(200).json(spaces);
|
||||
});
|
||||
@ -214,7 +204,7 @@ router.get('/', function(req, res, next) {
|
||||
};
|
||||
|
||||
db.Space
|
||||
.findAll({where: q})
|
||||
.findAll({where: q, include: ['creator']})
|
||||
.then(function(spaces) {
|
||||
var updatedSpaces = spaces.map(function(s) {
|
||||
var spaceObj = db.spaceToObject(s);
|
||||
@ -414,15 +404,12 @@ router.delete('/:id', function(req, res, next) {
|
||||
|
||||
if (req.spaceRole == "admin") {
|
||||
const attrs = req.body;
|
||||
Space.recursiveDelete(space, function(err) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
space.destroy().then(function() {
|
||||
res.distributeDelete("Space", space);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(403).json({
|
||||
"error": "requires admin status"
|
||||
"error": "requires admin role"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
@ -74,14 +74,12 @@ router.post('/', function(req, res) {
|
||||
res.sendStatus(400);
|
||||
})
|
||||
.then(u => {
|
||||
console.log("!!! created user:", u);
|
||||
var homeSpace = {
|
||||
_id: uuidv4(),
|
||||
name: req.i18n.__("home"),
|
||||
space_type: "folder",
|
||||
creator_id: u._id
|
||||
};
|
||||
|
||||
db.Space.create(homeSpace)
|
||||
.error(err => {
|
||||
res.sendStatus(400);
|
||||
@ -109,8 +107,6 @@ router.post('/', function(req, res) {
|
||||
});
|
||||
};
|
||||
|
||||
console.log("!!! hello !!!");
|
||||
|
||||
db.User.findAll({where: {email: email}})
|
||||
.then(users => {
|
||||
if (users.length == 0) {
|
||||
@ -131,19 +127,15 @@ router.get('/current', function(req, res, next) {
|
||||
});
|
||||
|
||||
router.put('/:id', function(req, res, next) {
|
||||
// TODO explicit whitelisting
|
||||
var user = req.user;
|
||||
console.log(req.params.id, user._id);
|
||||
if (user._id == req.params.id) {
|
||||
var newAttr = req.body;
|
||||
newAttr.updated_at = new Date();
|
||||
delete newAttr['_id'];
|
||||
|
||||
User.findOneAndUpdate({"_id": user._id}, {"$set": newAttr}, function(err, updatedUser) {
|
||||
if (err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
res.status(200).json(updatedUser);
|
||||
}
|
||||
db.User.update(newAttr, {where: {"_id": user._id}}).then(function(updatedUser) {
|
||||
res.status(200).json(newAttr);
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
@ -161,12 +153,8 @@ router.post('/:id/password', function(req, res, next) {
|
||||
bcrypt.genSalt(10, function(err, salt) {
|
||||
bcrypt.hash(pass, salt, function(err, hash) {
|
||||
user.password_hash = hash;
|
||||
user.save(function(err){
|
||||
if(err){
|
||||
res.status(400).json(err);
|
||||
}else{
|
||||
user.save().then(function() {
|
||||
res.sendStatus(204);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -239,19 +227,15 @@ router.post('/:user_id/avatar', (req, res, next) => {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
user.avatar_thumb_uri = url;
|
||||
user.save((err, updatedUser) => {
|
||||
if (err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
user.save().then(() => {
|
||||
fs.unlink(localResizedFilePath, (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
res.status(200).json(updatedUser);
|
||||
res.status(200).json(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -269,32 +253,21 @@ router.post('/feedback', function(req, res, next) {
|
||||
|
||||
router.post('/password_reset_requests', (req, res, next) => {
|
||||
const email = req.query.email;
|
||||
User.findOne({"email": email}).exec((err, user) => {
|
||||
if (err) {
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
db.User.findOne({where: {"email": email}}).then((user) => {
|
||||
if (user) {
|
||||
if(user.account_type == "email") {
|
||||
crypto.randomBytes(16, (ex, buf) => {
|
||||
user.password_reset_token = buf.toString('hex');
|
||||
user.save((err, updatedUser) => {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
user.save().then(updatedUser => {
|
||||
mailer.sendMail(email, req.i18n.__("password_reset_subject"), req.i18n.__("password_reset_body"), {action: {
|
||||
link: config.endpoint + "/password-confirm/" + user.password_reset_token,
|
||||
name: req.i18n.__("password_reset_action")
|
||||
}});
|
||||
res.status(201).json({});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
res.status(404).json({"error": "error_unknown_email"});
|
||||
}
|
||||
} else {
|
||||
res.status(404).json({"error": "error_unknown_email"});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -302,11 +275,8 @@ router.post('/password_reset_requests/:confirm_token/confirm', function(req, res
|
||||
var password = req.body.password;
|
||||
|
||||
User
|
||||
.findOne({"password_reset_token": req.params.confirm_token})
|
||||
.exec((err, user) => {
|
||||
if (err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
.findOne({where: {"password_reset_token": req.params.confirm_token}})
|
||||
.then((user) => {
|
||||
if (user) {
|
||||
bcrypt.genSalt(10, (err, salt) => {
|
||||
bcrypt.hash(password, salt, function(err, hash) {
|
||||
@ -325,7 +295,6 @@ router.post('/password_reset_requests/:confirm_token/confirm', function(req, res
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -9,7 +9,6 @@ const crypto = require('crypto');
|
||||
const router = express.Router();
|
||||
const mailer = require('../helpers/mailer');
|
||||
const _ = require('underscore');
|
||||
const qr = require('qr-image');
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.render('index', { title: 'Spaces' });
|
||||
|
169
spacedeck.js
Normal file
169
spacedeck.js
Normal file
@ -0,0 +1,169 @@
|
||||
"use strict";
|
||||
|
||||
const db = require('./models/db.js');
|
||||
require("log-timestamp");
|
||||
|
||||
const config = require('config');
|
||||
const redis = require('./helpers/redis');
|
||||
const websockets = require('./helpers/websockets');
|
||||
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
|
||||
const _ = require('underscore');
|
||||
const favicon = require('serve-favicon');
|
||||
const logger = require('morgan');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser');
|
||||
|
||||
const swig = require('swig');
|
||||
const i18n = require('i18n-2');
|
||||
const helmet = require('helmet');
|
||||
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const serveStatic = require('serve-static');
|
||||
|
||||
const isProduction = app.get('env') === 'production';
|
||||
|
||||
console.log("Booting Spacedeck Open… (environment: " + app.get('env') + ")");
|
||||
|
||||
app.use(logger(isProduction ? 'combined' : 'dev'));
|
||||
|
||||
i18n.expressBind(app, {
|
||||
locales: ["en", "de", "fr"],
|
||||
defaultLocale: "en",
|
||||
cookieName: "spacedeck_locale",
|
||||
devMode: (app.get('env') == 'development')
|
||||
});
|
||||
|
||||
swig.setDefaults({
|
||||
varControls: ["[[", "]]"] // otherwise it's not compatible with vue.js
|
||||
});
|
||||
|
||||
swig.setFilter('cdn', function(input, idx) {
|
||||
return input;
|
||||
});
|
||||
|
||||
app.engine('html', swig.renderFile);
|
||||
app.set('view engine', 'html');
|
||||
|
||||
if (isProduction) {
|
||||
app.set('views', path.join(__dirname, 'build', 'views'));
|
||||
app.use(favicon(path.join(__dirname, 'build', 'assets', 'images', 'favicon.png')));
|
||||
app.use(express.static(path.join(__dirname, 'build', 'assets')));
|
||||
} else {
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.use(favicon(path.join(__dirname, 'public', 'images', 'favicon.png')));
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
}
|
||||
|
||||
app.use(bodyParser.json({
|
||||
limit: '50mb'
|
||||
}));
|
||||
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: false,
|
||||
limit: '50mb'
|
||||
}));
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(helmet.frameguard())
|
||||
app.use(helmet.xssFilter())
|
||||
app.use(helmet.hsts({
|
||||
maxAge: 7776000000,
|
||||
includeSubdomains: true
|
||||
}))
|
||||
app.disable('x-powered-by');
|
||||
app.use(helmet.noSniff())
|
||||
|
||||
//app.use(require("./middlewares/error_helpers"));
|
||||
app.use(require("./middlewares/session"));
|
||||
//app.use(require("./middlewares/cors"));
|
||||
app.use(require("./middlewares/i18n"));
|
||||
app.use("/api", require("./middlewares/api_helpers"));
|
||||
app.use('/api/spaces/:id', require("./middlewares/space_helpers"));
|
||||
app.use('/api/spaces/:id/artifacts/:artifact_id', require("./middlewares/artifact_helpers"));
|
||||
|
||||
app.use('/api/users', require('./routes/api/users'));
|
||||
app.use('/api/memberships', require('./routes/api/memberships'));
|
||||
|
||||
const spaceRouter = require('./routes/api/spaces');
|
||||
app.use('/api/spaces', spaceRouter);
|
||||
|
||||
spaceRouter.use('/:id/artifacts', require('./routes/api/space_artifacts'));
|
||||
spaceRouter.use('/:id/memberships', require('./routes/api/space_memberships'));
|
||||
spaceRouter.use('/:id/messages', require('./routes/api/space_messages'));
|
||||
spaceRouter.use('/:id/digest', require('./routes/api/space_digest'));
|
||||
spaceRouter.use('/:id', require('./routes/api/space_exports'));
|
||||
|
||||
app.use('/api/sessions', require('./routes/api/sessions'));
|
||||
//app.use('/api/webgrabber', require('./routes/api/webgrabber'));
|
||||
app.use('/', require('./routes/root'));
|
||||
|
||||
if (config.get('storage_local_path')) {
|
||||
app.use('/storage', serveStatic(config.get('storage_local_path')+"/"+config.get('storage_bucket'), {
|
||||
maxAge: 24*3600
|
||||
}));
|
||||
}
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
//app.use(require('./middlewares/404'));
|
||||
if (app.get('env') == 'development') {
|
||||
app.set('view cache', false);
|
||||
swig.setDefaults({cache: false});
|
||||
} else {
|
||||
app.use(require('./middlewares/500'));
|
||||
}
|
||||
|
||||
module.exports = app;
|
||||
|
||||
// CONNECT TO DATABASE
|
||||
db.init();
|
||||
|
||||
// START WEBSERVER
|
||||
const port = 9666;
|
||||
|
||||
const server = http.Server(app).listen(port, () => {
|
||||
|
||||
if ("send" in process) {
|
||||
process.send('online');
|
||||
}
|
||||
|
||||
}).on('listening', () => {
|
||||
|
||||
const host = server.address().address;
|
||||
const port = server.address().port;
|
||||
console.log('Spacedeck Open listening at http://%s:%s', host, port);
|
||||
|
||||
}).on('error', (error) => {
|
||||
|
||||
if (error.syscall !== 'listen') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
console.error(bind + ' requires elevated privileges');
|
||||
process.exit(1);
|
||||
break;
|
||||
case 'EADDRINUSE':
|
||||
console.error(bind + ' is already in use');
|
||||
process.exit(1);
|
||||
break;
|
||||
default:
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
websockets.startWebsockets(server);
|
||||
redis.connectRedis();
|
||||
|
||||
/*process.on('message', (message) => {
|
||||
console.log("Process message:", message);
|
||||
if (message === 'shutdown') {
|
||||
console.log("Exiting Spacedeck.");
|
||||
process.exit(0);
|
||||
}
|
||||
});*/
|
@ -86,15 +86,15 @@
|
||||
<div class="collapse" v-bind:class="{in:account=='language'}">
|
||||
<div class="modal-section">
|
||||
<label class="radio" v-bind:class="{checked
|
||||
: user.preferences.language=='en'}" v-on:click="save_user_language('en')">
|
||||
: user.prefs_language=='en'}" v-on:click="save_user_language('en')">
|
||||
<input type="radio" id="user-preferences_language" name="language" value="en"><span>English</span>
|
||||
</label>
|
||||
<hr/>
|
||||
<label class="radio" v-bind:class="{checked: user.preferences.language=='de'}" v-on:click="save_user_language('de')">
|
||||
<label class="radio" v-bind:class="{checked: user.prefs_language=='de'}" v-on:click="save_user_language('de')">
|
||||
<input type="radio" id="user-preferences_language" name="language" value="de"><span>Deutsch</span>
|
||||
</label>
|
||||
<hr/>
|
||||
<label class="radio" v-bind:class="{checked: user.preferences.language=='fr'}" v-on:click="save_user_language('fr')">
|
||||
<label class="radio" v-bind:class="{checked: user.prefs_language=='fr'}" v-on:click="save_user_language('fr')">
|
||||
<input type="radio" id="user-preferences_language" name="language" value="fr"><span>Français</span>
|
||||
</label>
|
||||
</div>
|
||||
@ -104,8 +104,8 @@
|
||||
<div class="modal-section labels-inline">
|
||||
<div class="form-group">
|
||||
<label class="checkbox"
|
||||
v-bind:class="{checked: user.preferences.email_notifications}"
|
||||
v-on:click="account_save_user_notifications(!user.preferences.email_notifications);">
|
||||
v-bind:class="{checked: user.prefs_email_notifications}"
|
||||
v-on:click="account_save_user_notifications(!user.prefs_email_notifications);">
|
||||
<span>[[__('notifications_option_chat')]]</span>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -77,19 +77,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mobile-dialog" class="dropdown bottom light center static" v-bind:class="{open:opened_dialog=='mobile'}">
|
||||
<div class="btn-collapse in">
|
||||
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='mobile'}" v-on:click="open_dialog('mobile')" >
|
||||
<span class="icon icon-device-mobile"></span>
|
||||
<span class="icon-label">[[__("mobile")]]</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dialog mobile-search">
|
||||
{% include "./pick-mobile.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-divider" v-show="logged_in"></button>
|
||||
|
||||
<div class="dropdown bottom light center" v-show="logged_in" v-bind:class="{open:opened_dialog=='background'}">
|
||||
|
@ -13,6 +13,8 @@
|
||||
<link type="text/css" rel="stylesheet" href="https://fast.fonts.net/cssapi/ee1a3484-4d98-4f9f-9f55-020a7b37f3c5.css"/>
|
||||
<link rel="stylesheet" href="[[ '/stylesheets/style.css' | cdn ]]">
|
||||
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twemoji/1.3.2/twemoji.min.js"></script>
|
||||
|
||||
<script>
|
||||
@ -83,6 +85,8 @@
|
||||
<script minify src="/javascripts/spacedeck_directives.js"></script>
|
||||
<script minify src="/javascripts/spacedeck_vue.js"></script>
|
||||
{% endif %}
|
||||
|
||||
<script>if (window.module) module = window.module;</script>
|
||||
</head>
|
||||
|
||||
<body id="main" v-bind:class="{'present-mode':present_mode,'modal-open':active_modal}" v-on:click="handle_body_click($event)">
|
||||
|
Loading…
Reference in New Issue
Block a user