Unverified Commit ebac854d authored by mntmn's avatar mntmn Committed by GitHub
Browse files

Port Backend to SQLite/Sequelize (removes MongoDB), Support Electron (#14)

* The MongoDB/Mongoose data storage is removed in favor of Sequelize. This abstracts over SQLite or RDBMs like PostgreSQL and MSSQL. The default is SQLite, which significantly simplifies deployments in end-user environments.

* As Spacedeck now has no more mandatory server dependencies, we can wrap it in Electron and ship it as a desktop application.

* Removes docker-compose.yml

* First version of import UI
parent 8e0bc69a
Showing with 684 additions and 1288 deletions
+684 -1288
...@@ -21,7 +21,7 @@ function vec2_angle(v) { ...@@ -21,7 +21,7 @@ function vec2_angle(v) {
} }
function render_vector_drawing(a, padding) { function render_vector_drawing(a, padding) {
var shape = a.style.shape || ""; var shape = a.shape || "";
var path = []; var path = [];
var p = a.control_points[0]; var p = a.control_points[0];
...@@ -48,8 +48,8 @@ function render_vector_drawing(a, padding) { ...@@ -48,8 +48,8 @@ function render_vector_drawing(a, padding) {
var d = "M" + (cps.dx + padding) + "," + (cps.dy + padding) + " Q" + (scaledMiddlePoint.dx + padding) + "," + (scaledMiddlePoint.dy + padding) + " " + (cpe.dx + padding) + "," + (cpe.dy + padding); var d = "M" + (cps.dx + padding) + "," + (cps.dy + padding) + " Q" + (scaledMiddlePoint.dx + padding) + "," + (scaledMiddlePoint.dy + padding) + " " + (cpe.dx + padding) + "," + (cpe.dy + padding);
var tip = "<defs><marker id='ae" + markerId + "' refX=\"0.1\" refY=\"3\" markerWidth=\"3\" markerHeight=\"6\" orient=\"auto\">"; var tip = "<defs><marker id='ae" + markerId + "' refX=\"0.1\" refY=\"3\" markerWidth=\"3\" markerHeight=\"6\" orient=\"auto\">";
tip += "<path d=\"M-3,0 V6 L3,3 Z\" fill=\""+a.style.stroke_color+"\" stroke-width=\"0\"/></marker></defs>"; tip += "<path d=\"M-3,0 V6 L3,3 Z\" fill=\""+a.stroke_color+"\" stroke-width=\"0\"/></marker></defs>";
var svg = tip + "<path d='" + d + "' style='stroke-width:" + a.style.stroke + ";' marker-end='url(#ae" + markerId + ")'/>"; var svg = tip + "<path d='" + d + "' style='stroke-width:" + a.stroke + ";' marker-end='url(#ae" + markerId + ")'/>";
return svg; return svg;
} }
...@@ -237,11 +237,11 @@ function render_vector_rect(xradius,yradius,offset) { ...@@ -237,11 +237,11 @@ function render_vector_rect(xradius,yradius,offset) {
} }
function render_vector_shape(a) { function render_vector_shape(a) {
var stroke = parseInt(a.style.stroke) + 4; var stroke = parseInt(a.stroke) + 4;
var offset = stroke / 2; var offset = stroke / 2;
var xr = (a.board.w-stroke) / 2; var xr = (a.w-stroke) / 2;
var yr = (a.board.h-stroke) / 2; var yr = (a.h-stroke) / 2;
var shape_renderers = { var shape_renderers = {
ellipse: function() { return render_vector_ellipse(xr, yr, offset); }, ellipse: function() { return render_vector_ellipse(xr, yr, offset); },
...@@ -258,7 +258,7 @@ function render_vector_shape(a) { ...@@ -258,7 +258,7 @@ function render_vector_shape(a) {
cloud: function() { return render_vector_cloud(xr, yr, offset); }, cloud: function() { return render_vector_cloud(xr, yr, offset); },
} }
var render_func = shape_renderers[a.style.shape]; var render_func = shape_renderers[a.shape];
if (!render_func) return ""; if (!render_func) return "";
......
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema');
var fs = require('fs');
var _ = require("underscore");
var mongoose = require("mongoose");
var async = require('async'); var async = require('async');
var archiver = require('archiver');
var request = require('request');
var url = require("url"); var url = require("url");
var path = require("path"); var path = require("path");
var crypto = require('crypto'); var crypto = require('crypto');
var qr = require('qr-image');
var glob = require('glob'); var glob = require('glob');
var gm = require('gm');
var express = require('express'); var express = require('express');
var router = express.Router(); var router = express.Router();
var userMapping = { '_id': 1, 'nickname': 1, 'email': 1}; const db = require('../../models/db');
var spaceMapping = { '_id': 1, name: 1}; const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const uuidv4 = require('uuid/v4');
router.get('/:membership_id/accept', function(req, res, next) { router.get('/:membership_id/accept', function(req, res, next) {
if (req.user) { if (req.user) {
Membership.findOne({ db.Membership.findOne({where:{
_id: req.params.membership_id, _id: req.params.membership_id,
state: "pending", code: req.query.code
code: req.query.code, }, include: ['space']}).then((mem) => {
user: { "$exists": false } if (mem) {
}).populate('space').exec((err,mem) => { if (!mem.user) {
if (err) res.sendStatus(400); mem.state = "active";
else { mem.user_id = req.user._id;
if (mem) {
if(!mem.user) { mem.save().then(function() {
mem.code = null; res.status(200).json(mem);
mem.state = "active"; });
mem.user = req.user;
mem.save(function(err){
if (err) res.status(400).json(err);
else {
console.log(mem);
res.status(200).json(mem);
}
});
} else {
res.status(400).json({"error": "already_used"});
}
} else { } else {
res.status(404).json({"error": "not found"}); res.status(200).json(mem);
} }
} else {
res.status(404).json({"error": "not found"});
} }
}); });
} else { } else {
......
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema'); const db = require('../../models/db');
var bcrypt = require('bcryptjs'); var bcrypt = require('bcryptjs');
var crypo = require('crypto'); var crypto = require('crypto');
var URL = require('url').URL; var URL = require('url').URL;
var express = require('express'); var express = require('express');
...@@ -12,68 +12,64 @@ var router = express.Router(); ...@@ -12,68 +12,64 @@ var router = express.Router();
router.post('/', function(req, res) { router.post('/', function(req, res) {
var data = req.body; var data = req.body;
if (data.email && data.password) { if (!data.email || !data.password) {
var email = req.body.email.toLowerCase(); res.status(400).json({});
var password = req.body["password"]; return;
}
User.find({email: email, account_type: "email"}, (function (err, users) {
if (err) { var email = req.body.email.toLowerCase();
res.status(400).json({"error":"session.users"}); var password = req.body["password"];
} else {
if (users.length == 1) {
var user = users[0];
if (bcrypt.compareSync(password, user.password_hash)) {
crypo.randomBytes(48, function(ex, buf) {
var token = buf.toString('hex');
var session = {
token: token,
ip: req.ip,
device: "web",
created_at: new Date()
};
if (!user.sessions)
user.sessions = [];
user.sessions.push(session); db.User.findOne({where: {email: email}})
.error(err => {
res.sendStatus(404);
//res.status(400).json({"error":"session.users"});
})
.then(user => {
console.log("!!! user: ",user.password_hash);
if (bcrypt.compareSync(password, user.password_hash)) {
crypto.randomBytes(48, function(ex, buf) {
var token = buf.toString('hex');
console.log("!!! token: ",token);
user.save(function(err, result) { var session = {
if (err) console.error("Error saving user:",err); user_id: user._id,
token: token,
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : "localhost"; ip: req.ip,
device: "web",
created_at: new Date()
};
res.cookie('sdsession', token, { domain: domain, httpOnly: true }); db.Session.create(session)
res.status(201).json(session); .error(err => {
}); console.error("Error creating Session:",err);
res.sendStatus(500);
})
.then(() => {
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : "localhost";
res.cookie('sdsession', token, { domain: domain, httpOnly: true });
res.status(201).json(session);
}); });
}else{ });
res.sendStatus(403); } else {
} res.sendStatus(403);
} else {
res.sendStatus(404);
}
} }
})); });
} else {
res.status(400).json({});
}
}); });
router.delete('/current', function(req, res, next) { router.delete('/current', function(req, res, next) {
if (req.user) { if (req.user) {
var user = req.user; /*var user = req.user;
var newSessions = user.sessions.filter( function(session){ var newSessions = user.sessions.filter( function(session){
return session.token != req.token; return session.token != req.token;
}); });*/
user.sessions = newSessions; //user.sessions = newSessions;
user.save(function(err, result) { //user.save(function(err, result) {
var domain = new URL(config.get('endpoint')).hostname; var domain = new URL(config.get('endpoint')).hostname;
res.clearCookie('sdsession', { domain: domain }); res.clearCookie('sdsession', { domain: domain });
res.sendStatus(204); res.sendStatus(204);
}); //});
} else { } else {
res.sendStatus(404); res.sendStatus(404);
} }
......
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema');
const os = require('os');
const db = require('../../models/db');
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const uuidv4 = require('uuid/v4');
var payloadConverter = require('../../helpers/artifact_converter'); var payloadConverter = require('../../helpers/artifact_converter');
var redis = require('../../helpers/redis'); var redis = require('../../helpers/redis');
...@@ -9,13 +14,11 @@ var redis = require('../../helpers/redis'); ...@@ -9,13 +14,11 @@ var redis = require('../../helpers/redis');
var async = require('async'); var async = require('async');
var fs = require('fs'); var fs = require('fs');
var _ = require("underscore"); var _ = require("underscore");
var mongoose = require("mongoose");
var archiver = require('archiver'); var archiver = require('archiver');
var request = require('request'); var request = require('request');
var url = require("url"); var url = require("url");
var path = require("path"); var path = require("path");
var crypto = require('crypto'); var crypto = require('crypto');
var qr = require('qr-image');
var glob = require('glob'); var glob = require('glob');
var gm = require('gm'); var gm = require('gm');
...@@ -46,15 +49,24 @@ var roleMapping = { ...@@ -46,15 +49,24 @@ var roleMapping = {
// ARTIFACTS // ARTIFACTS
router.get('/', (req, res) => { router.get('/', (req, res) => {
Artifact.find({ db.Artifact.findAll({where: {
space_id: req.space._id space_id: req.space._id
}).exec((err, artifacts) => { }}).then(artifacts => {
async.map(artifacts, (a, cb) => { async.map(artifacts, (a, cb) => {
a = a.toObject(); //a = a.toObject(); TODO
if (a.control_points) {
a.control_points = JSON.parse(a.control_points);
}
if (a.payload_alternatives) {
a.payload_alternatives = JSON.parse(a.payload_alternatives);
}
if (a.user_id) { if (a.user_id) {
User.findOne({ // FIXME JOIN
/*User.findOne({where: {
"_id": a.user_id "_id": a.user_id
}).select({ }}).select({
"_id": 1, "_id": 1,
"nickname": 1, "nickname": 1,
"email": 1 "email": 1
...@@ -63,7 +75,8 @@ router.get('/', (req, res) => { ...@@ -63,7 +75,8 @@ router.get('/', (req, res) => {
a['user'] = user.toObject(); a['user'] = user.toObject();
} }
cb(err, a); cb(err, a);
}); });*/
cb(null, a);
} else { } else {
cb(null, a); cb(null, a);
} }
...@@ -81,9 +94,8 @@ router.post('/', function(req, res, next) { ...@@ -81,9 +94,8 @@ router.post('/', function(req, res, next) {
attrs['space_id'] = req.space._id; attrs['space_id'] = req.space._id;
var artifact = new Artifact(attrs); var artifact = attrs;
artifact._id = uuidv4();
artifact.created_from_ip = req['real_ip'];
if (req.user) { if (req.user) {
artifact.user_id = req.user._id; artifact.user_id = req.user._id;
...@@ -92,23 +104,18 @@ router.post('/', function(req, res, next) { ...@@ -92,23 +104,18 @@ router.post('/', function(req, res, next) {
artifact.last_update_editor_name = req.editor_name; artifact.last_update_editor_name = req.editor_name;
} }
if (req.spaceRole == "editor"  ||  req.spaceRole == "admin") { db.packArtifact(artifact);
artifact.save(function(err) {
if (err) res.status(400).json(err); if (req.spaceRole == "editor" || req.spaceRole == "admin") {
else { db.Artifact.create(artifact).then(() => {
Space.update({ //if (err) res.status(400).json(err);
_id: req.space._id db.unpackArtifact(artifact);
}, { db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id}});
"$set": { res.distributeCreate("Artifact", artifact);
updated_at: new Date()
}
});
res.distributeCreate("Artifact", artifact);
}
}); });
} else { } else {
res.status(401).json({ res.status(401).json({
"error": "no access" "error": "Access denied"
}); });
} }
}); });
...@@ -118,7 +125,8 @@ router.post('/:artifact_id/payload', function(req, res, next) { ...@@ -118,7 +125,8 @@ router.post('/:artifact_id/payload', function(req, res, next) {
var a = req.artifact; var a = req.artifact;
var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9_\-\.]/g, ''); var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9_\-\.]/g, '');
var localFilePath = "/tmp/" + fileName;
var localFilePath = os.tmpdir() + "/" + fileName;
var writeStream = fs.createWriteStream(localFilePath); var writeStream = fs.createWriteStream(localFilePath);
var stream = req.pipe(writeStream); var stream = req.pipe(writeStream);
...@@ -132,13 +140,7 @@ router.post('/:artifact_id/payload', function(req, res, next) { ...@@ -132,13 +140,7 @@ router.post('/:artifact_id/payload', function(req, res, next) {
payloadConverter.convert(a, fileName, localFilePath, function(error, artifact) { payloadConverter.convert(a, fileName, localFilePath, function(error, artifact) {
if (error) res.status(400).json(error); if (error) res.status(400).json(error);
else { else {
Space.update({ db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id}});
_id: req.space._id
}, {
"$set": {
updated_at: new Date()
}
});
res.distributeUpdate("Artifact", artifact); res.distributeUpdate("Artifact", artifact);
} }
}, progress_callback); }, progress_callback);
...@@ -161,42 +163,23 @@ router.put('/:artifact_id', function(req, res, next) { ...@@ -161,42 +163,23 @@ router.put('/:artifact_id', function(req, res, next) {
} else { } else {
newAttr.last_update_editor_name = req.editor_name; newAttr.last_update_editor_name = req.editor_name;
} }
db.packArtifact(newAttr);
Artifact.findOneAndUpdate({ db.Artifact.update(newAttr, { where: {
"_id": a._id "_id": a._id
}, { }}).then(rows => {
"$set": newAttr db.unpackArtifact(newAttr);
}, { db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id} });
"new": true res.distributeUpdate("Artifact", newAttr);
}, function(err, artifact) {
if (err) res.status(400).json(err);
else {
Space.update({
_id: req.space._id
}, {
"$set": {
updated_at: new Date()
}
});
res.distributeUpdate("Artifact", artifact);
}
}); });
}); });
router.delete('/:artifact_id', function(req, res, next) { router.delete('/:artifact_id', function(req, res, next) {
var artifact = req.artifact; var artifact = req.artifact;
artifact.remove(function(err) { db.Artifact.destroy({where: { "_id": artifact._id}}).then(() => {
if (err) res.status(400).json(err); db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id} });
else { res.distributeDelete("Artifact", artifact);
Space.update({
_id: req.space._id
}, {
"$set": {
updated_at: new Date()
}
});
res.distributeDelete("Artifact", artifact);
}
}); });
}); });
......
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema'); require('../../models/db');
var async = require('async'); var async = require('async');
var fs = require('fs'); var fs = require('fs');
var _ = require("underscore"); var _ = require("underscore");
var mongoose = require("mongoose");
var request = require('request'); var request = require('request');
var url = require("url"); var url = require("url");
var path = require("path"); var path = require("path");
var crypto = require('crypto'); var crypto = require('crypto');
var qr = require('qr-image');
var glob = require('glob'); var glob = require('glob');
var gm = require('gm'); var gm = require('gm');
...@@ -40,6 +38,12 @@ var roleMapping = { ...@@ -40,6 +38,12 @@ var roleMapping = {
}; };
router.get('/', function(req, res, next) { router.get('/', function(req, res, next) {
res.status(200).json([]);
return;
// FIXME TODO
var showActionForSpaces = function(err, spaceIds) { var showActionForSpaces = function(err, spaceIds) {
var userMapping = { var userMapping = {
'_id': 1, '_id': 1,
......
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema'); const db = require('../../models/db');
var redis = require('../../helpers/redis');
var mailer = require('../../helpers/mailer'); var mailer = require('../../helpers/mailer');
var uploader = require('../../helpers/uploader'); var uploader = require('../../helpers/uploader');
var space_render = require('../../helpers/space-render'); var space_render = require('../../helpers/space-render');
...@@ -12,13 +11,11 @@ var async = require('async'); ...@@ -12,13 +11,11 @@ var async = require('async');
var moment = require('moment'); var moment = require('moment');
var fs = require('fs'); var fs = require('fs');
var _ = require("underscore"); var _ = require("underscore");
var mongoose = require("mongoose");
var archiver = require('archiver'); var archiver = require('archiver');
var request = require('request'); var request = require('request');
var url = require("url"); var url = require("url");
var path = require("path"); var path = require("path");
var crypto = require('crypto'); var crypto = require('crypto');
var qr = require('qr-image');
var glob = require('glob'); var glob = require('glob');
var gm = require('gm'); var gm = require('gm');
var sanitizeHtml = require('sanitize-html'); var sanitizeHtml = require('sanitize-html');
...@@ -49,26 +46,18 @@ var roleMapping = { ...@@ -49,26 +46,18 @@ var roleMapping = {
router.get('/png', function(req, res, next) { router.get('/png', function(req, res, next) {
var triggered = new Date(); var triggered = new Date();
var s3_filename = "s" + req.space._id + "/" + "thumb_" + triggered.getTime() + ".jpg"; var s3_filename = "s" + req.space._id + "/" + "thumb_" + triggered.getTime() + ".jpg";
if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) { if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) {
db.Space.update({ thumbnail_updated_at: triggered }, {where : {"_id": req.space._id }});
Space.update({
"_id": req.space._id
}, {
"$set": {
thumbnail_updated_at: triggered
}
}, function(a, b, c) {});
phantom.takeScreenshot(req.space, "png", phantom.takeScreenshot(req.space, "png",
function(local_path) { function(local_path) {
var localResizedFilePath = local_path + ".thumb.jpg"; var localResizedFilePath = local_path + ".thumb.jpg";
gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) { gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) {
if (err) { if (err) {
console.error("screenshot resize error: ", err); console.error("[space screenshot] resize error: ", err);
res.status(500).send("Error taking screenshot."); res.status(500).send("Error taking screenshot.");
return; return;
} }
...@@ -76,22 +65,15 @@ router.get('/png', function(req, res, next) { ...@@ -76,22 +65,15 @@ router.get('/png', function(req, res, next) {
uploader.uploadFile(s3_filename, "image/jpeg", localResizedFilePath, function(err, thumbnailUrl) { uploader.uploadFile(s3_filename, "image/jpeg", localResizedFilePath, function(err, thumbnailUrl) {
if (err) { if (err) {
console.error("screenshot s3 upload error. filename: " + s3_filename + " details: ", err); console.error("[space screenshot] upload error. filename: " + s3_filename + " details: ", err);
res.status(500).send("Error uploading screenshot."); res.status(500).send("Error uploading screenshot.");
return; return;
} }
var oldUrl = req.space.thumbnail_url; var oldUrl = req.space.thumbnail_url;
Space.update({ db.Space.update({ thumbnail_url: thumbnailUrl }, {where : {"_id": req.space._id }}).then(() => {
"_id": req.space._id
}, {
"$set": {
thumbnail_url: thumbnailUrl
}
}, function(a, b, c) {
res.redirect(thumbnailUrl); res.redirect(thumbnailUrl);
try { try {
if (oldUrl) { if (oldUrl) {
var oldPath = url.parse(oldUrl).pathname; var oldPath = url.parse(oldUrl).pathname;
...@@ -125,77 +107,6 @@ function make_export_filename(space, extension) { ...@@ -125,77 +107,6 @@ function make_export_filename(space, extension) {
return space.name.replace(/[^\w]/g, '') + "-" + space._id + "-" + moment().format("YYYYMMDD-HH-mm-ss") + "." + extension; return space.name.replace(/[^\w]/g, '') + "-" + space._id + "-" + moment().format("YYYYMMDD-HH-mm-ss") + "." + extension;
} }
router.get('/list', function(req, res, next) {
if (req.user) {
if (req.spaceRole == "admin" ||  req.spaceRole == "editor") {
if (req.space.space_type == "space") {
Artifact.find({
space_id: req.space._id
}).exec(function(err, artifacts) {
async.map(artifacts, function(a, cb) {
if (a.user_id) {
User.findOne({
"_id": a.user_id
}).exec(function(err, user) {
a.user = user;
if (a.last_update_user_id) {
User.findOne({
"_id": a.last_update_user_id
}).exec(function(err, updateUser) {
a.update_user = updateUser;
cb(null, a);
});
} else {
cb(null, a);
}
});
} else {
cb(null, a);
}
}, function(err, mappedArtifacts) {
req.space.artifacts = mappedArtifacts.map(function(a) {
a.description = sanitizeHtml(a.description, {
allowedTags: [],
allowedAttributes: []
});
if (a.payload_uri) {
var parsed = url.parse(a.payload_uri);
var fileName = path.basename(parsed.pathname) || "file.bin";
a.filename = fileName;
}
return a;
});
res.render('artifact_list', {
space: req.space
});
});
});
} else {
Space.getRecursiveSubspacesForSpace(req.space, (err, subspaces) => {
res.render('space_list', {
subspaces: subspaces.map((s) => {
s.ae_link = config.endpoint + '/s/' + s.edit_hash + (s.edit_slug ? ('-'+s.edit_slug) : '')
return s;
}),
space: req.space
});
});
}
} else {
res.sendStatus(403);
}
} else {
res.sendStatus(403);
}
});
router.get('/pdf', function(req, res, next) { router.get('/pdf', function(req, res, next) {
var s3_filename = make_export_filename(req.space, "pdf"); var s3_filename = make_export_filename(req.space, "pdf");
...@@ -329,36 +240,14 @@ router.get('/zip', function(req, res, next) { ...@@ -329,36 +240,14 @@ router.get('/zip', function(req, res, next) {
}); });
router.get('/html', function(req, res) { router.get('/html', function(req, res) {
Artifact.find({ console.log("!!!!! hello ");
db.Artifact.findAll({where: {
space_id: req.space._id space_id: req.space._id
}, function(err, artifacts) { }}).then(function(artifacts) {
var space = req.space; var space = req.space;
res.send(space_render.render_space_as_html(space, artifacts)); res.send(space_render.render_space_as_html(space, artifacts));
}); });
}); });
router.get('/path', (req, res) => {
// build up a breadcrumb trail (path)
var path = [];
var buildPath = (space) => {
if (space.parent_space_id) {
Space.findOne({
"_id": space.parent_space_id
}, (err, parentSpace) => {
if (space._id == parentSpace._id) {
console.log("error: circular parent reference for space " + space._id);
res.send("error: circular reference");
} else {
path.push(parentSpace);
buildPath(parentSpace);
}
});
} else {
// reached the top
res.json(path.reverse());
}
}
buildPath(req.space);
});
module.exports = router; module.exports = router;
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema'); const db = require('../../models/db');
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const uuidv4 = require('uuid/v4');
var redis = require('../../helpers/redis'); var redis = require('../../helpers/redis');
var mailer = require('../../helpers/mailer'); var mailer = require('../../helpers/mailer');
var uploader = require('../../helpers/uploader');
var space_render = require('../../helpers/space-render');
var phantom = require('../../helpers/phantom');
var async = require('async'); var async = require('async');
var fs = require('fs'); var fs = require('fs');
var _ = require("underscore"); var _ = require("underscore");
var mongoose = require("mongoose");
var archiver = require('archiver');
var request = require('request'); var request = require('request');
var url = require("url"); var url = require("url");
var path = require("path"); var path = require("path");
var crypto = require('crypto');
var qr = require('qr-image');
var glob = require('glob'); var glob = require('glob');
var gm = require('gm'); var crypto = require('crypto');
var express = require('express'); var express = require('express');
var router = express.Router({mergeParams: true}); var router = express.Router({mergeParams: true});
// JSON MAPPINGS
var userMapping = {
_id: 1,
nickname: 1,
email: 1,
avatar_thumb_uri: 1
};
var spaceMapping = {
_id: 1,
name: 1,
thumbnail_url: 1
};
var roleMapping = {
"none": 0,
"viewer": 1,
"editor": 2,
"admin": 3
}
router.get('/', function(req, res, next) { router.get('/', function(req, res, next) {
Membership db.Membership
.find({ .findAll({where: {
space: req.space._id space_id: req.space._id
}) }, include: ['user']})
.populate("user") .then(memberships => {
.exec(function(err, memberships) {
res.status(200).json(memberships); res.status(200).json(memberships);
}); });
}); });
...@@ -59,52 +33,51 @@ router.get('/', function(req, res, next) { ...@@ -59,52 +33,51 @@ router.get('/', function(req, res, next) {
router.post('/', function(req, res, next) { router.post('/', function(req, res, next) {
if (req.spaceRole == "admin") { if (req.spaceRole == "admin") {
var attrs = req.body; var attrs = req.body;
attrs['space'] = req.space._id; attrs.space_id = req.space._id;
attrs['state'] = "pending"; attrs.state = "pending";
var membership = new Membership(attrs); attrs._id = uuidv4();
var membership = attrs;
var msg = attrs.personal_message; var msg = attrs.personal_message;
if (membership.email_invited != req.user.email) { if (membership.email_invited != req.user.email) {
User.findOne({ db.User.findOne({where:{
"email": membership.email_invited "email": membership.email_invited
}, function(err, user) { }}).then(function(user) {
if (user) { if (user) {
membership.user = user; membership.user_id = user._id;
membership.state = "active"; membership.state = "active";
} else { } else {
membership.code = crypto.randomBytes(64).toString('hex').substring(0, 12); membership.code = crypto.randomBytes(64).toString('hex').substring(0, 12);
} }
membership.save(function(err) { db.Membership.create(membership).then(function() {
if (err) res.sendStatus(400); var accept_link = config.endpoint + "/accept/" + membership._id + "?code=" + membership.code;
else {
var accept_link = config.endpoint + "/accept/" + membership._id + "?code=" + membership.code; if (user) {
accept_link = config.endpoint + "/" + req.space.space_type + "s/" + req.space._id;
if (user) {
accept_link = config.endpoint + "/" + req.space.space_type + "s/" + req.space._id;
}
var openText = req.i18n.__("space_invite_membership_action");
if (user) {
req.i18n.__("open");
}
const name = req.user.nickname || req.user.email
const subject = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_subject", name, req.space.name) : req.i18n.__("folder_invite_membership_subject", req.user.nickname, req.space.name)
const body = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_body", name, req.space.name) : req.i18n.__("folder_invite_membership_body", req.user.nickname, req.space.name)
mailer.sendMail(
membership.email_invited, subject, body, {
messsage: msg,
action: {
link: accept_link,
name: openText
}
});
res.status(201).json(membership);
} }
var openText = req.i18n.__("space_invite_membership_action");
if (user) {
req.i18n.__("open");
}
const name = req.user.nickname || req.user.email
const subject = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_subject", name, req.space.name) : req.i18n.__("folder_invite_membership_subject", req.user.nickname, req.space.name)
const body = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_body", name, req.space.name) : req.i18n.__("folder_invite_membership_body", req.user.nickname, req.space.name)
mailer.sendMail(
membership.email_invited, subject, body, {
messsage: msg,
action: {
link: accept_link,
name: openText
}
});
res.status(201).json(membership);
}); });
}); });
...@@ -125,21 +98,15 @@ router.post('/', function(req, res, next) { ...@@ -125,21 +98,15 @@ router.post('/', function(req, res, next) {
router.put('/:membership_id', function(req, res, next) { router.put('/:membership_id', function(req, res, next) {
if (req.user) { if (req.user) {
if (req.spaceRole == "admin") { if (req.spaceRole == "admin") {
Membership.findOne({ db.Membership.findOne({ where: {
_id: req.params.membership_id _id: req.params.membership_id
}, function(err, mem) { }}).then(function(mem) {
if (err) res.sendStatus(400); if (mem) {
else { var attrs = req.body;
if (mem) { mem.role = attrs.role;
var attrs = req.body; mem.save(function() {
mem.role = attrs.role; res.status(201).json(mem);
mem.save(function(err) { });
if (err) res.sendStatus(400);
else {
res.status(201).json(mem);
}
});
}
} }
}); });
} else { } else {
...@@ -152,20 +119,12 @@ router.put('/:membership_id', function(req, res, next) { ...@@ -152,20 +119,12 @@ router.put('/:membership_id', function(req, res, next) {
router.delete('/:membership_id', function(req, res, next) { router.delete('/:membership_id', function(req, res, next) {
if (req.user) { if (req.user) {
Membership.findOne({ db.Membership.findOne({ where: {
_id: req.params.membership_id _id: req.params.membership_id
}, function(err, mem) { }}).then(function(mem) {
if (err) res.sendStatus(400); mem.destroy().then(function() {
else { res.sendStatus(204);
mem.remove(function(err) { });
if (err) {
res.status(400).json(err);
} else {
// FIXME might need to delete the user?
res.sendStatus(204);
}
});
}
}); });
} else { } else {
res.sendStatus(403); res.sendStatus(403);
......
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema'); const db = require('../../models/db');
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const uuidv4 = require('uuid/v4');
var redis = require('../../helpers/redis'); var redis = require('../../helpers/redis');
var mailer = require('../../helpers/mailer'); var mailer = require('../../helpers/mailer');
...@@ -11,15 +14,12 @@ var phantom = require('../../helpers/phantom'); ...@@ -11,15 +14,12 @@ var phantom = require('../../helpers/phantom');
var async = require('async'); var async = require('async');
var fs = require('fs'); var fs = require('fs');
var _ = require("underscore"); var _ = require("underscore");
var mongoose = require("mongoose");
var archiver = require('archiver'); var archiver = require('archiver');
var request = require('request'); var request = require('request');
var url = require("url"); var url = require("url");
var path = require("path"); var path = require("path");
var crypto = require('crypto'); var crypto = require('crypto');
var qr = require('qr-image');
var glob = require('glob'); var glob = require('glob');
var gm = require('gm');
var express = require('express'); var express = require('express');
var router = express.Router({mergeParams: true}); var router = express.Router({mergeParams: true});
...@@ -49,90 +49,44 @@ var roleMapping = { ...@@ -49,90 +49,44 @@ var roleMapping = {
// MESSAGES // MESSAGES
router.get('/', function(req, res, next) { router.get('/', function(req, res, next) {
Message.find({ db.Message.findAll({where:{
space: req.space._id space_id: req.space._id
}).populate('user', userMapping).exec(function(err, messages) { }, include: ['user']})
res.status(200).json(messages); .then(function(messages) {
}); res.status(200).json(messages);
});
}); });
router.post('/', function(req, res, next) { router.post('/', function(req, res, next) {
var attrs = req.body; var attrs = req.body;
attrs.space = req.space; attrs.space_id = req.space._id;
if (req.user) { if (req.user) {
attrs.user = req.user; attrs.user = req.user;
attrs.user_id = req.user._id;
} else { } else {
attrs.user = null; attrs.user = null;
} }
var msg = new Message(attrs); var msg = attrs;
msg.save(function(err) { msg._id = uuidv4();
if (err) res.status(400).json(erra);
else {
if (msg.message.length <= 1) return;
Membership
.find({
space: req.space,
user: {
"$exists": true
}
})
.populate('user')
.exec(function(err, memberships) {
var users = memberships.map(function(m) {
return m.user;
});
users.forEach((user) => {
if (user.preferences.email_notifications) {
redis.isOnlineInSpace(user, req.space, function(err, online) {
if (!online) {
var nickname = msg.editor_name;
if (req.user) {
nickname = req.user.nickname;
}
mailer.sendMail(
user.email,
req.i18n.__("space_message_subject", req.space.name),
req.i18n.__("space_message_body", nickname, req.space.name), {
message: msg.message,
action: {
link: config.endpoint + "/spaces/" + req.space._id.toString(),
name: req.i18n.__("open")
}
});
} else {
console.log("not sending message to user: is online.");
}
});
} else {
console.log("not sending message to user: is disabled notifications.");
}
});
});
res.distributeCreate("Message", msg); db.Message.create(msg).then(function() {
} if (msg.message.length <= 1) return;
// TODO reimplement notifications
res.distributeCreate("Message", msg);
}); });
}); });
router.delete('/:message_id', function(req, res, next) { router.delete('/:message_id', function(req, res, next) {
Message.findOne({ db.Message.findOne({where:{
"_id": req.params.message_id "_id": req.params.message_id
}, function(err, msg) { }}).then(function(msg) {
if (!msg) { if (!msg) {
res.sendStatus(404); res.sendStatus(404);
} else { } else {
msg.remove(function(err) { msg.destroy().then(function() {
if (err) res.status(400).json(err); res.distributeDelete("Message", msg);
else {
if (msg) {
res.distributeDelete("Message", msg);
} else {
res.sendStatus(404);
}
}
}); });
} }
}); });
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
"use strict"; "use strict";
var config = require('config'); var config = require('config');
require('../../models/schema'); require('../../models/db');
var fs = require('fs'); var fs = require('fs');
var phantom = require('node-phantom-simple'); var phantom = require('node-phantom-simple');
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<div id="pick-mobile" v-if="active_space" class="dialog-section" v-show="opened_dialog=='mobile'"> <div id="pick-mobile" v-if="active_space" class="dialog-section" v-show="opened_dialog=='mobile'">
<h4 class="dialog-title">Mobile Upload</h4> <h4 class="dialog-title">Mobile Upload</h4>
<img v-if="active_space.edit_hash" v-bind:src="'/api/helper/qrcode/'+ active_space._id" /> <!--img v-if="active_space.edit_hash" v-bind:src="'/api/helper/qrcode/'+ active_space._id"-->
<p class="text-center"> <p class="text-center">
Install the Spacedeck App on your phone and scan this QR code to upload photos, sound, video or text. Install the Spacedeck App on your phone and scan this QR code to upload photos, sound, video or text.
......
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment