2017-04-07 01:29:05 +02:00
|
|
|
"use strict";
|
|
|
|
var config = require('config');
|
2018-05-03 15:35:51 +02:00
|
|
|
const os = require('os');
|
2018-04-12 18:40:58 +02:00
|
|
|
const db = require('../../models/db');
|
|
|
|
const Sequelize = require('sequelize');
|
|
|
|
const Op = Sequelize.Op;
|
|
|
|
const uuidv4 = require('uuid/v4');
|
2017-04-07 01:29:05 +02:00
|
|
|
|
|
|
|
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 request = require('request');
|
|
|
|
var url = require("url");
|
|
|
|
var path = require("path");
|
|
|
|
var crypto = require('crypto');
|
|
|
|
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 {
|
2020-04-09 14:15:48 +02:00
|
|
|
if (req.query.search) {
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Membership.findAll({where:{
|
|
|
|
user_id: req.user._id
|
|
|
|
}}).then(memberships => {
|
2020-04-09 17:26:58 +02:00
|
|
|
// search for spaces
|
|
|
|
|
2017-04-07 01:29:05 +02:00
|
|
|
var validMemberships = memberships.filter(function(m) {
|
2018-04-12 18:40:58 +02:00
|
|
|
if (!m.space_id || (m.space_id == "undefined"))
|
2017-04-07 01:29:05 +02:00
|
|
|
return false;
|
|
|
|
else
|
2018-04-12 18:40:58 +02:00
|
|
|
return true;
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
var spaceIds = validMemberships.map(function(m) {
|
2018-04-12 18:40:58 +02:00
|
|
|
return m.space_id;
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
// TODO FIXME port
|
|
|
|
var q = { where: {
|
|
|
|
[Op.or]: [{"creator_id": req.user._id},
|
|
|
|
{"_id": {[Op.in]: spaceIds}},
|
|
|
|
{"parent_space_id": {[Op.in]: spaceIds}}],
|
|
|
|
name: {[Op.like]: "%"+req.query.search+"%"}
|
|
|
|
}, include: ['creator']};
|
|
|
|
|
|
|
|
db.Space
|
|
|
|
.findAll(q)
|
|
|
|
.then(function(spaces) {
|
2017-04-07 01:29:05 +02:00
|
|
|
res.status(200).json(spaces);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
} else if (req.query.parent_space_id && req.query.parent_space_id != req.user.home_folder_id) {
|
2020-04-09 17:26:58 +02:00
|
|
|
// list spaces in a folder
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Space
|
|
|
|
.findOne({where: {
|
2017-04-07 01:29:05 +02:00
|
|
|
_id: req.query.parent_space_id
|
2018-04-12 18:40:58 +02:00
|
|
|
}})
|
|
|
|
//.populate('creator', userMapping)
|
|
|
|
.then(function(space) {
|
2017-04-07 01:29:05 +02:00
|
|
|
if (space) {
|
2018-04-12 18:40:58 +02:00
|
|
|
db.getUserRoleInSpace(space, req.user, function(role) {
|
2017-04-07 01:29:05 +02:00
|
|
|
if (role == "none") {
|
2018-04-12 18:40:58 +02:00
|
|
|
if (space.access_mode == "public") {
|
2017-04-07 01:29:05 +02:00
|
|
|
role = "viewer";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (role != "none") {
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Space
|
|
|
|
.findAll({where:{
|
2017-04-07 01:29:05 +02:00
|
|
|
parent_space_id: req.query.parent_space_id
|
2018-04-12 18:40:58 +02:00
|
|
|
}, include:['creator']})
|
|
|
|
.then(function(spaces) {
|
2017-04-07 01:29:05 +02:00
|
|
|
res.status(200).json(spaces);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
res.status(403).json({"error": "no authorized"});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
res.status(404).json({"error": "space not found"});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
2020-04-09 17:26:58 +02:00
|
|
|
// list home folder and spaces/folders that the user is a member of
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Membership.findAll({ where: {
|
|
|
|
user_id: req.user._id
|
|
|
|
}}).then(memberships => {
|
|
|
|
if (!memberships) memberships = [];
|
2020-04-09 17:26:58 +02:00
|
|
|
|
2017-04-07 01:29:05 +02:00
|
|
|
var validMemberships = memberships.filter(function(m) {
|
2018-04-12 18:40:58 +02:00
|
|
|
if (!m.space_id || (m.space_id == "undefined"))
|
2017-04-07 01:29:05 +02:00
|
|
|
return false;
|
2020-04-09 17:26:58 +02:00
|
|
|
return true;
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
var spaceIds = validMemberships.map(function(m) {
|
2018-04-12 18:40:58 +02:00
|
|
|
return m.space_id;
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
var q = {
|
2018-04-12 18:40:58 +02:00
|
|
|
[Op.or]: [{
|
|
|
|
"creator_id": req.user._id,
|
2017-04-07 01:29:05 +02:00
|
|
|
"parent_space_id": req.user.home_folder_id
|
|
|
|
}, {
|
|
|
|
"_id": {
|
2018-04-12 18:40:58 +02:00
|
|
|
[Op.in]: spaceIds
|
2017-04-07 01:29:05 +02:00
|
|
|
},
|
2018-04-12 18:40:58 +02:00
|
|
|
"creator_id": {
|
|
|
|
[Op.ne]: req.user._id
|
2017-04-07 01:29:05 +02:00
|
|
|
}
|
|
|
|
}]
|
|
|
|
};
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Space
|
|
|
|
.findAll({where: q, include: ['creator']})
|
|
|
|
.then(function(spaces) {
|
2017-04-07 01:29:05 +02:00
|
|
|
var updatedSpaces = spaces.map(function(s) {
|
2018-04-12 18:40:58 +02:00
|
|
|
var spaceObj = db.spaceToObject(s);
|
2017-04-07 01:29:05 +02:00
|
|
|
return spaceObj;
|
|
|
|
});
|
|
|
|
res.status(200).json(spaces);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
// create a space
|
2017-04-07 01:29:05 +02:00
|
|
|
router.post('/', function(req, res, next) {
|
|
|
|
if (req.user) {
|
|
|
|
var attrs = req.body;
|
|
|
|
|
|
|
|
var createSpace = () => {
|
2018-04-12 18:40:58 +02:00
|
|
|
attrs._id = uuidv4();
|
|
|
|
attrs.creator_id = req.user._id;
|
2017-04-07 01:29:05 +02:00
|
|
|
attrs.edit_hash = crypto.randomBytes(64).toString('hex').substring(0, 7);
|
|
|
|
attrs.edit_slug = slug(attrs.name);
|
2020-04-09 15:23:14 +02:00
|
|
|
attrs.access_mode = "private";
|
2017-04-07 01:29:05 +02:00
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Space.create(attrs).then(createdSpace => {
|
2020-04-09 14:55:18 +02:00
|
|
|
res.status(201).json(createdSpace);
|
|
|
|
|
|
|
|
// create initial admin membership
|
2018-04-12 18:40:58 +02:00
|
|
|
var membership = {
|
|
|
|
_id: uuidv4(),
|
|
|
|
user_id: req.user._id,
|
|
|
|
space_id: attrs._id,
|
2020-04-09 14:55:18 +02:00
|
|
|
role: "admin",
|
|
|
|
state: "active"
|
2018-04-12 18:40:58 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
db.Membership.create(membership).then(() => {
|
|
|
|
res.status(201).json(createdSpace);
|
|
|
|
});
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attrs.parent_space_id) {
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Space.findOne({ where: {
|
2017-04-07 01:29:05 +02:00
|
|
|
"_id": attrs.parent_space_id
|
2018-04-12 18:40:58 +02:00
|
|
|
}}).then(parentSpace => {
|
2017-04-07 01:29:05 +02:00
|
|
|
if (parentSpace) {
|
2018-04-12 18:40:58 +02:00
|
|
|
db.getUserRoleInSpace(parentSpace, req.user, (role) => {
|
2017-04-07 01:29:05 +02:00
|
|
|
if ((role == "editor") || (role == "admin")) {
|
|
|
|
createSpace();
|
|
|
|
} else {
|
|
|
|
res.status(403).json({
|
2018-04-12 18:40:58 +02:00
|
|
|
"error": "not editor in parent Space. role: "+role
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} 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);
|
|
|
|
});
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
router.get('/:id/path', (req, res) => {
|
|
|
|
// build up a breadcrumb trail (path)
|
|
|
|
var path = [];
|
|
|
|
var buildPath = (space) => {
|
|
|
|
if (space.parent_space_id) {
|
|
|
|
db.Space.findOne({ where: {
|
|
|
|
"_id": space.parent_space_id
|
|
|
|
}}).then(parentSpace => {
|
|
|
|
if (space._id == parentSpace._id) {
|
|
|
|
console.error("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);
|
|
|
|
});
|
|
|
|
|
2017-04-07 01:29:05 +02:00
|
|
|
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'];
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Space.update(newAttr, {where: {
|
2017-04-07 01:29:05 +02:00
|
|
|
"_id": space._id
|
2018-04-12 18:40:58 +02:00
|
|
|
}}).then(space => {
|
|
|
|
res.distributeUpdate("Space", space);
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
router.post('/:id/background', function(req, res, next) {
|
|
|
|
var space = req.space;
|
|
|
|
var newDate = new Date();
|
2018-04-12 18:40:58 +02:00
|
|
|
var fileName = (req.query.filename || "upload.jpg").replace(/[^a-zA-Z0-9\.]/g, '');
|
2017-04-07 01:29:05 +02:00
|
|
|
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 {
|
2018-04-12 18:40:58 +02:00
|
|
|
if (space.background_uri) {
|
|
|
|
var oldPath = url.parse(req.space.background_uri).pathname;
|
2017-04-07 01:29:05 +02:00
|
|
|
uploader.removeFile(oldPath, function(err) {
|
2018-04-12 18:40:58 +02:00
|
|
|
console.error("removed old bg error:", err);
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-04-12 18:40:58 +02:00
|
|
|
db.Space.update({
|
|
|
|
background_uri: backgroundUrl
|
2017-04-07 01:29:05 +02:00
|
|
|
}, {
|
2018-04-12 18:40:58 +02:00
|
|
|
where: { "_id": space._id }
|
|
|
|
}, function(rows) {
|
|
|
|
fs.unlink(localFilePath, function(err) {
|
|
|
|
if (err) {
|
|
|
|
console.error(err);
|
|
|
|
res.status(400).json(err);
|
|
|
|
} else {
|
|
|
|
res.status(200).json(space);
|
|
|
|
}
|
|
|
|
});
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
router.delete('/:id', function(req, res, next) {
|
|
|
|
if (req.user) {
|
|
|
|
const space = req.space;
|
|
|
|
|
|
|
|
if (req.spaceRole == "admin") {
|
|
|
|
const attrs = req.body;
|
2018-04-12 18:40:58 +02:00
|
|
|
space.destroy().then(function() {
|
|
|
|
res.distributeDelete("Space", space);
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
res.status(403).json({
|
2018-04-12 18:40:58 +02:00
|
|
|
"error": "requires admin role"
|
2017-04-07 01:29:05 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
res.sendStatus(403);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = router;
|