initial commit.
This commit is contained in:
61
routes/api/memberships.js
Normal file
61
routes/api/memberships.js
Normal file
@@ -0,0 +1,61 @@
|
||||
"use strict";
|
||||
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var fs = require('fs');
|
||||
var _ = require("underscore");
|
||||
var mongoose = require("mongoose");
|
||||
var async = require('async');
|
||||
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 express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
var userMapping = { '_id': 1, 'nickname': 1, 'email': 1};
|
||||
var spaceMapping = { '_id': 1, name: 1};
|
||||
|
||||
router.get('/:membership_id/accept', function(req, res, next) {
|
||||
if (req.user) {
|
||||
Membership.findOne({
|
||||
_id: req.params.membership_id,
|
||||
state: "pending",
|
||||
code: req.query.code,
|
||||
user: { "$exists": false }
|
||||
}).populate('space').exec((err,mem) => {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
if (mem) {
|
||||
if(!mem.user) {
|
||||
mem.code = null;
|
||||
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 {
|
||||
res.status(404).json({"error": "not found"});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
82
routes/api/sessions.js
Normal file
82
routes/api/sessions.js
Normal file
@@ -0,0 +1,82 @@
|
||||
"use strict";
|
||||
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var bcrypt = require('bcrypt');
|
||||
var crypo = require('crypto');
|
||||
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
router.post('/', function(req, res) {
|
||||
var data = req.body;
|
||||
if (data.email && data.password) {
|
||||
var email = req.body.email.toLowerCase();
|
||||
var password = req.body["password"];
|
||||
|
||||
User.find({email: email, account_type: "email"}, (function (err, users) {
|
||||
if (err) {
|
||||
res.status(400).json({"error":"session.users"});
|
||||
} 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);
|
||||
|
||||
user.save(function(err, result) {
|
||||
// FIXME
|
||||
var secure = process.env.NODE_ENV == "production" || process.env.NODE_ENV == "staging";
|
||||
var domain = (process.env.NODE_ENV == "production") ? ".example.org" : "localhost";
|
||||
|
||||
res.cookie('sdsession', token, { domain: domain, httpOnly: true, secure: secure});
|
||||
res.status(201).json(session);
|
||||
});
|
||||
});
|
||||
}else{
|
||||
res.sendStatus(403);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
res.status(400).json({});
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/current', function(req, res, next) {
|
||||
if (req.user) {
|
||||
var user = req.user;
|
||||
var newSessions = user.sessions.filter( function(session){
|
||||
return session.token != req.token;
|
||||
});
|
||||
user.sessions = newSessions;
|
||||
user.save(function(err, result) {
|
||||
// FIXME
|
||||
var domain = (process.env.NODE_ENV == "production") ? ".example.org" : "localhost";
|
||||
res.clearCookie('sdsession', { domain: domain });
|
||||
res.sendStatus(204);
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
201
routes/api/space_artifacts.js
Normal file
201
routes/api/space_artifacts.js
Normal file
@@ -0,0 +1,201 @@
|
||||
"use strict";
|
||||
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var payloadConverter = require('../../helpers/artifact_converter');
|
||||
var redis = require('../../helpers/redis');
|
||||
|
||||
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");
|
||||
var path = require("path");
|
||||
var crypto = require('crypto');
|
||||
var qr = require('qr-image');
|
||||
var glob = require('glob');
|
||||
var gm = require('gm');
|
||||
|
||||
var express = require('express');
|
||||
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
|
||||
}
|
||||
|
||||
// ARTIFACTS
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
Artifact.find({
|
||||
space_id: req.space._id
|
||||
}).exec((err, artifacts) => {
|
||||
async.map(artifacts, (a, cb) => {
|
||||
a = a.toObject();
|
||||
if (a.user_id) {
|
||||
User.findOne({
|
||||
"_id": a.user_id
|
||||
}).select({
|
||||
"_id": 1,
|
||||
"nickname": 1,
|
||||
"email": 1
|
||||
}).exec((err, user) => {
|
||||
a['user'] = user.toObject();
|
||||
cb(err, a);
|
||||
});
|
||||
} else {
|
||||
cb(null, a);
|
||||
}
|
||||
}, (err, mappedArtifacts) => {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
res.status(200).json(mappedArtifacts);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/', function(req, res, next) {
|
||||
var attrs = req.body;
|
||||
|
||||
attrs['space_id'] = req.space._id;
|
||||
|
||||
var artifact = new Artifact(attrs);
|
||||
|
||||
artifact.created_from_ip = req['real_ip'];
|
||||
|
||||
if (req.user) {
|
||||
artifact.user_id = req.user._id;
|
||||
artifact.last_update_user_id = req.user._id;
|
||||
} else {
|
||||
artifact.last_update_editor_name = req.editor_name;
|
||||
}
|
||||
|
||||
if (req.spaceRole == "editor" || req.spaceRole == "admin") {
|
||||
artifact.save(function(err) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
Space.update({
|
||||
_id: req.space._id
|
||||
}, {
|
||||
"$set": {
|
||||
updated_at: new Date()
|
||||
}
|
||||
});
|
||||
res.distributeCreate("Artifact", artifact);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(401).json({
|
||||
"error": "no access"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/:artifact_id/payload', function(req, res, next) {
|
||||
if (req.spaceRole == "editor" || req.spaceRole == "admin") {
|
||||
var a = req.artifact;
|
||||
|
||||
var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9_\-\.]/g, '');
|
||||
var localFilePath = "/tmp/" + fileName;
|
||||
var writeStream = fs.createWriteStream(localFilePath);
|
||||
var stream = req.pipe(writeStream);
|
||||
|
||||
var progress_callback = function(progress_msg) {
|
||||
a.description = progress_msg;
|
||||
a.save();
|
||||
redis.sendMessage("update", a, a.toJSON(), req.channelId);
|
||||
};
|
||||
|
||||
stream.on('finish', function() {
|
||||
payloadConverter.convert(a, fileName, localFilePath, function(error, artifact) {
|
||||
if (error) res.status(400).json(error);
|
||||
else {
|
||||
Space.update({
|
||||
_id: req.space._id
|
||||
}, {
|
||||
"$set": {
|
||||
updated_at: new Date()
|
||||
}
|
||||
});
|
||||
res.distributeUpdate("Artifact", artifact);
|
||||
}
|
||||
}, progress_callback);
|
||||
});
|
||||
} else {
|
||||
res.status(401).json({
|
||||
"error": "no access"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:artifact_id', function(req, res, next) {
|
||||
var a = req.artifact;
|
||||
var newAttr = req.body;
|
||||
newAttr.updated_at = new Date();
|
||||
delete newAttr['_id'];
|
||||
|
||||
if (req.user) {
|
||||
newAttr.last_update_user_id = req.user._id;
|
||||
} else {
|
||||
newAttr.last_update_editor_name = req.editor_name;
|
||||
}
|
||||
|
||||
Artifact.findOneAndUpdate({
|
||||
"_id": a._id
|
||||
}, {
|
||||
"$set": newAttr
|
||||
}, {
|
||||
"new": true
|
||||
}, 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) {
|
||||
var artifact = req.artifact;
|
||||
artifact.remove(function(err) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
Space.update({
|
||||
_id: req.space._id
|
||||
}, {
|
||||
"$set": {
|
||||
updated_at: new Date()
|
||||
}
|
||||
});
|
||||
res.distributeDelete("Artifact", artifact);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
159
routes/api/space_digest.js
Normal file
159
routes/api/space_digest.js
Normal file
@@ -0,0 +1,159 @@
|
||||
"use strict";
|
||||
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
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');
|
||||
|
||||
var express = require('express');
|
||||
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) {
|
||||
var showActionForSpaces = function(err, spaceIds) {
|
||||
var userMapping = {
|
||||
'_id': 1,
|
||||
'nickname': 1,
|
||||
'email': 1
|
||||
};
|
||||
|
||||
var spaceMapping = {
|
||||
'_id': 1,
|
||||
'name': 1
|
||||
};
|
||||
|
||||
var d = new Date();
|
||||
d.setDate(d.getDate() - 1);
|
||||
|
||||
Action
|
||||
.find({
|
||||
created_at: {
|
||||
"$gt": d
|
||||
},
|
||||
space: {
|
||||
"$in": spaceIds
|
||||
}
|
||||
})
|
||||
.populate('space', spaceMapping)
|
||||
.populate('user', userMapping)
|
||||
.exec(function(err, actions) {
|
||||
var groupedBySpaceEvents = _.groupBy(actions, function(action) {
|
||||
return action.space._id;
|
||||
});
|
||||
|
||||
var events = _.map(groupedBySpaceEvents, function(value, key) {
|
||||
|
||||
var sortByDate = _.sortBy(groupedBySpaceEvents[key], function(o) {
|
||||
return o.created_at;
|
||||
});
|
||||
var lastDate = sortByDate[sortByDate.length - 1].created_at;
|
||||
|
||||
var users = groupedBySpaceEvents[key].map(function(action) {
|
||||
if (action.user) {
|
||||
if (action.user._id.equals(req.user._id)) {
|
||||
return "you";
|
||||
} else {
|
||||
return action.user.nickname;
|
||||
}
|
||||
}
|
||||
return action.editor_name;
|
||||
});
|
||||
|
||||
var uniqueUsers = _.unique(users);
|
||||
|
||||
return {
|
||||
space: value[0].space,
|
||||
users: uniqueUsers,
|
||||
last_action: lastDate
|
||||
};
|
||||
});
|
||||
|
||||
var sortedEvents = _.sortBy(events, function(o) {
|
||||
return -o.last_action;
|
||||
});
|
||||
res.status(200).json(sortedEvents);
|
||||
});
|
||||
};
|
||||
|
||||
if (!req.user) {
|
||||
res.status(403).json({
|
||||
error: "auth required"
|
||||
});
|
||||
} else {
|
||||
if (!req.space._id.equals(req.user.home_folder_id)) {
|
||||
Space.getRecursiveSubspacesForSpace(req.space, function(err, spaces) {
|
||||
showActionForSpaces(err, spaces.map(function(s) {
|
||||
return s._id;
|
||||
}));
|
||||
});
|
||||
} else {
|
||||
async.parallel({
|
||||
bycreator: function(cb) {
|
||||
Space.find({
|
||||
creator: req.user._id
|
||||
}, function(err, spaces) {
|
||||
cb(null, spaces.map(function(s) {
|
||||
return s._id;
|
||||
}));
|
||||
});
|
||||
},
|
||||
bymembership: function(cb) {
|
||||
Membership.find({
|
||||
user: req.user,
|
||||
space: {
|
||||
"$exists": 1
|
||||
}
|
||||
}).populate("space").exec(function(err, memberships) {
|
||||
|
||||
async.map(memberships, function(membership, memcb) {
|
||||
Space.getRecursiveSubspacesForSpace(membership.space, function(err, spaces) {
|
||||
cb(null, spaces.map(function(s) {
|
||||
return s._id;
|
||||
}));
|
||||
});
|
||||
}, function(err, spaceArrays) {
|
||||
cb(null, spaceArrays.map(function(s) {
|
||||
return s._id;
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
}, function(err, results) {
|
||||
var spaceIds = _.unique(results.bycreator.concat(results.bymembership));
|
||||
showActionForSpaces(err, spaceIds);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
364
routes/api/space_exports.js
Normal file
364
routes/api/space_exports.js
Normal file
@@ -0,0 +1,364 @@
|
||||
"use strict";
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var redis = require('../../helpers/redis');
|
||||
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 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');
|
||||
|
||||
var express = require('express');
|
||||
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('/png', function(req, res, next) {
|
||||
var triggered = new Date();
|
||||
|
||||
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) {
|
||||
|
||||
Space.update({
|
||||
"_id": req.space._id
|
||||
}, {
|
||||
"$set": {
|
||||
thumbnail_updated_at: triggered
|
||||
}
|
||||
}, function(a, b, c) {});
|
||||
|
||||
phantom.takeScreenshot(req.space, "png",
|
||||
function(local_path) {
|
||||
var localResizedFilePath = local_path + ".thumb.jpg";
|
||||
gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) {
|
||||
|
||||
if (err) {
|
||||
console.error("screenshot resize error: ", err);
|
||||
res.status(500).send("Error taking screenshot.");
|
||||
return;
|
||||
}
|
||||
|
||||
uploader.uploadFile(s3_filename, "image/jpeg", localResizedFilePath, function(err, thumbnailUrl) {
|
||||
|
||||
if (err) {
|
||||
console.error("screenshot s3 upload error. filename: " + s3_filename + " details: ", err);
|
||||
res.status(500).send("Error uploading screenshot.");
|
||||
return;
|
||||
}
|
||||
|
||||
var oldUrl = req.space.thumbnail_url;
|
||||
|
||||
Space.update({
|
||||
"_id": req.space._id
|
||||
}, {
|
||||
"$set": {
|
||||
thumbnail_url: thumbnailUrl
|
||||
}
|
||||
}, function(a, b, c) {
|
||||
res.redirect(thumbnailUrl);
|
||||
|
||||
try {
|
||||
if (oldUrl) {
|
||||
var oldPath = url.parse(oldUrl).pathname;
|
||||
uploader.removeFile(oldPath, function(err, res) {});
|
||||
}
|
||||
fs.unlink(local_path);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
fs.unlink(localResizedFilePath);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
function() {
|
||||
// on_error
|
||||
console.error("phantom could not create screenshot for space " + req.space_id);
|
||||
res.status(404).send("Not found");
|
||||
});
|
||||
} else {
|
||||
res.redirect(req.space.thumbnail_url);
|
||||
}
|
||||
});
|
||||
|
||||
function make_export_filename(space, 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) {
|
||||
var s3_filename = make_export_filename(req.space, "pdf");
|
||||
|
||||
phantom.takeScreenshot(req.space, "pdf", function(local_path) {
|
||||
uploader.uploadFile(s3_filename, "application/pdf", local_path, function(err, url) {
|
||||
res.status(201).json({
|
||||
url: url
|
||||
});
|
||||
fs.unlink(local_path);
|
||||
});
|
||||
}, (err) => {
|
||||
res.status(500).json({
|
||||
error: "PDF could not created (500)"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/zip', function(req, res, next) {
|
||||
Artifact.find({
|
||||
space_id: req.space._id
|
||||
}, function(err, artifacts) {
|
||||
|
||||
if (!artifacts || !artifacts.length || err) {
|
||||
res.status(404).json({
|
||||
"error": "no artifacts"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var localPath = "/tmp/" + req.space._id;
|
||||
|
||||
try {
|
||||
var files = fs.readdirSync(localPath);
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
console.log("[zip export] unlink old file: ", localPath + "/" + files[i]);
|
||||
if (files[i] != "." && files[i] != "..") {
|
||||
fs.unlinkSync(localPath + "/" + files[i]);
|
||||
}
|
||||
}
|
||||
fs.rmdirSync(localPath);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
var used_filenames = {};
|
||||
|
||||
fs.mkdir(localPath, function(err, cb) {
|
||||
async.eachLimit(artifacts, 10, function(artifact, cb) {
|
||||
try {
|
||||
if (artifact.payload_uri) {
|
||||
if (artifact.payload_uri.indexOf("https://") > -1 || artifact.payload_uri.indexOf("http://") > -1) {
|
||||
var parsed = url.parse(artifact.payload_uri);
|
||||
var fileName = path.basename(parsed.pathname) || "file.bin";
|
||||
|
||||
if (fileName.length > 128) {
|
||||
fileName = fileName.substr(fileName.length - 128);
|
||||
}
|
||||
|
||||
if (used_filenames[fileName]) {
|
||||
// if there is a fileName collision, we insert a number before the extension
|
||||
// to differentiate
|
||||
var ext = path.extname(fileName);
|
||||
fileName = path.basename(fileName, ext) + "_" + (parseInt(Math.random() * 10000)) + ext;
|
||||
}
|
||||
used_filenames[fileName] = true;
|
||||
|
||||
//fix for old artifacts where no .pdf is in the filename
|
||||
if (artifact.mime == "application/pdf" && fileName.indexOf(".pdf") < 0) {
|
||||
fileName = fileName + ".pdf";
|
||||
}
|
||||
if (artifact.mime == "image/png" && fileName.indexOf(".png") < 0) {
|
||||
fileName = fileName + ".png";
|
||||
}
|
||||
|
||||
var localFilePath = localPath + '/' + fileName;
|
||||
|
||||
request
|
||||
.get(artifact.payload_uri)
|
||||
.on('error', function(err) {
|
||||
console.error(err);
|
||||
cb(null, artifact.payload_uri);
|
||||
})
|
||||
.on('end', function() {
|
||||
cb(null, artifact.payload_uri);
|
||||
}).pipe(fs.createWriteStream(localFilePath));
|
||||
|
||||
} else {
|
||||
cb(null, artifact.payload_uri);
|
||||
}
|
||||
} else {
|
||||
cb(null, artifact.payload_uri);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
cb(null);
|
||||
}
|
||||
|
||||
}, function(err, payloads) {
|
||||
|
||||
var outputPath = '/tmp/' + req.space._id + '.zip';
|
||||
var output = fs.createWriteStream(outputPath);
|
||||
var archive = archiver('zip');
|
||||
|
||||
output.on('close', function() {
|
||||
var name = make_export_filename(req.space, "zip");
|
||||
uploader.uploadFile(name, "application/zip", outputPath, function(err, url) {
|
||||
res.status(201).json({
|
||||
url: url
|
||||
});
|
||||
|
||||
try {
|
||||
fs.unlink(outputPath);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
archive.on('error', function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
archive.pipe(output);
|
||||
archive.directory(localPath, false, {
|
||||
date: new Date()
|
||||
});
|
||||
archive.finalize();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/html', function(req, res) {
|
||||
Artifact.find({
|
||||
space_id: req.space._id
|
||||
}, function(err, artifacts) {
|
||||
var space = req.space;
|
||||
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;
|
||||
175
routes/api/space_memberships.js
Normal file
175
routes/api/space_memberships.js
Normal file
@@ -0,0 +1,175 @@
|
||||
"use strict";
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var redis = require('../../helpers/redis');
|
||||
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 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 express = require('express');
|
||||
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) {
|
||||
Membership
|
||||
.find({
|
||||
space: req.space._id
|
||||
})
|
||||
.populate("user")
|
||||
.exec(function(err, memberships) {
|
||||
res.status(200).json(memberships);
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/', function(req, res, next) {
|
||||
if (req.spaceRole == "admin") {
|
||||
var attrs = req.body;
|
||||
attrs['space'] = req.space._id;
|
||||
attrs['state'] = "pending";
|
||||
var membership = new Membership(attrs);
|
||||
var msg = attrs.personal_message;
|
||||
|
||||
if (membership.email_invited != req.user.email) {
|
||||
User.findOne({
|
||||
"email": membership.email_invited
|
||||
}, function(err, user) {
|
||||
|
||||
if (user) {
|
||||
membership.user = user;
|
||||
membership.state = "active";
|
||||
} else {
|
||||
membership.code = crypto.randomBytes(64).toString('hex').substring(0, 12);
|
||||
}
|
||||
|
||||
membership.save(function(err) {
|
||||
if (err) res.sendStatus(400);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
res.status(400).json({
|
||||
"error": "user already in space"
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
res.status(403).json({
|
||||
"error": "not_permitted"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:membership_id', function(req, res, next) {
|
||||
if (req.user) {
|
||||
if (req.spaceRole == "admin") {
|
||||
Membership.findOne({
|
||||
_id: req.params.membership_id
|
||||
}, function(err, mem) {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
if (mem) {
|
||||
var attrs = req.body;
|
||||
mem.role = attrs.role;
|
||||
mem.save(function(err) {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
res.status(201).json(mem);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:membership_id', function(req, res, next) {
|
||||
if (req.user) {
|
||||
Membership.findOne({
|
||||
_id: req.params.membership_id
|
||||
}, function(err, mem) {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
mem.remove(function(err) {
|
||||
if (err) {
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
// FIXME might need to delete the user?
|
||||
res.sendStatus(204);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
141
routes/api/space_messages.js
Normal file
141
routes/api/space_messages.js
Normal file
@@ -0,0 +1,141 @@
|
||||
"use strict";
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var redis = require('../../helpers/redis');
|
||||
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 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 express = require('express');
|
||||
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
|
||||
}
|
||||
|
||||
// MESSAGES
|
||||
|
||||
router.get('/', function(req, res, next) {
|
||||
Message.find({
|
||||
space: req.space._id
|
||||
}).populate('user', userMapping).exec(function(err, messages) {
|
||||
res.status(200).json(messages);
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/', function(req, res, next) {
|
||||
var attrs = req.body;
|
||||
attrs.space = req.space;
|
||||
|
||||
if (req.user) {
|
||||
attrs.user = req.user;
|
||||
} else {
|
||||
attrs.user = null;
|
||||
}
|
||||
|
||||
var msg = new Message(attrs);
|
||||
msg.save(function(err) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.delete('/:message_id', function(req, res, next) {
|
||||
Message.findOne({
|
||||
"_id": req.params.message_id
|
||||
}, function(err, msg) {
|
||||
if (!msg) {
|
||||
res.sendStatus(404);
|
||||
} else {
|
||||
msg.remove(function(err) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
if (msg) {
|
||||
res.distributeDelete("Message", msg);
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
569
routes/api/spaces.js
Normal file
569
routes/api/spaces.js
Normal file
@@ -0,0 +1,569 @@
|
||||
"use strict";
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var redis = require('../../helpers/redis');
|
||||
var mailer = require('../../helpers/mailer');
|
||||
var uploader = require('../../helpers/uploader');
|
||||
var space_render = require('../../helpers/space-render');
|
||||
var phantom = require('../../helpers/phantom');
|
||||
var payloadConverter = require('../../helpers/artifact_converter');
|
||||
|
||||
var slug = require('slug');
|
||||
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
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');
|
||||
const exec = require('child_process');
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
// JSON MAPPINGS
|
||||
var userMapping = {
|
||||
_id: 1,
|
||||
nickname: 1,
|
||||
email: 1,
|
||||
avatar_thumb_uri: 1
|
||||
};
|
||||
|
||||
var spaceMapping = {
|
||||
_id: 1,
|
||||
name: 1,
|
||||
thumbnail_url: 1
|
||||
};
|
||||
|
||||
router.get('/', function(req, res, next) {
|
||||
if (!req.user) {
|
||||
res.status(403).json({
|
||||
error: "auth required"
|
||||
});
|
||||
} else {
|
||||
if (req.query.writablefolders) {
|
||||
Membership.find({
|
||||
user: req.user._id
|
||||
}, (err, memberships) => {
|
||||
|
||||
var validMemberships = memberships.filter((m) => {
|
||||
if (!m.space || (m.space == "undefined"))
|
||||
return false;
|
||||
else
|
||||
return mongoose.Types.ObjectId.isValid(m.space.toString());
|
||||
});
|
||||
|
||||
var editorMemberships = validMemberships.filter((m) => {
|
||||
return (m.role == "editor") || (m.role == "admin")
|
||||
});
|
||||
|
||||
var spaceIds = editorMemberships.map(function(m) {
|
||||
return new mongoose.Types.ObjectId(m.space);
|
||||
});
|
||||
|
||||
var q = {
|
||||
"space_type": "folder",
|
||||
"$or": [{
|
||||
"creator": req.user._id
|
||||
}, {
|
||||
"_id": {
|
||||
"$in": spaceIds
|
||||
},
|
||||
"creator": {
|
||||
"$ne": req.user._id
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
Space
|
||||
.find(q)
|
||||
.populate('creator', userMapping)
|
||||
.exec(function(err, spaces) {
|
||||
if (err) console.error(err);
|
||||
var updatedSpaces = spaces.map(function(s) {
|
||||
var spaceObj = s.toObject();
|
||||
return spaceObj;
|
||||
});
|
||||
|
||||
async.map(spaces, (space, cb) => {
|
||||
Space.getRecursiveSubspacesForSpace(space, (err, spaces) => {
|
||||
var allSpaces = spaces;
|
||||
cb(err, allSpaces);
|
||||
})
|
||||
}, (err, spaces) => {
|
||||
|
||||
var allSpaces = _.flatten(spaces);
|
||||
|
||||
var onlyFolders = _.filter(allSpaces, (s) => {
|
||||
return s.space_type == "folder";
|
||||
})
|
||||
var uniqueFolders = _.unique(onlyFolders, (s) => {
|
||||
return s._id.toString();
|
||||
})
|
||||
|
||||
res.status(200).json(uniqueFolders);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (req.query.search) {
|
||||
|
||||
Membership.find({
|
||||
user: req.user._id
|
||||
}, function(err, memberships) {
|
||||
|
||||
var validMemberships = memberships.filter(function(m) {
|
||||
if (!m.space || (m.space == "undefined"))
|
||||
return false;
|
||||
else
|
||||
return mongoose.Types.ObjectId.isValid(m.space.toString());
|
||||
});
|
||||
|
||||
var spaceIds = validMemberships.map(function(m) {
|
||||
return new mongoose.Types.ObjectId(m.space);
|
||||
});
|
||||
|
||||
var q = {
|
||||
"$or": [{"creator": req.user._id},
|
||||
{"_id": {"$in": spaceIds}},
|
||||
{"parent_space_id": {"$in": spaceIds}}],
|
||||
name: new RegExp(req.query.search, "i")
|
||||
};
|
||||
|
||||
Space
|
||||
.find(q)
|
||||
.populate('creator', userMapping)
|
||||
.exec(function(err, spaces) {
|
||||
if (err) console.error(err);
|
||||
var updatedSpaces = spaces.map(function(s) {
|
||||
var spaceObj = s.toObject();
|
||||
return spaceObj;
|
||||
});
|
||||
res.status(200).json(spaces);
|
||||
});
|
||||
});
|
||||
|
||||
} else if (req.query.parent_space_id && req.query.parent_space_id != req.user.home_folder_id) {
|
||||
|
||||
Space
|
||||
.findOne({
|
||||
_id: req.query.parent_space_id
|
||||
})
|
||||
.populate('creator', userMapping)
|
||||
.exec(function(err, space) {
|
||||
if (space) {
|
||||
Space.roleInSpace(space, req.user, function(err, role) {
|
||||
|
||||
if (role == "none") {
|
||||
if(space.access_mode == "public") {
|
||||
role = "viewer";
|
||||
}
|
||||
}
|
||||
|
||||
if (role != "none") {
|
||||
Space
|
||||
.find({
|
||||
parent_space_id: req.query.parent_space_id
|
||||
})
|
||||
.populate('creator', userMapping)
|
||||
.exec(function(err, spaces) {
|
||||
res.status(200).json(spaces);
|
||||
});
|
||||
} else {
|
||||
res.status(403).json({"error": "no authorized"});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(404).json({"error": "space not found"});
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
Membership.find({
|
||||
user: req.user._id
|
||||
}, function(err, memberships) {
|
||||
var validMemberships = memberships.filter(function(m) {
|
||||
if (!m.space || (m.space == "undefined"))
|
||||
return false;
|
||||
else
|
||||
return mongoose.Types.ObjectId.isValid(m.space.toString());
|
||||
});
|
||||
|
||||
var spaceIds = validMemberships.map(function(m) {
|
||||
return new mongoose.Types.ObjectId(m.space);
|
||||
});
|
||||
|
||||
var q = {
|
||||
"$or": [{
|
||||
"creator": req.user._id,
|
||||
"parent_space_id": req.user.home_folder_id
|
||||
}, {
|
||||
"_id": {
|
||||
"$in": spaceIds
|
||||
},
|
||||
"creator": {
|
||||
"$ne": req.user._id
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
Space
|
||||
.find(q)
|
||||
.populate('creator', userMapping)
|
||||
.exec(function(err, spaces) {
|
||||
if (err) console.error(err);
|
||||
var updatedSpaces = spaces.map(function(s) {
|
||||
var spaceObj = s.toObject();
|
||||
return spaceObj;
|
||||
});
|
||||
res.status(200).json(spaces);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', function(req, res, next) {
|
||||
if (req.user) {
|
||||
var attrs = req.body;
|
||||
|
||||
var createSpace = () => {
|
||||
|
||||
attrs.creator = req.user;
|
||||
attrs.edit_hash = crypto.randomBytes(64).toString('hex').substring(0, 7);
|
||||
attrs.edit_slug = slug(attrs.name);
|
||||
|
||||
var space = new Space(attrs);
|
||||
space.save(function(err, createdSpace) {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
var membership = new Membership({
|
||||
user: req.user,
|
||||
space: createdSpace,
|
||||
role: "admin"
|
||||
});
|
||||
membership.save(function(err, createdTeam) {
|
||||
if (err) {
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
res.status(201).json(createdSpace);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (attrs.parent_space_id) {
|
||||
Space.findOne({
|
||||
"_id": attrs.parent_space_id
|
||||
}).populate('creator', userMapping).exec((err, parentSpace) => {
|
||||
if (parentSpace) {
|
||||
Space.roleInSpace(parentSpace, req.user, (err, role) => {
|
||||
if ((role == "editor") || (role == "admin")) {
|
||||
createSpace();
|
||||
} else {
|
||||
res.status(403).json({
|
||||
"error": "not editor in parent Space"
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(404).json({
|
||||
"error": "parent Space not found"
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
createSpace();
|
||||
}
|
||||
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:id', function(req, res, next) {
|
||||
res.status(200).json(req.space);
|
||||
});
|
||||
|
||||
router.put('/:id', function(req, res) {
|
||||
var space = req.space;
|
||||
var newAttr = req.body;
|
||||
|
||||
if (req['spaceRole'] != "editor" && req['spaceRole'] != "admin") {
|
||||
res.sendStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
newAttr.updated_at = new Date();
|
||||
newAttr.edit_slug = slug(newAttr['name']);
|
||||
|
||||
delete newAttr['_id'];
|
||||
delete newAttr['editor_name'];
|
||||
delete newAttr['creator'];
|
||||
|
||||
Space.findOneAndUpdate({
|
||||
"_id": space._id
|
||||
}, {
|
||||
"$set": newAttr
|
||||
}, {
|
||||
"new": true
|
||||
}, function(err, space) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
res.distributeUpdate("Space", space);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/:id/background', function(req, res, next) {
|
||||
var space = req.space;
|
||||
var newDate = new Date();
|
||||
var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9\.]/g, '');
|
||||
var localFilePath = "/tmp/" + fileName;
|
||||
var writeStream = fs.createWriteStream(localFilePath);
|
||||
var stream = req.pipe(writeStream);
|
||||
|
||||
req.on('end', function() {
|
||||
uploader.uploadFile("s" + req.space._id + "/bg_" + newDate.getTime() + "_" + fileName, "image/jpeg", localFilePath, function(err, backgroundUrl) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
var adv = space.advanced;
|
||||
|
||||
if (adv.background_uri) {
|
||||
var oldPath = url.parse(req.space.thumbnail_url).pathname;
|
||||
uploader.removeFile(oldPath, function(err) {
|
||||
console.log("removed old bg error:", err);
|
||||
});
|
||||
}
|
||||
|
||||
adv.background_uri = backgroundUrl;
|
||||
|
||||
Space.findOneAndUpdate({
|
||||
"_id": space._id
|
||||
}, {
|
||||
"$set": {
|
||||
advanced: adv
|
||||
}
|
||||
}, {
|
||||
"new": true
|
||||
}, function(err, space) {
|
||||
if (err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
fs.unlink(localFilePath, function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
res.status(200).json(space);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var handleDuplicateSpaceRequest = function(req, res, parentSpace) {
|
||||
Space.duplicateSpace(req.space, req.user, 0, (err, newSpace) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
res.status(201).json(newSpace);
|
||||
}
|
||||
}, parentSpace);
|
||||
}
|
||||
|
||||
router.post('/:id/duplicate', (req, res, next) => {
|
||||
if (req.query.parent_space_id) {
|
||||
Space.findOne({
|
||||
_id: req.query.parent_space_id
|
||||
}).populate('creator', userMapping).exec((err, parentSpace) => {
|
||||
if (!parentSpace) {
|
||||
res.status(404).json({
|
||||
"error": "parent space not found for dupicate"
|
||||
});
|
||||
} else {
|
||||
Space.roleInSpace(parentSpace, req.user, (err, role) => {
|
||||
if (role == "admin" || role == "editor") {
|
||||
handleDuplicateSpaceRequest(req, res, parentSpace);
|
||||
} else {
|
||||
res.status(403).json({
|
||||
"error": "not authed for parent_space_id"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
handleDuplicateSpaceRequest(req, res);
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:id', function(req, res, next) {
|
||||
if (req.user) {
|
||||
const space = req.space;
|
||||
|
||||
if (req.spaceRole == "admin") {
|
||||
const attrs = req.body;
|
||||
Space.recursiveDelete(space, function(err) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
res.distributeDelete("Space", space);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(403).json({
|
||||
"error": "requires admin status"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/:id/artifacts-pdf', function(req, res, next) {
|
||||
if (req.spaceRole == "editor" || req.spaceRole == "admin") {
|
||||
|
||||
var withZones = (req.query.zones) ? req.query.zones == "true" : false;
|
||||
var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9\.]/g, '');
|
||||
var localFilePath = "/tmp/" + fileName;
|
||||
var writeStream = fs.createWriteStream(localFilePath);
|
||||
var stream = req.pipe(writeStream);
|
||||
|
||||
req.on('end', function() {
|
||||
|
||||
var rawName = fileName.slice(0, fileName.length - 4);
|
||||
var outputFolder = "/tmp/" + rawName;
|
||||
var rights = 777;
|
||||
|
||||
fs.mkdir(outputFolder, function(db) {
|
||||
var images = outputFolder + "/" + rawName + "-page-%03d.jpeg";
|
||||
|
||||
exec.execFile("gs", ["-sDEVICE=jpeg", "-dDownScaleFactor=4", "-dDOINTERPOLATE", "-dNOPAUSE", "-dJPEGQ=80", "-dBATCH", "-sOutputFile=" + images, "-r250", "-f", localFilePath], {}, function(error, stdout, stderr) {
|
||||
if (error === null) {
|
||||
|
||||
glob(outputFolder + "/*.jpeg", function(er, files) {
|
||||
var count = files.length;
|
||||
var delta = 10;
|
||||
|
||||
var limitPerRow = Math.ceil(Math.sqrt(count));
|
||||
|
||||
var startX = parseInt(req.query.x, delta);
|
||||
var startY = parseInt(req.query.y, delta);
|
||||
|
||||
async.mapLimit(files, 20, function(localfilePath, cb) {
|
||||
|
||||
var fileName = path.basename(localfilePath);
|
||||
var baseName = path.basename(localfilePath, ".jpeg");
|
||||
|
||||
var number = parseInt(baseName.slice(baseName.length - 3, baseName.length), 10);
|
||||
|
||||
gm(localFilePath).size(function(err, size) {
|
||||
var w = 350;
|
||||
var h = w;
|
||||
|
||||
var x = startX + (((number - 1) % limitPerRow) * w);
|
||||
var y = startY + ((parseInt(((number - 1) / limitPerRow), 10) + 1) * w);
|
||||
|
||||
var userId;
|
||||
if (req.user)
|
||||
userId = req.user._id;
|
||||
|
||||
var a = new Artifact({
|
||||
mime: "image/jpg",
|
||||
space_id: req.space._id,
|
||||
user_id: userId,
|
||||
editor_name: req.guest_name,
|
||||
board: {
|
||||
w: w,
|
||||
h: h,
|
||||
x: x,
|
||||
y: y,
|
||||
z: (number + (count + 100))
|
||||
}
|
||||
});
|
||||
|
||||
payloadConverter.convert(a, fileName, localfilePath, (error, artifact) => {
|
||||
if (error) res.status(400).json(error);
|
||||
else {
|
||||
if (withZones) {
|
||||
var zone = new Artifact({
|
||||
mime: "x-spacedeck/zone",
|
||||
description: "Zone " + (number),
|
||||
space_id: req.space._id,
|
||||
user_id: userId,
|
||||
editor_name: req.guest_name,
|
||||
board: {
|
||||
w: artifact.board.w + 20,
|
||||
h: artifact.board.h + 40,
|
||||
x: x - 10,
|
||||
y: y - 30,
|
||||
z: number
|
||||
},
|
||||
style: {
|
||||
order: number,
|
||||
valign: "middle",
|
||||
align: "center"
|
||||
}
|
||||
});
|
||||
|
||||
zone.save((err) => {
|
||||
redis.sendMessage("create", "Artifact", zone.toJSON(), req.channelId);
|
||||
cb(null, [artifact, zone]);
|
||||
});
|
||||
|
||||
} else {
|
||||
cb(null, [artifact]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}, function(err, artifacts) {
|
||||
|
||||
exec.execFile("rm", ["-r", outputFolder], function(err) {
|
||||
res.status(201).json(_.flatten(artifacts));
|
||||
|
||||
async.eachLimit(artifacts, 10, (artifact_or_artifacts, cb) => {
|
||||
|
||||
if (artifact_or_artifacts instanceof Array) {
|
||||
_.each(artifact_or_artifacts, (a) => {
|
||||
redis.sendMessage("create", "Artifact", a.toJSON(), req.channelId);
|
||||
});
|
||||
} else {
|
||||
redis.sendMessage("create", "Artifact", artifact_or_artifacts.toJSON(), req.channelId);
|
||||
}
|
||||
cb(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.error("error:", error);
|
||||
exec.execFile("rm", ["-r", outputFolder], function(err) {
|
||||
fs.unlink(localFilePath);
|
||||
res.status(400).json({});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
res.status(401).json({
|
||||
"error": "no access"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
265
routes/api/teams.js
Normal file
265
routes/api/teams.js
Normal file
@@ -0,0 +1,265 @@
|
||||
"use strict";
|
||||
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var redis = require('../../helpers/redis');
|
||||
var mailer = require('../../helpers/mailer');
|
||||
|
||||
var fs = require('fs');
|
||||
var _ = require('underscore');
|
||||
var crypto = require('crypto');
|
||||
var bcrypt = require('bcrypt');
|
||||
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
var userMapping = { '_id': 1, 'nickname': 1, 'email': 1};
|
||||
|
||||
router.get('/:id', (req, res) => {
|
||||
res.status(200).json(req.user.team);
|
||||
});
|
||||
|
||||
router.put('/:id', (req, res) => {
|
||||
var team = req.user.team;
|
||||
if (!team) {
|
||||
res.status(400).json({"error": "user in no team"});
|
||||
} else {
|
||||
var newAttr = req.body;
|
||||
newAttr.updated_at = new Date();
|
||||
delete newAttr['_id'];
|
||||
|
||||
if(newAttr['subdomain']) {
|
||||
newAttr['subdomain'] = newAttr['subdomain'].toLowerCase();
|
||||
}
|
||||
const new_subdomain = newAttr['subdomain'];
|
||||
var forbidden_subdomains = [];
|
||||
|
||||
function updateTeam() {
|
||||
Team.findOneAndUpdate({"_id": team._id}, {"$set": newAttr}, {"new": true}, (err, team) => {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
res.status(200).json(team);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var isForbidden = forbidden_subdomains.indexOf(new_subdomain) > -1;
|
||||
if (isForbidden) {
|
||||
res.bad_request("subdomain not valid");
|
||||
} else {
|
||||
if (new_subdomain) {
|
||||
Team.findOne({"domain": new_subdomain}).exec((err, team) => {
|
||||
if(team) {
|
||||
res.bad_request("subdomain already used");
|
||||
} else {
|
||||
updateTeam()
|
||||
}
|
||||
});
|
||||
} else {
|
||||
updateTeam()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:id/memberships', (req, res) => {
|
||||
User
|
||||
.find({team: req.user.team})
|
||||
.populate("team")
|
||||
.exec(function(err, users){
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
res.status(200).json(users);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/:id/memberships', (req, res, next) => {
|
||||
if (req.body.email) {
|
||||
const email = req.body.email.toLowerCase();
|
||||
const team = req.user.team;
|
||||
|
||||
User.findOne({"email": email}).populate('team').exec((err, user) => {
|
||||
if (user) {
|
||||
const code = crypto.randomBytes(64).toString('hex').substring(0,7);
|
||||
team.invitation_codes.push(code);
|
||||
team.save((err) => {
|
||||
if (err){ res.status(400).json(err); }
|
||||
else {
|
||||
mailer.sendMail(email, req.i18n.__("team_invite_membership_subject", team.name), req.i18n.__("team_invite_membership_body", team.name), { action: {
|
||||
link: config.endpoint + "/teams/" + req.user.team._id + "/join?code=" + code,
|
||||
name: req.i18n.__("team_invite_membership_action"),
|
||||
teamname: team.name
|
||||
}});
|
||||
|
||||
res.status(201).json(user);
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
// complete new user
|
||||
const password = crypto.randomBytes(64).toString('hex').substring(0,7);
|
||||
const confirmation_token = crypto.randomBytes(64).toString('hex').substring(0,7);
|
||||
|
||||
bcrypt.genSalt(10, (err, salt) => {
|
||||
bcrypt.hash(password, salt, (err, hash) => {
|
||||
crypto.randomBytes(16, (ex, buf) => {
|
||||
const token = buf.toString('hex');
|
||||
|
||||
var u = new User({
|
||||
email: email,
|
||||
account_type: "email",
|
||||
nickname: email,
|
||||
team: team._id,
|
||||
password_hash: hash,
|
||||
payment_plan_key: team.payment_plan_key,
|
||||
confirmation_token: confirmation_token,
|
||||
preferences: {
|
||||
language: req.i18n.locale
|
||||
}
|
||||
});
|
||||
|
||||
u.save((err) => {
|
||||
if(err) res.sendStatus(400);
|
||||
else {
|
||||
var homeSpace = new Space({
|
||||
name: req.i18n.__("home"),
|
||||
space_type: "folder",
|
||||
creator: u
|
||||
});
|
||||
|
||||
homeSpace.save((err, homeSpace) => {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
u.home_folder_id = homeSpace._id;
|
||||
u.save((err) => {
|
||||
|
||||
User.find({"_id": {"$in": team.admins }}).exec((err, admins) => {
|
||||
admins.forEach((admin) => {
|
||||
var i18n = req.i18n;
|
||||
if(admin.preferences && admin.preferences.language){
|
||||
i18n.setLocale(admin.preferences.language || "en");
|
||||
}
|
||||
mailer.sendMail(admin.email, i18n.__("team_invite_membership_subject", team.name), i18n.__("team_invite_admin_body", email, team.name, password), { teamname: team.name });
|
||||
});
|
||||
});
|
||||
|
||||
mailer.sendMail(email, req.i18n.__("team_invite_membership_subject", team.name), req.i18n.__("team_invite_user_body", team.name, password), { action: {
|
||||
link: config.endpoint + "/users/byteam/" + req.user.team._id + "/join?confirmation_token=" + confirmation_token,
|
||||
name: req.i18n.__("team_invite_membership_action")
|
||||
}, teamname: team.name });
|
||||
|
||||
if (err) res.status(400).json(err);
|
||||
else{
|
||||
res.status(201).json(u)
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({"error": "email missing"});
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:id/memberships/:user_id', (req, res) => {
|
||||
User.findOne({_id: req.params.user_id}, (err,mem) => {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
if(user.team._id == req.user.team._id){
|
||||
user['team'] = req.user.team._id;
|
||||
user.save((err) => {
|
||||
res.sendStatus(204);
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/:id/memberships/:user_id/promote', (req, res) => {
|
||||
User.findOne({_id: req.params.user_id}, (err,user) => {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
if (user.team.toString() == req.user.team._id.toString()) {
|
||||
var team = req.user.team;
|
||||
var adminIndex = team.admins.indexOf(user._id);
|
||||
|
||||
if (adminIndex == -1) {
|
||||
team.admins.push(user._id);
|
||||
team.save((err, team) => {
|
||||
res.status(204).json(team);
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({"error": "already admin"});
|
||||
}
|
||||
} else {
|
||||
res.status(403).json({"error": "team id not correct"});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/:id/memberships/:user_id/demote', (req, res, next) => {
|
||||
User.findOne({_id: req.params.user_id}, (err,user) => {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
if (user.team.toString() == req.user.team._id.toString()) {
|
||||
const team = req.user.team;
|
||||
const adminIndex = team.admins.indexOf(user._id);
|
||||
|
||||
if(adminIndex > -1) {
|
||||
team.admins.splice(adminIndex,1);
|
||||
team.save((err, team) => {
|
||||
res.status(204).json(team);
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.delete('/:id/memberships/:user_id', (req, res) => {
|
||||
User.findOne({_id: req.params.user_id}).populate('team').exec((err,user) => {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
const currentUserId = req.user._id.toString();
|
||||
const team = req.user.team;
|
||||
|
||||
const isAdmin = (req.user.team.admins.filter( mem => {
|
||||
return mem == currentUserId;
|
||||
}).length == 1)
|
||||
|
||||
if (isAdmin) {
|
||||
user.team = null;
|
||||
user.payment_plan_key = "free";
|
||||
user.save( err => {
|
||||
const adminIndex = team.admins.indexOf(user._id);
|
||||
if(adminIndex > -1) {
|
||||
team.admins.splice(adminIndex,1);
|
||||
team.save((err, team) => {
|
||||
console.log("admin removed");
|
||||
});
|
||||
}
|
||||
|
||||
res.sendStatus(204);
|
||||
});
|
||||
} else {
|
||||
res.status(403).json({"error": "not admin"});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
470
routes/api/users.js
Normal file
470
routes/api/users.js
Normal file
@@ -0,0 +1,470 @@
|
||||
"use strict";
|
||||
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var mailer = require('../../helpers/mailer');
|
||||
var uploader = require('../../helpers/uploader');
|
||||
|
||||
var bcrypt = require('bcrypt');
|
||||
var crypo = require('crypto');
|
||||
var swig = require('swig');
|
||||
var async = require('async');
|
||||
var _ = require('underscore');
|
||||
var fs = require('fs');
|
||||
var request = require('request');
|
||||
var gm = require('gm');
|
||||
var validator = require('validator');
|
||||
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
router.get('/current', function(req, res, next) {
|
||||
if (req.user) {
|
||||
console.log(req.user.team);
|
||||
res.status(200).json(req.user);
|
||||
} else {
|
||||
res.status(401).json({"error":"user_not_found"});
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/', function(req, res) {
|
||||
if (req.body["email"] && req.body["password"]) {
|
||||
|
||||
var email = req.body["email"].toLowerCase();
|
||||
var nickname = req.body["nickname"];
|
||||
var password = req.body["password"];
|
||||
var password_confirmation = req.body["password_confirmation"];
|
||||
|
||||
if (password_confirmation == password) {
|
||||
if (validator.isEmail(email)) {
|
||||
|
||||
var createUser = function() {
|
||||
bcrypt.genSalt(10, function(err, salt) {
|
||||
bcrypt.hash(password, salt, function(err, hash) {
|
||||
|
||||
crypo.randomBytes(16, function(ex, buf) {
|
||||
var token = buf.toString('hex');
|
||||
|
||||
var u = new User({
|
||||
email: email,
|
||||
account_type: "email",
|
||||
nickname: nickname,
|
||||
password_hash: hash,
|
||||
preferences: {
|
||||
language: req.i18n.locale
|
||||
},
|
||||
confirmation_token: token
|
||||
});
|
||||
|
||||
u.save(function (err) {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
var homeSpace = new Space({
|
||||
name: req.i18n.__("home"),
|
||||
space_type: "folder",
|
||||
creator: u
|
||||
});
|
||||
|
||||
homeSpace.save((err, homeSpace) => {
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
u.home_folder_id = homeSpace._id;
|
||||
u.save((err) => {
|
||||
|
||||
mailer.sendMail(u.email, req.i18n.__("confirm_subject"), req.i18n.__("confirm_body"), {
|
||||
action: {
|
||||
link: config.endpoint + "/confirm/" + u.confirmation_token,
|
||||
name: req.i18n.__("confirm_action")
|
||||
}
|
||||
});
|
||||
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
res.status(201).json({});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
User.find({email: email}, (function (err, users) {
|
||||
if (err) {
|
||||
res.status(400).json({"error":"password_confirmation"});
|
||||
} else {
|
||||
|
||||
if (users.length === 0) {
|
||||
var domain = email.slice(email.lastIndexOf('@')+1);
|
||||
|
||||
Domain.findOne({domain: domain}, function(err, domain) {
|
||||
if(domain){
|
||||
if(domain.edu) {
|
||||
createUser();
|
||||
} else {
|
||||
res.status(400).json({"error":"domain_blocked"});
|
||||
}
|
||||
} else {
|
||||
createUser();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({"error":"user_email_already_used"});
|
||||
}
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
res.status(400).json({"error":"email_invalid"});
|
||||
}
|
||||
} else {
|
||||
res.status(400).json({"error":"password_confirmation"});
|
||||
}
|
||||
} else {
|
||||
res.status(400).json({"error":"email or password missing"});
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/oauth2callback/url', function(req, res) {
|
||||
var google = require('googleapis');
|
||||
var OAuth2 = google.auth.OAuth2;
|
||||
|
||||
var oauth2Client = new OAuth2(
|
||||
config.google_access,
|
||||
config.google_secret,
|
||||
config.endpoint + "/login"
|
||||
);
|
||||
|
||||
var url = oauth2Client.generateAuthUrl({
|
||||
access_type: 'online',
|
||||
scope: "email"
|
||||
});
|
||||
|
||||
res.status(200).json({"url":url});
|
||||
});
|
||||
|
||||
router.get('/loginorsignupviagoogle', function(req, res) {
|
||||
var google = require('googleapis');
|
||||
var OAuth2 = google.auth.OAuth2;
|
||||
var plus = google.plus('v1');
|
||||
|
||||
var oauth2Client = new OAuth2(
|
||||
config.google_access,
|
||||
config.google_secret,
|
||||
config.endpoint + "/login"
|
||||
);
|
||||
|
||||
var loginUser = function(user, cb) {
|
||||
crypo.randomBytes(48, function(ex, buf) {
|
||||
var token = buf.toString('hex');
|
||||
var session = {
|
||||
token: token,
|
||||
created_at: new Date()
|
||||
};
|
||||
if(!user.sessions)
|
||||
user.sessions = [];
|
||||
user.sessions.push(session);
|
||||
user.save(function(err, user) {
|
||||
cb(session);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var code = req.query.code;
|
||||
oauth2Client.getToken(code, function(err, tokens) {
|
||||
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
var apiUrl = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=" + tokens.access_token;
|
||||
|
||||
var finalizeLogin = function(session){
|
||||
var secure = process.env.NODE_ENV == "production" || process.env.NODE_ENV == "staging";
|
||||
res.cookie('sdsession', session.token, { httpOnly: true, secure: secure});
|
||||
res.status(201).json(session);
|
||||
};
|
||||
|
||||
request.get(apiUrl, function(error, response, body) {
|
||||
if (error) res.status(400).json(error);
|
||||
else {
|
||||
const data = JSON.parse(body);
|
||||
const email = data.email;
|
||||
const name = data.name;
|
||||
|
||||
User.findOne({email: email}, function (err, user) {
|
||||
if (user) {
|
||||
// login new google user
|
||||
if (user.account_type == "google") {
|
||||
// just login
|
||||
loginUser(user, (session) => {
|
||||
finalizeLogin(session);
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({"error":"user_email_already_used"});
|
||||
}
|
||||
} else {
|
||||
const u = new User({
|
||||
email: email,
|
||||
account_type: "google",
|
||||
nickname: name,
|
||||
avatar_thumb_uri: body.picture,
|
||||
preferences: {
|
||||
language: req.i18n.locale
|
||||
},
|
||||
confirmed_at: new Date()
|
||||
});
|
||||
|
||||
u.save(function (err) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
var homeSpace = new Space({
|
||||
name: req.i18n.__("home"),
|
||||
space_type: "folder",
|
||||
creator: u
|
||||
});
|
||||
|
||||
homeSpace.save(function(err, homeSpace) {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
u.home_folder_id = homeSpace._id;
|
||||
u.save(function(err){
|
||||
if (err) res.sendStatus(400);
|
||||
else {
|
||||
|
||||
mailer.sendMail(u.email, req.i18n.__("welcome_subject"), req.i18n.__("welcome_body"), {});
|
||||
loginUser(u, function(session) {
|
||||
finalizeLogin(session);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/ ', function(req, res, next) {
|
||||
if (req.user) {
|
||||
console.log(req.user.team);
|
||||
res.status(200).json(req.user);
|
||||
} else {
|
||||
res.status(401).json({"error":"user_not_found"});
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:id', function(req, res, next) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(403);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/:id/password', function(req, res, next) {
|
||||
var user = req.user;
|
||||
var old_password = req.body.old_password;
|
||||
var pass = req.body.new_password;
|
||||
|
||||
if (pass.length >= 6) {
|
||||
if (user._id == req.params.id) {
|
||||
if (bcrypt.compareSync(old_password, user.password_hash)) {
|
||||
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{
|
||||
res.sendStatus(204);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
res.status(403).json({"error": "old password wrong"});
|
||||
}
|
||||
} else {
|
||||
res.status(403).json({"error": "wrong user"});
|
||||
}
|
||||
} else {
|
||||
res.status(400).json({"error": "password_to_short"});
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:id', (req, res, next) => {
|
||||
const user = req.user;
|
||||
if(user._id == req.params.id) {
|
||||
if (user.account_type == 'email') {
|
||||
if (bcrypt.compareSync(req.query.password, user.password_hash)) {
|
||||
user.remove((err) => {
|
||||
if(err)res.status(400).json(err);
|
||||
else res.sendStatus(204);
|
||||
});
|
||||
} else {
|
||||
res.bad_request("password_incorrect");
|
||||
}
|
||||
} else {
|
||||
user.remove((err) => {
|
||||
if(err)res.status(400).json(err);
|
||||
else res.sendStatus(204);
|
||||
});
|
||||
}
|
||||
}
|
||||
else res.status(403).json({error: ""});
|
||||
});
|
||||
|
||||
router.put('/:user_id/confirm', (req, res) => {
|
||||
const token = req.body.token;
|
||||
const user = req.user;
|
||||
|
||||
if (user.confirmation_token === token) {
|
||||
user.confirmation_token = null;
|
||||
user.confirmed_at = new Date();
|
||||
user.save(function(err, updatedUser) {
|
||||
if(err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
res.status(200).json(updatedUser);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(400);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/:user_id/avatar', (req, res, next) => {
|
||||
const user = req.user;
|
||||
const filename = "u"+req.user._id+"_"+(new Date().getTime())+".jpeg"
|
||||
|
||||
const localFilePath = "/tmp/"+filename;
|
||||
const localResizedFilePath = "/tmp/resized_"+filename;
|
||||
const writeStream = fs.createWriteStream(localFilePath);
|
||||
const stream = req.pipe(writeStream);
|
||||
|
||||
req.on('end', function() {
|
||||
gm(localFilePath).resize(200, 200).autoOrient().write(localResizedFilePath, (err) => {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
uploader.uploadFile(filename, "image/jpeg", localResizedFilePath, (err, url) => {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
user.avatar_thumb_uri = url;
|
||||
user.save((err, updatedUser) => {
|
||||
if (err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
fs.unlink(localResizedFilePath, (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
res.status(200).json(updatedUser);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/feedback', function(req, res, next) {
|
||||
var text = req.body.text;
|
||||
// FIXME
|
||||
mailer.sendMail("support@example.org", "Support Request by " + req.user.email, text, {reply_to: req.user.email});
|
||||
res.sendStatus(201);
|
||||
});
|
||||
|
||||
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 {
|
||||
if (user) {
|
||||
if(user.account_type == "email") {
|
||||
crypo.randomBytes(16, (ex, buf) => {
|
||||
user.password_reset_token = buf.toString('hex');
|
||||
user.save((err, updatedUser) => {
|
||||
if (err) res.status(400).json(err);
|
||||
else {
|
||||
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"});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/password_reset_requests/:confirm_token/confirm', function(req, res, next) {
|
||||
var password = req.body.password;
|
||||
|
||||
User
|
||||
.findOne({"password_reset_token": req.params.confirm_token})
|
||||
.exec((err, user) => {
|
||||
if (err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
if(user) {
|
||||
bcrypt.genSalt(10, (err, salt) => {
|
||||
bcrypt.hash(password, salt, function(err, hash) {
|
||||
|
||||
user.password_hash = hash;
|
||||
user.password_token = null;
|
||||
user.save(function(err, updatedUser){
|
||||
if (err) {
|
||||
res.sendStatus(400);
|
||||
} else {
|
||||
res.sendStatus(201);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/:user_id/confirm', function(req, res, next) {
|
||||
mailer.sendMail(req.user.email, req.i18n.__("confirm_subject"), req.i18n.__("confirm_body"), { action:{
|
||||
link: config.endpoint + "/confirm/" + req.user.confirmation_token,
|
||||
name: req.i18n.__("confirm_action")
|
||||
}});
|
||||
res.sendStatus(201);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
74
routes/api/webgrabber.js
Normal file
74
routes/api/webgrabber.js
Normal file
@@ -0,0 +1,74 @@
|
||||
"use strict";
|
||||
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var fs = require('fs');
|
||||
var phantom = require('node-phantom-simple');
|
||||
var md5 = require('md5');
|
||||
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
function website_to_png(url,on_success,on_error) {
|
||||
var hash = md5(url);
|
||||
var export_path = "/tmp/webgrabber-"+hash+".png";
|
||||
|
||||
var timeout = 2000;
|
||||
|
||||
console.log("[webgrabber] url: "+url);
|
||||
console.log("[webgrabber] export_path: "+export_path);
|
||||
|
||||
var on_success_called = false;
|
||||
|
||||
var on_exit = function(exit_code) {
|
||||
if (exit_code>0) {
|
||||
console.log("[phantom-webgrabber] abnormal exit for url "+url);
|
||||
if (!on_success_called && on_error) {
|
||||
on_error();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fs.stat(export_path, function(err, stat) {
|
||||
if (!err) {
|
||||
// file exists
|
||||
console.log("[webgrabber] serving cached snapshot of url: "+url);
|
||||
on_success(export_path);
|
||||
} else {
|
||||
phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) {
|
||||
return browser.createPage(function (err, page) {
|
||||
page.set('settings.resourceTimeout',timeout);
|
||||
page.set('settings.javascriptEnabled',false);
|
||||
|
||||
return page.open(url, function(err, status) {
|
||||
console.log("[webgrabber] status: "+status);
|
||||
page.render(export_path, function() {
|
||||
on_success_called = true;
|
||||
on_success(export_path);
|
||||
browser.exit();
|
||||
});
|
||||
});
|
||||
});
|
||||
}, {
|
||||
onExit: on_exit
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
router.get('/:id', function (req, res) {
|
||||
var uri = new Buffer(req.params.id, "base64")+"";
|
||||
var on_success_called = false;
|
||||
|
||||
website_to_png(uri, (image_path) => {
|
||||
on_success_called = true;
|
||||
res.sendFile(image_path);
|
||||
}, () => {
|
||||
if (!on_success_called) {
|
||||
res.status(500).send("[webgrabber] Error fetching website.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user