diff --git a/app.js b/app.js index 004fb5a..8b3e80b 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,6 @@ "use strict"; -require('./models/schema'); +const db = require('./models/db.js'); require("log-timestamp"); const config = require('config'); @@ -16,7 +16,7 @@ const logger = require('morgan'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); -const mongoose = require('mongoose'); +//const mongoose = require('mongoose'); const swig = require('swig'); const i18n = require('i18n-2'); @@ -81,33 +81,30 @@ app.use(helmet.noSniff()) // CUSTOM MIDDLEWARES -app.use(require("./middlewares/templates")); -app.use(require("./middlewares/error_helpers")); -app.use(require("./middlewares/setuser")); -app.use(require("./middlewares/cors")); -app.use(require("./middlewares/i18n")); +//app.use(require("./middlewares/error_helpers")); +app.use(require("./middlewares/session")); +//app.use(require("./middlewares/cors")); +//app.use(require("./middlewares/i18n")); app.use("/api", require("./middlewares/api_helpers")); app.use('/api/spaces/:id', require("./middlewares/space_helpers")); app.use('/api/spaces/:id/artifacts/:artifact_id', require("./middlewares/artifact_helpers")); -app.use('/api/teams', require("./middlewares/team_helpers")); // REAL ROUTES app.use('/api/users', require('./routes/api/users')); -app.use('/api/memberships', require('./routes/api/memberships')); +//app.use('/api/memberships', require('./routes/api/memberships')); const spaceRouter = require('./routes/api/spaces'); app.use('/api/spaces', spaceRouter); spaceRouter.use('/:id/artifacts', require('./routes/api/space_artifacts')); spaceRouter.use('/:id/memberships', require('./routes/api/space_memberships')); -spaceRouter.use('/:id/messages', require('./routes/api/space_messages')); +//spaceRouter.use('/:id/messages', require('./routes/api/space_messages')); spaceRouter.use('/:id/digest', require('./routes/api/space_digest')); -spaceRouter.use('/:id', require('./routes/api/space_exports')); +//spaceRouter.use('/:id', require('./routes/api/space_exports')); app.use('/api/sessions', require('./routes/api/sessions')); -app.use('/api/teams', require('./routes/api/teams')); -app.use('/api/webgrabber', require('./routes/api/webgrabber')); +//app.use('/api/webgrabber', require('./routes/api/webgrabber')); app.use('/', require('./routes/root')); if (config.get('storage_local_path')) { @@ -117,7 +114,7 @@ if (config.get('storage_local_path')) { } // catch 404 and forward to error handler -app.use(require('./middlewares/404')); +//app.use(require('./middlewares/404')); if (app.get('env') == 'development') { app.set('view cache', false); swig.setDefaults({cache: false}); @@ -128,8 +125,9 @@ if (app.get('env') == 'development') { module.exports = app; // CONNECT TO DATABASE -const mongoHost = process.env.MONGO_PORT_27017_TCP_ADDR || config.get('mongodb_host'); -mongoose.connect('mongodb://' + mongoHost + '/spacedeck'); +//const mongoHost = process.env.MONGO_PORT_27017_TCP_ADDR || config.get('mongodb_host'); +//mongoose.connect('mongodb://' + mongoHost + '/spacedeck'); +db.init(); // START WEBSERVER const port = 9666; @@ -174,7 +172,7 @@ redis.connectRedis(); process.on('message', (message) => { console.log("Process message:", message); if (message === 'shutdown') { - console.log("Exiting spacedeck."); + console.log("Exiting Spacedeck."); process.exit(0); } }); diff --git a/helpers/artifact_converter.js b/helpers/artifact_converter.js index d6f468d..5ce5801 100644 --- a/helpers/artifact_converter.js +++ b/helpers/artifact_converter.js @@ -4,11 +4,15 @@ const exec = require('child_process'); const gm = require('gm'); const async = require('async'); const fs = require('fs'); -const Models = require('../models/schema'); +const Models = require('../models/db'); const uploader = require('../helpers/uploader'); const path = require('path'); const os = require('os'); +const db = require('../models/db'); +const Sequelize = require('sequelize'); +const Op = Sequelize.Op; + const fileExtensionMap = { ".amr" : "audio/AMR", ".ogg" : "audio/ogg", @@ -301,25 +305,20 @@ var resizeAndUploadImage = function(a, mime, size, fileName, fileNameOrg, imageF a.payload_uri = results.original; var factor = 320/size.width; - var newBoardSpecs = a.board; - newBoardSpecs.w = Math.round(size.width*factor); - newBoardSpecs.h = Math.round(size.height*factor); - a.board = newBoardSpecs; + a.w = Math.round(size.width*factor); + a.h = Math.round(size.height*factor); a.updated_at = new Date(); - a.save(function(err) { - if(err) payloadCallback(err, null); - else { - fs.unlink(originalFilePath, function (err) { - if (err){ - console.error(err); - payloadCallback(err, null); - } else { - console.log('successfully deleted ' + originalFilePath); - payloadCallback(null, a); - } - }); - } + a.save().then(function() { + fs.unlink(originalFilePath, function (err) { + if (err){ + console.error(err); + payloadCallback(err, null); + } else { + console.log('successfully deleted ' + originalFilePath); + payloadCallback(null, a); + } + }); }); }); }; @@ -371,25 +370,20 @@ module.exports = { a.payload_uri = url; var factor = 320/size.width; - var newBoardSpecs = a.board; - newBoardSpecs.w = Math.round(size.width*factor); - newBoardSpecs.h = Math.round(size.height*factor); - a.board = newBoardSpecs; + a.w = Math.round(size.width*factor); + a.h = Math.round(size.height*factor); a.updated_at = new Date(); - a.save(function(err){ - if(err) payloadCallback(err, null); - else { - fs.unlink(localFilePath, function (err) { - if (err){ - console.error(err); - payloadCallback(err, null); - } else { - console.log('successfully deleted ' + localFilePath); - payloadCallback(null, a); - } - }); - } + a.save().then(function() { + fs.unlink(localFilePath, function (err) { + if (err){ + console.error(err); + payloadCallback(err, null); + } else { + console.log('successfully deleted ' + localFilePath); + payloadCallback(null, a); + } + }); }); } }); @@ -483,6 +477,8 @@ module.exports = { ]; } + db.packArtifact(a); + a.updated_at = new Date(); a.save(function(err) { if (err) payloadCallback(err, null); @@ -564,19 +560,19 @@ module.exports = { ]; a.updated_at = new Date(); - a.save(function(err){ - if(err) payloadCallback(err, null); - else { - fs.unlink(localFilePath, function (err) { - if (err){ - console.error(err); - payloadCallback(err, null); - } else { - console.log('successfully deleted ' + localFilePath); - payloadCallback(null, a); - } - }); - } + + db.packArtifact(a); + + a.save().then(function(){ + fs.unlink(localFilePath, function (err) { + if (err){ + console.error(err); + payloadCallback(err, null); + } else { + console.log('successfully deleted ' + localFilePath); + payloadCallback(null, a); + } + }); }); } }); @@ -594,13 +590,10 @@ module.exports = { a.payload_uri = url; a.updated_at = new Date(); - a.save(function(err) { - if(err) payloadCallback(err, null); - else { - fs.unlink(localFilePath, function (err) { - payloadCallback(null, a); - }); - } + a.save().then(function() { + fs.unlink(localFilePath, function (err) { + payloadCallback(null, a); + }); }); }); } diff --git a/helpers/importer.js b/helpers/importer.js index 90eb2a9..2277787 100644 --- a/helpers/importer.js +++ b/helpers/importer.js @@ -5,7 +5,7 @@ const config = require('config') const fs = require('fs') const path = require('path') -require('../models/schema') +require('../models/db') module.exports = { importZIP: function(user, zipPath) { diff --git a/helpers/phantom.js b/helpers/phantom.js index ed897f5..01f9fb3 100644 --- a/helpers/phantom.js +++ b/helpers/phantom.js @@ -1,6 +1,6 @@ 'use strict'; -require('../models/schema'); +require('../models/db'); var config = require('config'); var phantom = require('node-phantom-simple'); diff --git a/helpers/websockets.js b/helpers/websockets.js index d541ede..23caebd 100644 --- a/helpers/websockets.js +++ b/helpers/websockets.js @@ -1,5 +1,8 @@ 'use strict'; -require('../models/schema'); + +const db = require('../models/db'); +const Sequelize = require('sequelize'); +const Op = Sequelize.Op; const config = require('config'); @@ -8,7 +11,6 @@ const WebSocketServer = require('ws').Server; const RedisConnection = require('ioredis'); const async = require('async'); const _ = require("underscore"); -const mongoose = require("mongoose"); const crypto = require('crypto'); const redisMock = require("./redis.js"); @@ -45,11 +47,11 @@ module.exports = { const editorAuth = msg.editor_auth; const spaceId = msg.space_id; - Space.findOne({"_id": spaceId}).populate('creator').exec((err, space) => { + db.Space.findOne({where: {"_id": spaceId}}).then(space => { if (space) { const upgradeSocket = function() { if (token) { - User.findBySessionToken(token, function(err, user) { + db.findUserBySessionToken(token, function(err, user) { if (err) { console.error(err, user); } else { @@ -268,10 +270,10 @@ module.exports = { }, distributeUsers: function(spaceId) { - if(!spaceId) + if (!spaceId) return; - this.state.smembers("space_" + spaceId, function(err, list) { + /*this.state.smembers("space_" + spaceId, function(err, list) { async.map(list, function(item, callback) { this.state.get(item, function(err, userId) { console.log(item, "->", userId); @@ -292,16 +294,14 @@ module.exports = { return {nickname: realNickname, email: null, avatar_thumbnail_uri: null }; }); - User.find({"_id" : { "$in" : validUserIds }}, { "nickname" : 1 , "email" : 1, "avatar_thumbnail_uri": 1 }, function(err, users) { - if (err) - console.error(err); - else { + db.User.findAll({where: { + "_id" : { "$in" : validUserIds }}, attributes: ["nickname","email","avatar_thumbnail_uri"]}) + .then(users) { const allUsers = users.concat(anonymousUsers); const strUsers = JSON.stringify({users: allUsers, space_id: spaceId}); this.state.publish("users", strUsers); - } - }.bind(this)); + }.bind(this)); }.bind(this)); - }.bind(this)); + }.bind(this));*/ } }; diff --git a/middlewares/404.js b/middlewares/404.js index ac38434..2854608 100644 --- a/middlewares/404.js +++ b/middlewares/404.js @@ -1,6 +1,6 @@ 'use strict'; -require('../models/schema'); +require('../models/db'); var config = require('config'); module.exports = (req, res, next) => { @@ -16,4 +16,4 @@ module.exports = (req, res, next) => { } else { res.status(404).send("Not Found."); } -} \ No newline at end of file +} diff --git a/middlewares/api_helpers.js b/middlewares/api_helpers.js index e6c844a..893f35f 100644 --- a/middlewares/api_helpers.js +++ b/middlewares/api_helpers.js @@ -1,9 +1,11 @@ 'use strict'; -require('../models/schema'); +require('../models/db'); var config = require('config'); const redis = require('../helpers/redis'); +// FIXME TODO object.toJSON() + var saveAction = (actionKey, object) => { if (object.constructor.modelName == "Space") return; @@ -13,14 +15,14 @@ var saveAction = (actionKey, object) => { space: object.space_id || object.space, user: object.user_id || object.user, editor_name: object.editor_name, - object: object.toJSON() + object: object }; - let action = new Action(attr); + /*let action = new Action(attr); action.save(function(err) { if (err) console.error("saved create action err:", err); - }); + });*/ }; module.exports = (req, res, next) => { @@ -32,21 +34,21 @@ module.exports = (req, res, next) => { res['distributeCreate'] = function(model, object) { if (!object) return; - redis.sendMessage("create", model, object.toJSON(), req.channelId); - this.status(201).json(object.toJSON()); + redis.sendMessage("create", model, object, req.channelId); + this.status(201).json(object); saveAction("create", object); }; res['distributeUpdate'] = function(model, object) { if (!object) return; - redis.sendMessage("update", model, object.toJSON(), req.channelId); - this.status(200).json(object.toJSON()); + redis.sendMessage("update", model, object, req.channelId); + this.status(200).json(object); saveAction("update", object); }; res['distributeDelete'] = function(model, object) { if (!object) return; - redis.sendMessage("delete", model, object.toJSON(), req.channelId); + redis.sendMessage("delete", model, object, req.channelId); this.sendStatus(204); saveAction("delete", object); }; diff --git a/middlewares/artifact_helpers.js b/middlewares/artifact_helpers.js index 4df5d58..b436150 100644 --- a/middlewares/artifact_helpers.js +++ b/middlewares/artifact_helpers.js @@ -1,22 +1,20 @@ 'use strict'; +const db = require('../models/db'); +const Sequelize = require('sequelize'); +const Op = Sequelize.Op; -require('../models/schema'); var config = require('config'); module.exports = (req, res, next) => { var artifactId = req.params.artifact_id; - Artifact.findOne({ + db.Artifact.findOne({where: { "_id": artifactId - }, (err, artifact) => { - if (err) { - res.status(400).json(err); + }}).then(artifact => { + if (artifact) { + req['artifact'] = artifact; + next(); } else { - if (artifact) { - req['artifact'] = artifact; - next(); - } else { - res.sendStatus(404); - } + res.sendStatus(404); } }); -}; \ No newline at end of file +}; diff --git a/middlewares/cors.js b/middlewares/cors.js index 09c4875..d5b0900 100644 --- a/middlewares/cors.js +++ b/middlewares/cors.js @@ -1,6 +1,6 @@ 'use strict'; -require('../models/schema'); +require('../models/db'); const config = require('config'); const url = require('url'); @@ -26,20 +26,20 @@ module.exports = (req, res, next) => { const parsedUrl = url.parse(origin, true, true); // FIXME - if (parsedUrl.hostname == "cdn.spacedeck.com") { + if (parsedUrl.hostname == "cdn.spacedeck.com") { res.header('Cache-Control', "max-age"); res.header('Expires', "30d"); res.removeHeader("Pragma"); respond(origin, req, res, next); } else { - Team.getTeamForHost(parsedUrl.hostname, (err, team, subdomain) => { - if (team) { + //Team.getTeamForHost(parsedUrl.hostname, (err, team, subdomain) => { + //if (team) { respond(origin, req, res, next); - } else { + //} else { next(); - } - }); + //} + //}); } } else { diff --git a/middlewares/i18n.js b/middlewares/i18n.js index a28203b..f330312 100644 --- a/middlewares/i18n.js +++ b/middlewares/i18n.js @@ -1,6 +1,6 @@ 'use strict'; -require('../models/schema'); +require('../models/db'); var config = require('config'); module.exports = (req, res, next) => { @@ -14,4 +14,4 @@ module.exports = (req, res, next) => { req.i18n.setLocale(req.user.preferences.language); } next(); -} \ No newline at end of file +} diff --git a/middlewares/session.js b/middlewares/session.js new file mode 100644 index 0000000..3060637 --- /dev/null +++ b/middlewares/session.js @@ -0,0 +1,46 @@ +'use strict'; + +const db = require('../models/db'); +var config = require('config'); + +module.exports = (req, res, next) => { + const token = req.cookies["sdsession"]; + + if (token && token != "null" && token != null) { + db.Session.findOne({where: {token: token}}) + .then(session => { + if (!session) { + // session not found + next(); + } + else db.User.findOne({where: {_id: session.user_id}}) + .then(user => { + if (!user) { + res.clearCookie('sdsession'); + + if (req.accepts("text/html")) { + res.send("Please clear your cookies and try again."); + } else if (req.accepts('application/json')) { + res.status(403).json({ + "error": "token_not_found" + }); + } else { + res.send("Please clear your cookies and try again."); + } + + } else { + req["token"] = token; + req["user"] = user; + next(); + } + }); + }) + .error(err => { + console.error("Session resolve error",err); + next(); + }); + } else { + next(); + } +} + diff --git a/middlewares/setuser.js b/middlewares/setuser.js deleted file mode 100644 index 56bcd78..0000000 --- a/middlewares/setuser.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -require('../models/schema'); -var config = require('config'); - -module.exports = (req, res, next) => { - const token = req.cookies["sdsession"]; - - if (token && token != "null" && token !== null) { - User.findOne({ - "sessions.token": token - }).populate('team').exec((err, user) => { - if (err) console.error("session.token lookup error:",err); - if (!user) { - res.clearCookie('sdsession'); - - if (req.accepts("text/html")) { - res.send("Please clear your cookies and try again."); - } else if (req.accepts('application/json')) { - res.status(403).json({ - "error": "token_not_found" - }); - } else { - res.send("Please clear your cookies and try again."); - } - } else { - req["token"] = token; - req["user"] = user; - next(); - } - }); - } else { - next(); - } -} diff --git a/middlewares/space_helpers.js b/middlewares/space_helpers.js index 96a9357..07e5931 100644 --- a/middlewares/space_helpers.js +++ b/middlewares/space_helpers.js @@ -1,6 +1,6 @@ 'use strict'; -require('../models/schema'); +const db = require('../models/db'); var config = require('config'); module.exports = (req, res, next) => { @@ -19,50 +19,6 @@ module.exports = (req, res, next) => { } }; - var rolePerUser = (originalSpace, user, cb) => { - originalSpace.path = []; - - if (originalSpace._id.equals(req.user.home_folder_id) || (originalSpace.creator && originalSpace.creator._id.equals(req.user._id))) { - cb("admin"); - } else { - var findMembershipsForSpace = function(space, allMemberships, prevRole) { - Membership.find({ - "space": space._id - }, function(err, parentMemberships) { - var currentMemberships = parentMemberships.concat(allMemberships); - - if (space.parent_space_id) { - Space.findOne({ - "_id": space.parent_space_id - }, function(err, parentSpace) { - findMembershipsForSpace(parentSpace, currentMemberships, prevRole); - }); - } else { - // reached the top - - var role = prevRole; - space.memberships = currentMemberships; - - if(role == "none"){ - if(originalSpace.access_mode == "public") { - role = "viewer"; - } - } - - currentMemberships.forEach(function(m, i) { - if (m.user && m.user.equals(user._id)) { - role = m.role; - } - }); - - cb(role); - } - }); - }; - findMembershipsForSpace(originalSpace, [], "none"); - } - }; - var finalizeAnonymousLogin = function(space, spaceAuth) { var role = "none"; @@ -77,7 +33,7 @@ module.exports = (req, res, next) => { } if (req.user) { - rolePerUser(space, req.user, function(newRole) { + db.getUserRoleInSpace(space, req.user, function(newRole) { if (newRole == "admin" && (role == "editor" || role == "viewer")) { finalizeReq(space, newRole); } else if (newRole == "editor" && (role == "viewer")) { @@ -97,64 +53,66 @@ module.exports = (req, res, next) => { 'email': 1 }; - Space.findOne({ + db.Space.findOne({where: { "_id": spaceId - }).populate("creator", userMapping).exec(function(err, space) { - if (err) { - res.status(400).json(err); - } else { - if (space) { + }}).then(function(space) { - if (space.access_mode == "public") { + //.populate("creator", userMapping) + //if (err) { + // res.status(400).json(err); + //} else { - if (space.password) { - if (req.spacePassword) { - if (req.spacePassword === space.password) { - finalizeAnonymousLogin(space, req["spaceAuth"]); - } else { - res.status(403).json({ - "error": "password_wrong" - }); - } - } else { - res.status(401).json({ - "error": "password_required" - }); - } - } else { - finalizeAnonymousLogin(space, req["spaceAuth"]); - } - - } else { - // special permission for screenshot/pdf export from backend - if (req.query['api_token'] && req.query['api_token'] == config.get('phantom_api_secret')) { - finalizeReq(space, "viewer"); - return; - } - - if (req.user) { - rolePerUser(space, req.user, function(role) { - if (role == "none") { - finalizeAnonymousLogin(space, req["spaceAuth"]); - } else { - finalizeReq(space, role); - } - }); - } else { - if (req.spaceAuth && space.edit_hash) { + if (space) { + if (space.access_mode == "public") { + if (space.password) { + if (req.spacePassword) { + if (req.spacePassword === space.password) { finalizeAnonymousLogin(space, req["spaceAuth"]); } else { res.status(403).json({ - "error": "auth_required" + "error": "password_wrong" }); } + } else { + res.status(401).json({ + "error": "password_required" + }); + } + } else { + finalizeAnonymousLogin(space, req["spaceAuth"]); + } + + } else { + // space is private + + // special permission for screenshot/pdf export from backend + if (req.query['api_token'] && req.query['api_token'] == config.get('phantom_api_secret')) { + finalizeReq(space, "viewer"); + return; + } + + if (req.user) { + db.getUserRoleInSpace(space, req.user, function(role) { + if (role == "none") { + finalizeAnonymousLogin(space, req["spaceAuth"]); + } else { + finalizeReq(space, role); + } + }); + } else { + if (req.spaceAuth && space.edit_hash) { + finalizeAnonymousLogin(space, req["spaceAuth"]); + } else { + res.status(403).json({ + "error": "auth_required" + }); } } - } else { - res.status(404).json({ - "error": "space_not_found" - }); } + } else { + res.status(404).json({ + "error": "space_not_found" + }); } }); } diff --git a/middlewares/subdomain.js b/middlewares/subdomain.js deleted file mode 100644 index 2ce6a6a..0000000 --- a/middlewares/subdomain.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -require('../models/schema'); -var config = require('config'); - -module.exports = (req, res, next) => { - let host = req.headers.host; - Team.getTeamForHost(host, (err, team, subdomain) => { - if (subdomain) { - if (!err && team) { - req.subdomainTeam = team; - req.subdomain = subdomain; - next() - } else { - if (req.accepts('text/html')) { - res.status(404).render('not_found', { - title: 'Page Not Found.' - }); - } else if (req.accepts('application/json')) { - res.status(404).json({ - "error": "not_found" - }); - } else { - res.status(404).render('not_found', { - title: 'Page Not Found.' - }); - } - } - } else { - next(); - } - }); -} diff --git a/middlewares/team_helpers.js b/middlewares/team_helpers.js deleted file mode 100644 index b072043..0000000 --- a/middlewares/team_helpers.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -require('../models/schema'); -var config = require('config'); - -module.exports = (req, res, next) => { - if (req.user) { - var isAdmin = req.user.team.admins.indexOf(req.user._id) >= 0; - var correctMethod = req.method == "GET" || (req.method == "DELETE" || req.method == "PUT" || req.method == "POST"); - - if (correctMethod && isAdmin) { - next(); - } else { - res.status(403, { - "error": "not authorized" - }); - } - } else { - res.status(403, { - "error": "not logged in" - }); - } -} \ No newline at end of file diff --git a/middlewares/templates.js b/middlewares/templates.js deleted file mode 100644 index 4aebb63..0000000 --- a/middlewares/templates.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -require('../models/schema'); -var config = require('config'); -var _ = require('underscore'); - -module.exports = (req, res, next) => { - res.oldRender = res.render; - res.render = function(template, params) { - - var team = req.subdomainTeam; - if (team) { - team = _.pick(team.toObject(), ['_id', 'name', 'subdomain', 'avatar_original_uri']); - } else { - team = null; - } - - const addParams = { - locale: req.i18n.locale, - config: config, - subdomain_team: team, - user: req.user, - csrf_token: "", - socket_auth: req.token - }; - - const all = _.extend(params, addParams); - res.oldRender(template, all); - }; - next(); -} \ No newline at end of file diff --git a/models/db.js b/models/db.js new file mode 100644 index 0000000..0fa30ac --- /dev/null +++ b/models/db.js @@ -0,0 +1,284 @@ +//'use strict'; + +//var mongoose = require('mongoose'); +//const sqlite3 = require('sqlite3').verbose(); + +function sequel_log(a,b,c) { + console.log(a); +} + +const Sequelize = require('sequelize'); +const sequelize = new Sequelize('database', 'username', 'password', { + host: 'localhost', + dialect: 'sqlite', + + pool: { + max: 5, + min: 0, + acquire: 30000, + idle: 10000 + }, + + // SQLite only + storage: 'database.sqlite', + logging: sequel_log, + + // http://docs.sequelizejs.com/manual/tutorial/querying.html#operators + operatorsAliases: false +}); + +var User; +var Session; +var Space; +var Membership; +var Artifact; +var Message; +var Action; + +module.exports = { + User: sequelize.define('user', { + _id: {type: Sequelize.STRING, primaryKey: true}, + email: Sequelize.STRING, + password_hash: Sequelize.STRING, + nickname: Sequelize.STRING, + avatar_original_uri: Sequelize.STRING, + avatar_thumb_uri: Sequelize.STRING, + confirmation_token: Sequelize.STRING, + password_reset_token: Sequelize.STRING, + home_folder_id: Sequelize.STRING, + prefs_language: Sequelize.STRING, + prefs_email_notifications: Sequelize.STRING, + prefs_email_digest: Sequelize.STRING, + created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW} + }), + + Session: sequelize.define('session', { + token: {type: Sequelize.STRING, primaryKey: true}, + user_id: Sequelize.STRING, + expires: Sequelize.DATE, + created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + device: Sequelize.STRING, + ip: Sequelize.STRING + }), + + Space: sequelize.define('space', { + _id: {type: Sequelize.STRING, primaryKey: true}, + name: {type: Sequelize.STRING, default: "New Space"}, + space_type: {type: Sequelize.STRING, defaultValue: "space"}, + creator_id: Sequelize.STRING, + parent_space_id: Sequelize.STRING, + + access_mode: {type: Sequelize.STRING, default: "private"}, // "public" || "private" + password: Sequelize.STRING, + edit_hash: Sequelize.STRING, + edit_slug: Sequelize.STRING, + editors_locking: Sequelize.BOOLEAN, + + thumbnail_uri: Sequelize.STRING, + + width: Sequelize.INTEGER, + height: Sequelize.INTEGER, + background_color: Sequelize.STRING, + background_uri: Sequelize.STRING, + + created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + thumbnail_url: Sequelize.STRING, + thumbnail_updated_at: {type: Sequelize.DATE} + }), + + Membership: sequelize.define('membership', { + _id: {type: Sequelize.STRING, primaryKey: true}, + space_id: Sequelize.STRING, + user_id: Sequelize.STRING, + role: Sequelize.STRING, + created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW} + }), + + Artifact: sequelize.define('message', { + _id: {type: Sequelize.STRING, primaryKey: true}, + space_id: Sequelize.STRING, + user_id: Sequelize.STRING, + editor_name: Sequelize.STRING, + message: Sequelize.TEXT, + created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW} + }), + + Artifact: sequelize.define('artifact', { + _id: {type: Sequelize.STRING, primaryKey: true}, + space_id: Sequelize.STRING, + user_id: Sequelize.STRING, + + mime: Sequelize.STRING, + thumbnail_uri: Sequelize.STRING, + last_update_user_id: Sequelize.STRING, + editor_name: Sequelize.STRING, + last_update_editor_name: Sequelize.STRING, + description: Sequelize.TEXT, + state: {type: Sequelize.STRING, default: "idle"}, + + //linked_to: Sequelize.STRING, + title: Sequelize.STRING, + tags: Sequelize.TEXT, + search_text: Sequelize.STRING, + link_uri: Sequelize.STRING, + play_from: Sequelize.DECIMAL, + play_to: Sequelize.DECIMAL, + + x: {type: Sequelize.DECIMAL, default: 0.0}, + y: {type: Sequelize.DECIMAL, default: 0.0}, + z: {type: Sequelize.DECIMAL, default: 0.0}, + r: {type: Sequelize.DECIMAL, default: 0.0}, + w: {type: Sequelize.DECIMAL, default: 100}, + h: {type: Sequelize.DECIMAL, default: 100}, + + //control_points: [{ + // dx: Number, dy: Number + //}], + + control_points: Sequelize.TEXT, + + group: Sequelize.STRING, + locked: {type: Sequelize.BOOLEAN, default: false}, + + payload_uri: Sequelize.STRING, + payload_thumbnail_web_uri: Sequelize.STRING, + payload_thumbnail_medium_uri: Sequelize.STRING, + payload_thumbnail_big_uri: Sequelize.STRING, + payload_size: Sequelize.INTEGER, // file size in bytes + + fill_color: {type: Sequelize.STRING, default: "transparent"}, + stroke_color: {type: Sequelize.STRING, default: "#000000"}, + text_color: Sequelize.STRING, + stroke: {type: Sequelize.DECIMAL, default: 0.0}, + stroke_style: {type: Sequelize.STRING, default: "solid"}, + alpha: {type: Sequelize.DECIMAL, default: 1.0}, + order: {type: Sequelize.INTEGER, default: 0}, + crop_x: Sequelize.INTEGER, + crop_y: Sequelize.INTEGER, + crop_w: Sequelize.INTEGER, + crop_h: Sequelize.INTEGER, + shape: Sequelize.STRING, + shape_svg: Sequelize.STRING, + padding_left: Sequelize.INTEGER, + padding_right: Sequelize.INTEGER, + padding_top: Sequelize.INTEGER, + padding_bottom: Sequelize.INTEGER, + margin_left: Sequelize.INTEGER, + margin_right: Sequelize.INTEGER, + margin_top: Sequelize.INTEGER, + margin_bottom: Sequelize.INTEGER, + border_radius: Sequelize.INTEGER, + align: {type: Sequelize.STRING, default: "left"}, + valign: {type: Sequelize.STRING, default: "top"}, + + brightness: Sequelize.DECIMAL, + contrast: Sequelize.DECIMAL, + saturation: Sequelize.DECIMAL, + blur: Sequelize.DECIMAL, + hue: Sequelize.DECIMAL, + opacity: Sequelize.DECIMAL, + + payload_alternatives: Sequelize.TEXT, + + /*payload_alternatives: [{ + mime: String, + payload_uri: String, + payload_thumbnail_web_uri: String, + payload_thumbnail_medium_uri: String, + payload_thumbnail_big_uri: String, + payload_size: Number + }],*/ + + created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW} + }), + + init: function() { + sequelize.sync(); + }, + + getUserRoleInSpace: (originalSpace, user, cb) => { + originalSpace.path = []; + console.log("getUserRoleInSpace",originalSpace._id,user._id,user.home_folder_id); + + if (originalSpace._id == user.home_folder_id || (originalSpace.creator_id && originalSpace.creator_id == user._id)) { + cb("admin"); + } else { + var findMembershipsForSpace = function(space, allMemberships, prevRole) { + Membership.findAll({ where: { + "space": space._id + }}).then(function(parentMemberships) { + var currentMemberships = parentMemberships.concat(allMemberships); + + if (space.parent_space_id) { + Space.findOne({ where: { + "_id": space.parent_space_id + }}, function(err, parentSpace) { + findMembershipsForSpace(parentSpace, currentMemberships, prevRole); + }); + } else { + // reached the top + + var role = prevRole; + space.memberships = currentMemberships; + + if (role == "none") { + if (originalSpace.access_mode == "public") { + role = "viewer"; + } + } + + currentMemberships.forEach(function(m, i) { + if (m.user_id && m.user_id == user._id) { + role = m.role; + } + }); + + cb(role); + } + }); + }; + findMembershipsForSpace(originalSpace, [], "none"); + } + }, + + spaceToObject: (space) => { + // FIXME TODO + return space; + }, + + findUserBySessionToken: (token, cb) => { + db.Session.findOne({where: {token: token}}) + .then(session => { + if (!session) cb(null, null) + else db.User.findOne({where: {_id: session.user_id}}) + .then(user => { + cb(null, user) + }) + }) + }, + + unpackArtifact: (a) => { + if (a.control_points) { + a.control_points = JSON.parse(a.control_points); + } + if (a.payload_alternatives) { + a.payload_alternatives = JSON.parse(a.payload_alternatives); + } + return a; + }, + + packArtifact: (a) => { + if (a.control_points) { + a.control_points = JSON.stringify(a.control_points); + } + if (a.payload_alternatives) { + a.payload_alternatives = JSON.stringify(a.payload_alternatives); + } + return a; + } +} diff --git a/models/domain.js b/models/domain.js deleted file mode 100644 index b2be7db..0000000 --- a/models/domain.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; - -module.exports.domainSchema = mongoose.Schema({ - domain: String, - edu: Boolean, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports.domainSchema.index({ - domain: 1 -}); diff --git a/models/plan.js b/models/plan.js deleted file mode 100644 index b0c3815..0000000 --- a/models/plan.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; - -Plan = mongoose.model('Plan', { - key: String, - description: String, - limit_folders: { - type: Number, - default: 200 - }, - limit_spaces: { - type: Number, - default: 500 - }, - limit_storage_bytes: { - type: Number, - default: 10737418240 - }, - plan_type: { - type: String, - default: "org" - }, - price: Number, - public: Boolean, - recurring: { - type: String, - default: "month" - }, - title: String, - trial_days: Number, - voucher_code: String, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -exports.planModel = Plan; \ No newline at end of file diff --git a/models/schema.js b/models/schema.js deleted file mode 100644 index e64911b..0000000 --- a/models/schema.js +++ /dev/null @@ -1,12 +0,0 @@ -//'use strict'; - -var mongoose = require('mongoose'); - -User = mongoose.model('User', require('./user').userSchema); -Action = mongoose.model('Action', require('./action').actionSchema); -Space = mongoose.model('Space', require('./space').spaceSchema); -Artifact = mongoose.model('Artifact', require('./artifact').artifactSchema); -Team = mongoose.model('Team', require('./team').teamSchema); -Message = mongoose.model('Message', require('./message').messageSchema); -Membership = mongoose.model('Membership', require('./membership').membershipSchema); -Domain = mongoose.model('Domain', require('./domain').domainSchema); diff --git a/models/team.js b/models/team.js deleted file mode 100644 index b35942c..0000000 --- a/models/team.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; - -module.exports.teamSchema = mongoose.Schema({ - name: String, - subdomain: String, - creator: { - type: Schema.Types.ObjectId, - ref: 'User' - }, - admins: [{ - type: Schema.Types.ObjectId, - ref: 'User' - }], - invitation_codes: [String], - avatar_thumb_uri: String, - avatar_uri: String, - payment_type: { - type: String, - default: "auto" - }, - payment_plan_key: String, - payment_subscription_id: String, - blocked_at: { - type: Date - }, - upgraded_at: { - type: Date - }, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports.teamSchema.index({ - creator: 1 -}); - -module.exports.teamSchema.statics.getTeamForHost = (host, cb) => { - - if (host != "127.0.0.1:9666") { //phantomjs check - let subDomainParts = host.split('.'); - - if (subDomainParts.length > 2) { - const subdomain = subDomainParts[0]; - - if (subdomain != "www") { - Team.findOne({ - subdomain: subdomain - }).exec((err, team) => { - cb(err, team, subdomain) - }); - } else { - cb(null, null) - } - - } else { - cb(null, null); - } - } else { - cb(null, null); - } -} diff --git a/package.json b/package.json index fcfa957..02a2d62 100644 --- a/package.json +++ b/package.json @@ -53,11 +53,14 @@ "raven": "1.2.0", "request": "2.81.0", "sanitize-html": "^1.11.1", + "sequelize": "^4.37.6", "serve-favicon": "~2.4.2", "serve-static": "^1.13.1", "slug": "0.9.1", + "sqlite3": "^4.0.0", "swig": "1.4.2", "underscore": "1.8.3", + "uuid": "^3.2.1", "validator": "7.0.0", "weak": "1.0.1", "ws": "2.2.3" diff --git a/public/javascripts/spacedeck_account.js b/public/javascripts/spacedeck_account.js index fd64917..d66d9c4 100644 --- a/public/javascripts/spacedeck_account.js +++ b/public/javascripts/spacedeck_account.js @@ -36,13 +36,11 @@ SpacedeckAccount = { save_user_language: function(lang) { localStorage.lang = lang; - if (this.user.preferences) { - this.user.preferences.language = lang; - this.save_user(function() { - window._spacedeck_location_change = true; - location.href="/spaces"; - }.bind(this)); - } + this.user.prefs_language = lang; + this.save_user(function() { + window._spacedeck_location_change = true; + location.href="/spaces"; + }.bind(this)); }, save_user: function(on_success) { diff --git a/public/javascripts/spacedeck_board_artifacts.js b/public/javascripts/spacedeck_board_artifacts.js index 5ec3aba..2915f99 100644 --- a/public/javascripts/spacedeck_board_artifacts.js +++ b/public/javascripts/spacedeck_board_artifacts.js @@ -61,16 +61,16 @@ var SpacedeckBoardArtifacts = { }, artifact_link: function(a) { - if (a.meta && a.meta.link_uri) { - return a.meta.link_uri; + if (a.link_uri) { + return a.link_uri; } else { return ""; } }, artifact_link_caption: function(a) { - if (a.meta && a.meta.link_uri) { - var parts = a.meta.link_uri.split("/"); + if (a.link_uri) { + var parts = a.link_uri.split("/"); // scheme://domain.foo/... // 0 1 2 if (parts.length>2) { @@ -102,11 +102,9 @@ var SpacedeckBoardArtifacts = { if (this.artifact_is_selected(a) && this.editing_artifact_id!=a._id) clzs.push("selected"); if (!a._id) clzs.push("creating"); - if (a.style) { - clzs.push("align-"+a.style.align); - clzs.push("align-"+a.style.valign); - } - + if (a.align) clzs.push("align-"+a.align); + if (a.valign) clzs.push("align-"+a.valign); + clzs.push("state-"+a.state); if (this.artifact_is_text_blank(a)) { @@ -123,56 +121,56 @@ var SpacedeckBoardArtifacts = { artifact_inner_style: function(a) { var styles = []; - if (a.style) { + //if (a.style) { - var svg_style = ((a.mime.match("vector") || a.mime.match("shape")) && a.style.shape!="square"); + var svg_style = ((a.mime.match("vector") || a.mime.match("shape")) && a.shape!="square"); if (!svg_style) { - if (a.style.stroke) { - styles.push("border-width:"+a.style.stroke+"px"); - styles.push("border-style:"+(a.style.stroke_style||"solid")); + if (a.stroke) { + styles.push("border-width:"+a.stroke+"px"); + styles.push("border-style:"+(a.stroke_style||"solid")); } - if (a.style.stroke_color) { - styles.push("border-color:"+a.style.stroke_color); + if (a.stroke_color) { + styles.push("border-color:"+a.stroke_color); } - if (a.style.border_radius) { - styles.push("border-radius:"+a.style.border_radius+"px"); + if (a.border_radius) { + styles.push("border-radius:"+a.border_radius+"px"); } } - if (a.style.fill_color && !svg_style) { - styles.push("background-color:"+a.style.fill_color); + if (a.fill_color && !svg_style) { + styles.push("background-color:"+a.fill_color); } - if (a.style.text_color) { - styles.push("color:"+a.style.text_color); + if (a.text_color) { + styles.push("color:"+a.text_color); } var filters = []; - if (!isNaN(a.style.brightness) && a.style.brightness != 100) { - filters.push("brightness("+a.style.brightness+"%)"); + if (!isNaN(a.brightness) && a.brightness != 100) { + filters.push("brightness("+a.brightness+"%)"); } - if (!isNaN(a.style.contrast) && a.style.contrast != 100) { - filters.push("contrast("+a.style.contrast+"%)"); + if (!isNaN(a.contrast) && a.contrast != 100) { + filters.push("contrast("+a.contrast+"%)"); } - if (!isNaN(a.style.opacity) && a.style.opacity != 100) { - filters.push("opacity("+a.style.opacity+"%)"); + if (!isNaN(a.opacity) && a.opacity != 100) { + filters.push("opacity("+a.opacity+"%)"); } - if (!isNaN(a.style.hue) && a.style.hue) { - filters.push("hue-rotate("+a.style.hue+"deg)"); + if (!isNaN(a.hue) && a.hue) { + filters.push("hue-rotate("+a.hue+"deg)"); } - if (!isNaN(a.style.saturation) && a.style.saturation != 100) { - filters.push("saturate("+a.style.saturation+"%)"); + if (!isNaN(a.saturation) && a.saturation != 100) { + filters.push("saturate("+a.saturation+"%)"); } - if (!isNaN(a.style.blur) && a.style.blur) { - filters.push("blur("+a.style.blur+"px)"); + if (!isNaN(a.blur) && a.blur) { + filters.push("blur("+a.blur+"px)"); } if (filters.length) { styles.push("-webkit-filter:"+filters.join(" ")); styles.push("filter:"+filters.join(" ")); } - } + //} return styles.join(";"); }, @@ -180,12 +178,10 @@ var SpacedeckBoardArtifacts = { artifact_text_cell_style: function(a, for_text_editor) { var styles = []; - if (a.style) { - if (a.style.padding_left) styles.push("padding-left:"+a.style.padding_left+"px"); - if (a.style.padding_right) styles.push("padding-right:"+a.style.padding_right+"px"); - if (a.style.padding_top) styles.push("padding-top:"+a.style.padding_top+"px"); - if (a.style.padding_bottom) styles.push("padding-bottom:"+a.style.padding_bottom+"px"); - } + if (a.padding_left) styles.push("padding-left:"+a.padding_left+"px"); + if (a.padding_right) styles.push("padding-right:"+a.padding_right+"px"); + if (a.padding_top) styles.push("padding-top:"+a.padding_top+"px"); + if (a.padding_bottom) styles.push("padding-bottom:"+a.padding_bottom+"px"); return styles.join(";"); }, @@ -194,26 +190,22 @@ var SpacedeckBoardArtifacts = { var styles = []; var z = 0; - if (a.board) { - z = a.board.z; - if (z<0) z=0; // fix negative z-index - - styles = [ - "left:" +a.board.x+"px", - "top:" +a.board.y+"px", - "width:" +a.board.w+"px", - "height:"+a.board.h+"px", - "z-index:"+z - ]; - } - - if (a.style) { - if (a.style.margin_left) styles.push("margin-left:"+a.style.margin_left+"px"); - if (a.style.margin_right) styles.push("margin-right:"+a.style.margin_right+"px"); - if (a.style.margin_top) styles.push("margin-top:"+a.style.margin_top+"px"); - if (a.style.margin_bottom) styles.push("margin-bottom:"+a.style.margin_bottom+"px"); - } + z = a.z; + if (z<0) z=0; // fix negative z-index + + styles = [ + "left:" +a.x+"px", + "top:" +a.y+"px", + "width:" +a.w+"px", + "height:"+a.h+"px", + "z-index:"+z + ]; + if (a.margin_left) styles.push("margin-left:"+a.margin_left+"px"); + if (a.margin_right) styles.push("margin-right:"+a.margin_right+"px"); + if (a.margin_top) styles.push("margin-top:"+a.margin_top+"px"); + if (a.margin_bottom) styles.push("margin-bottom:"+a.margin_bottom+"px"); + // FIXME: via class logic? if (a.mime.match("vector")) { styles.push("overflow:visible"); @@ -241,7 +233,7 @@ var SpacedeckBoardArtifacts = { artifact_thumbnail_uri: function(a) { if (a.payload_thumbnail_big_uri && a.board) { - if (a.board.w>800) { + if (a.w>800) { return a.payload_thumbnail_big_uri; } } @@ -255,35 +247,35 @@ var SpacedeckBoardArtifacts = { var type = parts[0]; var provider = parts[1]; - if (!a.meta || !a.meta.link_uri) { + if (!a.link_uri) { console.log("missing meta / link_uri: ",a); console.log("type/provider: ",type,provider); return ("missing metadata: "+a._id); } if (provider=="youtube") { - var vid = a.meta.link_uri.match(/(v=|\/)([a-zA-Z0-9\-_]{11})/); + var vid = a.link_uri.match(/(v=|\/)([a-zA-Z0-9\-_]{11})/); if (vid && vid.length>2) { var uri = "https://youtube.com/embed/"+vid[2]; return ""; } else return "Can't resolve: "+a.payload_uri; } else if (provider=="dailymotion") { - var match = a.meta.link_uri.match(/dailymotion.com\/video\/([^<]*)/); + var match = a.link_uri.match(/dailymotion.com\/video\/([^<]*)/); if (match && match.length>1) { var uri = "https://www.dailymotion.com/embed/video/"+match[1]; return ""; } else return "Can't resolve: "+a.payload_uri; } else if (provider=="vimeo") { - var match = a.meta.link_uri.match(/https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/); + var match = a.link_uri.match(/https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/); if (match) { var uri = "https://player.vimeo.com/video/"+match[2]; return ""; } else return "Can't resolve: "+a.payload_uri; } else if (provider=="soundcloud") { - return ''; + return ''; } else if (provider=="spacedeck") { @@ -299,8 +291,8 @@ var SpacedeckBoardArtifacts = { if (mtype != "vector" && mtype != "shape") return ""; - var shape = a.style.shape || ""; - var padding = 32 + a.style.stroke*2; + var shape = a.shape || ""; + var padding = 32 + a.stroke*2; var path_svg; var fill = ""; @@ -310,13 +302,13 @@ var SpacedeckBoardArtifacts = { fill = "fill:none"; } else { path_svg = render_vector_shape(a, padding); - fill = "fill:"+a.style.fill_color+";"; + fill = "fill:"+a.fill_color+";"; padding = 0; } var margin = padding; - var svg = ""; + var svg = ""; svg += path_svg; svg += ""; @@ -329,10 +321,10 @@ var SpacedeckBoardArtifacts = { if (arts.length==0) return null; r = { - x1: parseInt(_.min(arts.map(function(a){return a.board.x}))), - y1: parseInt(_.min(arts.map(function(a){return a.board.y}))), - x2: parseInt(_.max(arts.map(function(a){return a.board.x+a.board.w}))), - y2: parseInt(_.max(arts.map(function(a){return a.board.y+a.board.h}))) + x1: parseInt(_.min(arts.map(function(a){return a.x}))), + y1: parseInt(_.min(arts.map(function(a){return a.y}))), + x2: parseInt(_.max(arts.map(function(a){return a.x+a.w}))), + y2: parseInt(_.max(arts.map(function(a){return a.y+a.h}))) }; r.x=r.x1; r.y=r.y1; @@ -356,7 +348,7 @@ var SpacedeckBoardArtifacts = { artifacts_in_rect: function(rect) { return _.filter(this.active_space_artifacts, function(a) { - return this.rects_intersecting(a.board, rect); + return this.rects_intersecting(a, rect); }.bind(this)); }, @@ -366,15 +358,15 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); var overlapping = _.filter(this.artifacts_in_rect(rect), function(a){return !this.is_selected(a)}.bind(this)); - var max_z = _.max(overlapping,function(a){ return a.board.z; }); + var max_z = _.max(overlapping,function(a){ return a.z; }); if (max_z.board) { - max_z = max_z.board.z + 1; + max_z = max_z.z + 1; } else { max_z = 1; } this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { z: max_z }) }; + return { z: max_z }; }); }, @@ -384,15 +376,15 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); var overlapping = _.filter(this.artifacts_in_rect(rect), function(a){return !this.is_selected(a);}.bind(this)); - var min_z = _.min(overlapping,function(a){ return (a.board?a.board.z:0); }); + var min_z = _.min(overlapping,function(a){ return a.z; }); if (min_z.board) { - min_z = min_z.board.z - 1; + min_z = min_z.z - 1; } else { min_z = 0; } - var my_z = _.max(this.selected_artifacts(),function(a){ (a.board?a.board.z:0); }); + var my_z = _.max(this.selected_artifacts(),function(a){ return a.z; }); if (my_z.board) { - my_z = my_z.board.z - 1; + my_z = my_z.z - 1; } else { my_z = 0; } @@ -400,14 +392,14 @@ var SpacedeckBoardArtifacts = { // TODO: move all other items up in this case? if (min_z < 0) { this.update_artifacts(overlapping, function(a) { - return { board: _.extend(a.board, { z: (my_z + (a.board?a.board.z:0) + 1) }) }; + return { z: (my_z + a.z + 1) }; }); return; } this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { z: min_z }) }; + return { z: min_z }; }); }, @@ -416,7 +408,7 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { x: rect.x1 }) }; + return { x: rect.x1 }; }); }, @@ -425,7 +417,7 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { y: rect.y1 }) }; + return { y: rect.y1 }; }); }, @@ -434,7 +426,7 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { x: rect.x2 - a.board.w }) }; + return { x: rect.x2 - a.w }; }); }, @@ -443,7 +435,7 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { y: rect.y2 - a.board.h }) }; + return { y: rect.y2 - a.h }; }); }, @@ -453,7 +445,7 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); var cx = rect.x1 + (rect.x2-rect.x1)/2; this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { x: cx - a.board.w/2 }) }; + return { x: cx - a.w/2 }; }); }, @@ -463,7 +455,7 @@ var SpacedeckBoardArtifacts = { var rect = this.artifact_selection_rect(); var cy = rect.y1 + (rect.y2-rect.y1)/2; this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { y: cy - a.board.h/2 }) }; + return { y: cy - a.h/2 }; }); }, @@ -473,11 +465,11 @@ var SpacedeckBoardArtifacts = { var arts = this.selected_artifacts(); if (arts.length<2) return; - var totalw = _.reduce(arts, function(sum, a) { return sum + a.board.w }, 0); + var totalw = _.reduce(arts, function(sum, a) { return sum + a.w }, 0); var avgw = totalw / arts.length; this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { w: avgw }) }; + return { w: avgw }; }); }, @@ -487,11 +479,11 @@ var SpacedeckBoardArtifacts = { var arts = this.selected_artifacts(); if (arts.length<2) return; - var totalh = _.reduce(arts, function(sum, a) { return sum + a.board.h }, 0); + var totalh = _.reduce(arts, function(sum, a) { return sum + a.h }, 0); var avgh = totalh / arts.length; this.update_selected_artifacts(function(a) { - return { board: _.extend(a.board, { h: avgh }) }; + return { h: avgh }; }); }, @@ -506,16 +498,16 @@ var SpacedeckBoardArtifacts = { var selected = this.selected_artifacts(); if (selected.length<3) return; - var sorted = _.sortBy(selected, function(a) { return a.board.x }); - var startx = sorted[0].board.x + sorted[0].board.w/2; - var stopx = _.last(sorted).board.x + _.last(sorted).board.w/2; + var sorted = _.sortBy(selected, function(a) { return a.x }); + var startx = sorted[0].x + sorted[0].w/2; + var stopx = _.last(sorted).x + _.last(sorted).w/2; var step = (stopx-startx)/(sorted.length-1); for (var i=1; i999) z=999; return z; @@ -1574,20 +1572,18 @@ var SpacedeckSections = { payload_thumbnail_web_uri: url || null, space_id: space._id, - style: { - order: this.active_space_artifacts.length+1, - valign: "middle", - align: "center" - //fill_color: "#f8f8f8" - } + order: this.active_space_artifacts.length+1, + valign: "middle", + align: "center" + //fill_color: "#f8f8f8" }; if (mimes[item_type] == "text/html") { - new_item.style.padding_left = 10; - new_item.style.padding_top = 10; - new_item.style.padding_right = 10; - new_item.style.padding_bottom = 10; - new_item.style.fill_color = "rgba(255,255,255,1)"; + new_item.padding_left = 10; + new_item.padding_top = 10; + new_item.padding_right = 10; + new_item.padding_bottom = 10; + new_item.fill_color = "rgba(255,255,255,1)"; new_item.description = "Text"; } @@ -1600,13 +1596,11 @@ var SpacedeckSections = { z = point.z; } - new_item.board = { - x: parseInt(point.x), - y: parseInt(point.y), - w: w, - h: h, - z: z - }; + new_item.x = parseInt(point.x); + new_item.y = parseInt(point.y); + new_item.z = z; + new_item.w = w; + new_item.h = h; if (this.guest_nickname) { new_item.editor_name = this.guest_nickname; @@ -1665,7 +1659,7 @@ var SpacedeckSections = { for (var i=0; ieff_w) { // horizontal centering @@ -2846,8 +2819,8 @@ var SpacedeckSections = { var el = $("#space")[0]; - var eff_w = this.active_space.advanced.width*this.viewport_zoom; - var eff_h = this.active_space.advanced.height*this.viewport_zoom; + var eff_w = this.active_space.width*this.viewport_zoom; + var eff_h = this.active_space.height*this.viewport_zoom; var sx = el.scrollLeft; var sy = el.scrollTop; @@ -2980,9 +2953,9 @@ var SpacedeckSections = { var w = 300; var h = 200; - if (parsed.board && parsed.board.w && parsed.board.h) { - w = parsed.board.w; - h = parsed.board.h; + if (parsed.board && parsed.w && parsed.h) { + w = parsed.w; + h = parsed.h; } var point = this.cursor_point_to_space(evt); diff --git a/public/javascripts/spacedeck_spaces.js b/public/javascripts/spacedeck_spaces.js index 55526ce..67d0bdb 100644 --- a/public/javascripts/spacedeck_spaces.js +++ b/public/javascripts/spacedeck_spaces.js @@ -283,9 +283,9 @@ var SpacedeckSpaces = { this.discover_zones(); - window.setTimeout(function() { - this.zoom_to_fit(); - }.bind(this),10); + //window.setTimeout(function() { + // this.zoom_to_fit(); + //}.bind(this),10); if (on_success) { on_success(); diff --git a/public/javascripts/spacedeck_whiteboard.js b/public/javascripts/spacedeck_whiteboard.js index c6ffd2e..9bdb4ec 100644 --- a/public/javascripts/spacedeck_whiteboard.js +++ b/public/javascripts/spacedeck_whiteboard.js @@ -331,7 +331,7 @@ function setup_whiteboard_directives() { var $scope = this.vm.$root; return _.filter($scope.active_space_artifacts, function(a) { - return this.rects_intersecting(a.board, rect); + return this.rects_intersecting(a, rect); }.bind(this)); }, @@ -439,15 +439,15 @@ function setup_whiteboard_directives() { dists = $scope.unselected_artifacts().map(function(a){ - var r = this.rect_to_points(a.board); + var r = this.rect_to_points(a); var xd1 = Math.abs(r[0].x-x); var xd2 = Math.abs(r[1].x-x); - var xd3 = Math.abs(r[0].x+a.board.w/2 - x); + var xd3 = Math.abs(r[0].x+a.w/2 - x); var yd1 = Math.abs(r[0].y-y); var yd2 = Math.abs(r[2].y-y); - var yd3 = Math.abs(r[0].y+a.board.h/2 - y); + var yd3 = Math.abs(r[0].y+a.h/2 - y); if (!snap_middle) { if (xd2x2) { var t = x1; x1 = x2; x2 = t; } if (y1>y2) { var t = y1; y1 = y2; y2 = t; } return { - board: _.extend(a.board, { - x: x1, - y: y1, - w: x2 - x1, - h: y2 - y1 - }) + x: x1, + y: y1, + w: x2 - x1, + h: y2 - y1 }; }.bind(this)); @@ -902,18 +886,17 @@ function setup_whiteboard_directives() { var old_a = $scope.find_artifact_before_transaction(a); var control_points = _.cloneDeep(old_a.control_points); - var board = _.clone(old_a.board); var cp = control_points[$scope.selected_control_point_idx]; - var snapped = _this.snap_point(board.x+cp.dx+dx, board.y+cp.dy+dy); - dx = snapped.snapx[1]-(board.x+cp.dx); - dy = snapped.snapy[1]-(board.y+cp.dy); + var snapped = _this.snap_point(old_a.x+cp.dx+dx, old_a.y+cp.dy+dy); + dx = snapped.snapx[1]-(old_a.x+cp.dx); + dy = snapped.snapy[1]-(old_a.y+cp.dy); cp.dx += dx; cp.dy += dy; // special case for arrow's 3rd point - if (a.style.shape == "arrow" && $scope.selected_control_point_idx!=2) { + if (a.shape == "arrow" && $scope.selected_control_point_idx!=2) { /*control_points[2].dx += dx/2; control_points[2].dy += dy/2; */ @@ -921,7 +904,7 @@ function setup_whiteboard_directives() { control_points[2].dy = (control_points[0].dy+control_points[1].dy)/2; } - return _this.normalize_control_points(control_points, board); + return _this.normalize_control_points(control_points, old_a); }); } else if (this.mouse_state == "scribble") { @@ -930,16 +913,14 @@ function setup_whiteboard_directives() { var old_a = a; var control_points = _.cloneDeep(old_a.control_points); - var board = _.clone(old_a.board); - var offset = this.offset_point_in_wrapper({x:cursor.x,y:cursor.y}); control_points.push({ - dx: offset.x-board.x, - dy: offset.y-board.y + dx: offset.x-old_a.x, + dy: offset.y-old_a.y }); - return this.normalize_control_points(simplify_scribble_points(control_points), board); + return this.normalize_control_points(simplify_scribble_points(control_points), old_a); }.bind(this)); var arts = $scope.selected_artifacts(); @@ -959,7 +940,7 @@ function setup_whiteboard_directives() { } }, - normalize_control_points: function(control_points, board) { + normalize_control_points: function(control_points, artifact) { var x1 = _.min(control_points,"dx").dx; var y1 = _.min(control_points,"dy").dy; var x2 = _.max(control_points,"dx").dx; @@ -981,19 +962,15 @@ function setup_whiteboard_directives() { var bshiftx = 0; var bshifty = 0; - if (board.w < 0) bshiftx = -board.w; - if (board.h < 0) bshifty = -board.h; - - var shifted_board = { - x: board.x + bshiftx - shiftx, - y: board.y + bshifty - shifty, - w: w, - h: h, - z: board.z - }; + if (artifact.w < 0) bshiftx = -artifact.w; + if (artifact.h < 0) bshifty = -artifact.h; return { - board: shifted_board, + x: artifact.x + bshiftx - shiftx, + y: artifact.y + bshifty - shifty, + w: w, + h: h, + z: artifact.z, control_points: shifted_cps }; } diff --git a/public/javascripts/vector-render.js b/public/javascripts/vector-render.js index 84adb91..4d4bc9f 100644 --- a/public/javascripts/vector-render.js +++ b/public/javascripts/vector-render.js @@ -21,7 +21,7 @@ function vec2_angle(v) { } function render_vector_drawing(a, padding) { - var shape = a.style.shape || ""; + var shape = a.shape || ""; var path = []; var p = a.control_points[0]; @@ -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 tip = ""; - tip += ""; - var svg = tip + ""; + tip += ""; + var svg = tip + ""; return svg; } @@ -237,11 +237,11 @@ function render_vector_rect(xradius,yradius,offset) { } function render_vector_shape(a) { - var stroke = parseInt(a.style.stroke) + 4; + var stroke = parseInt(a.stroke) + 4; var offset = stroke / 2; - var xr = (a.board.w-stroke) / 2; - var yr = (a.board.h-stroke) / 2; + var xr = (a.w-stroke) / 2; + var yr = (a.h-stroke) / 2; var shape_renderers = { ellipse: function() { return render_vector_ellipse(xr, yr, offset); }, @@ -258,7 +258,7 @@ function render_vector_shape(a) { 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 ""; diff --git a/routes/api/memberships.js b/routes/api/memberships.js index f01c0e7..e91360e 100644 --- a/routes/api/memberships.js +++ b/routes/api/memberships.js @@ -1,20 +1,16 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +require('../../models/db'); 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(); diff --git a/routes/api/sessions.js b/routes/api/sessions.js index 054e49c..8c2fdba 100644 --- a/routes/api/sessions.js +++ b/routes/api/sessions.js @@ -1,10 +1,10 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +const db = require('../../models/db'); var bcrypt = require('bcryptjs'); -var crypo = require('crypto'); +var crypto = require('crypto'); var URL = require('url').URL; var express = require('express'); @@ -12,68 +12,64 @@ 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) { - if (err) console.error("Error saving user:",err); - - 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(404); - } - } - })); - } else { + if (!data.email || !data.password) { res.status(400).json({}); + return; } + + var email = req.body.email.toLowerCase(); + var password = req.body["password"]; + + 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); + + var session = { + user_id: user._id, + token: token, + ip: req.ip, + device: "web", + created_at: new Date() + }; + + db.Session.create(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); + } + }); }); router.delete('/current', function(req, res, next) { if (req.user) { - var user = 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) { + });*/ + //user.sessions = newSessions; + //user.save(function(err, result) { var domain = new URL(config.get('endpoint')).hostname; res.clearCookie('sdsession', { domain: domain }); res.sendStatus(204); - }); + //}); } else { res.sendStatus(404); } diff --git a/routes/api/space_artifacts.js b/routes/api/space_artifacts.js index d3e5006..71d9f2a 100644 --- a/routes/api/space_artifacts.js +++ b/routes/api/space_artifacts.js @@ -1,7 +1,10 @@ "use strict"; 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 payloadConverter = require('../../helpers/artifact_converter'); var redis = require('../../helpers/redis'); @@ -9,13 +12,11 @@ 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'); @@ -46,15 +47,24 @@ var roleMapping = { // ARTIFACTS router.get('/', (req, res) => { - Artifact.find({ + db.Artifact.findAll({where: { space_id: req.space._id - }).exec((err, artifacts) => { + }}).then(artifacts => { 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) { - User.findOne({ + // FIXME JOIN + /*User.findOne({where: { "_id": a.user_id - }).select({ + }}).select({ "_id": 1, "nickname": 1, "email": 1 @@ -63,7 +73,8 @@ router.get('/', (req, res) => { a['user'] = user.toObject(); } cb(err, a); - }); + });*/ + cb(null, a); } else { cb(null, a); } @@ -81,9 +92,8 @@ router.post('/', function(req, res, next) { attrs['space_id'] = req.space._id; - var artifact = new Artifact(attrs); - - artifact.created_from_ip = req['real_ip']; + var artifact = attrs; + artifact._id = uuidv4(); if (req.user) { artifact.user_id = req.user._id; @@ -92,23 +102,18 @@ router.post('/', function(req, res, next) { 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); - } + db.packArtifact(artifact); + + if (req.spaceRole == "editor" || req.spaceRole == "admin") { + db.Artifact.create(artifact).then(() => { + //if (err) res.status(400).json(err); + db.unpackArtifact(artifact); + db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id}}); + res.distributeCreate("Artifact", artifact); }); } else { res.status(401).json({ - "error": "no access" + "error": "Access denied" }); } }); @@ -118,6 +123,8 @@ router.post('/:artifact_id/payload', function(req, res, next) { var a = req.artifact; var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9_\-\.]/g, ''); + + // FIXME TODO use portable tmp dir var localFilePath = "/tmp/" + fileName; var writeStream = fs.createWriteStream(localFilePath); var stream = req.pipe(writeStream); @@ -132,13 +139,7 @@ router.post('/:artifact_id/payload', function(req, res, next) { 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() - } - }); + db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id}}); res.distributeUpdate("Artifact", artifact); } }, progress_callback); @@ -161,42 +162,23 @@ router.put('/:artifact_id', function(req, res, next) { } else { newAttr.last_update_editor_name = req.editor_name; } + + db.packArtifact(newAttr); - Artifact.findOneAndUpdate({ + db.Artifact.update(newAttr, { where: { "_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); - } + }}).then(rows => { + db.unpackArtifact(newAttr); + db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id} }); + res.distributeUpdate("Artifact", newAttr); }); }); 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); - } + db.Artifact.destroy({where: { "_id": artifact._id}}).then(() => { + db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id} }); + res.distributeDelete("Artifact", artifact); }); }); diff --git a/routes/api/space_digest.js b/routes/api/space_digest.js index cee3557..f13af45 100644 --- a/routes/api/space_digest.js +++ b/routes/api/space_digest.js @@ -1,7 +1,7 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +require('../../models/db'); var async = require('async'); var fs = require('fs'); @@ -40,6 +40,12 @@ var roleMapping = { }; router.get('/', function(req, res, next) { + + res.status(200).json([]); + return; + + // FIXME TODO + var showActionForSpaces = function(err, spaceIds) { var userMapping = { '_id': 1, diff --git a/routes/api/space_exports.js b/routes/api/space_exports.js index 3a28f71..932dc44 100644 --- a/routes/api/space_exports.js +++ b/routes/api/space_exports.js @@ -1,6 +1,6 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +require('../../models/db'); var redis = require('../../helpers/redis'); var mailer = require('../../helpers/mailer'); @@ -337,28 +337,5 @@ router.get('/html', function(req, res) { }); }); -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; + diff --git a/routes/api/space_memberships.js b/routes/api/space_memberships.js index 7ec7b73..d9dc06c 100644 --- a/routes/api/space_memberships.js +++ b/routes/api/space_memberships.js @@ -1,25 +1,19 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +const db = require('../../models/db'); +const Sequelize = require('sequelize'); +const Op = Sequelize.Op; 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}); @@ -46,12 +40,12 @@ var roleMapping = { } router.get('/', function(req, res, next) { - Membership - .find({ - space: req.space._id - }) - .populate("user") - .exec(function(err, memberships) { + db.Membership + .findAll({where: { + space_id: req.space._id + }}) + //.populate("user") + .then(memberships => { res.status(200).json(memberships); }); }); diff --git a/routes/api/space_messages.js b/routes/api/space_messages.js index 47e4a58..fd2109d 100644 --- a/routes/api/space_messages.js +++ b/routes/api/space_messages.js @@ -1,6 +1,6 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +require('../../models/db'); var redis = require('../../helpers/redis'); var mailer = require('../../helpers/mailer'); diff --git a/routes/api/spaces.js b/routes/api/spaces.js index ff0545d..9036af7 100644 --- a/routes/api/spaces.js +++ b/routes/api/spaces.js @@ -1,6 +1,9 @@ "use strict"; 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 mailer = require('../../helpers/mailer'); @@ -15,12 +18,10 @@ 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'); @@ -48,15 +49,14 @@ router.get('/', function(req, res, next) { }); } else { if (req.query.writablefolders) { - Membership.find({ - user: req.user._id - }, (err, memberships) => { + db.Membership.find({where: { + user_id: req.user._id + }}, (memberships) => { var validMemberships = memberships.filter((m) => { - if (!m.space || (m.space == "undefined")) + if (!m.space_id || (m.space_id == "undefined")) return false; - else - return mongoose.Types.ObjectId.isValid(m.space.toString()); + return true; }); var editorMemberships = validMemberships.filter((m) => { @@ -64,7 +64,7 @@ router.get('/', function(req, res, next) { }); var spaceIds = editorMemberships.map(function(m) { - return new mongoose.Types.ObjectId(m.space); + return m.space_id; }); var q = { @@ -158,7 +158,7 @@ router.get('/', function(req, res, next) { .populate('creator', userMapping) .exec(function(err, space) { if (space) { - Space.roleInSpace(space, req.user, function(err, role) { + db.getUserRoleInSpace(space, req.user, function(role) { if (role == "none") { if(space.access_mode == "public") { @@ -185,41 +185,42 @@ router.get('/', function(req, res, next) { }); } else { - Membership.find({ - user: req.user._id - }, function(err, memberships) { + + console.log("!!!!!!!!!! spaces lookup"); + + db.Membership.findAll({ where: { + user_id: req.user._id + }}).then(memberships => { + if (!memberships) memberships = []; + var validMemberships = memberships.filter(function(m) { - if (!m.space || (m.space == "undefined")) + if (!m.space_id || (m.space_id == "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); + return m.space_id; }); var q = { - "$or": [{ - "creator": req.user._id, + [Op.or]: [{ + "creator_id": req.user._id, "parent_space_id": req.user.home_folder_id }, { "_id": { - "$in": spaceIds + [Op.in]: spaceIds }, - "creator": { - "$ne": req.user._id + "creator_id": { + [Op.ne]: req.user._id } }] }; - Space - .find(q) - .populate('creator', userMapping) - .exec(function(err, spaces) { - if (err) console.error(err); + db.Space + .findAll({where: q}) + .then(function(spaces) { var updatedSpaces = spaces.map(function(s) { - var spaceObj = s.toObject(); + var spaceObj = db.spaceToObject(s); return spaceObj; }); res.status(200).json(spaces); @@ -229,47 +230,46 @@ router.get('/', function(req, res, next) { } }); +// create a space router.post('/', function(req, res, next) { if (req.user) { var attrs = req.body; var createSpace = () => { - - attrs.creator = req.user; + attrs._id = uuidv4(); + attrs.creator_id = req.user._id; 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); - } - }); - } + db.Space.create(attrs).then(createdSpace => { + //if (err) res.sendStatus(400); + + console.log("!!!!!!!!!! createdSpace:",createdSpace); + + var membership = { + _id: uuidv4(), + user_id: req.user._id, + space_id: attrs._id, + role: "admin" + }; + + db.Membership.create(membership).then(() => { + res.status(201).json(createdSpace); + }); }); } if (attrs.parent_space_id) { - Space.findOne({ + db.Space.findOne({ where: { "_id": attrs.parent_space_id - }).populate('creator', userMapping).exec((err, parentSpace) => { + }}).then(parentSpace => { if (parentSpace) { - Space.roleInSpace(parentSpace, req.user, (err, role) => { + db.getUserRoleInSpace(parentSpace, req.user, (role) => { if ((role == "editor") || (role == "admin")) { createSpace(); } else { res.status(403).json({ - "error": "not editor in parent Space" + "error": "not editor in parent Space. role: "+role }); } }); @@ -292,6 +292,30 @@ router.get('/:id', function(req, res, next) { res.status(200).json(req.space); }); +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); +}); + router.put('/:id', function(req, res) { var space = req.space; var newAttr = req.body; @@ -308,17 +332,10 @@ router.put('/:id', function(req, res) { delete newAttr['editor_name']; delete newAttr['creator']; - Space.findOneAndUpdate({ + db.Space.update(newAttr, {where: { "_id": space._id - }, { - "$set": newAttr - }, { - "new": true - }, function(err, space) { - if (err) res.status(400).json(err); - else { - res.distributeUpdate("Space", space); - } + }}).then(space => { + res.distributeUpdate("Space", space); }); }); @@ -339,7 +356,7 @@ router.post('/:id/background', function(req, res, next) { 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); + console.error("removed old bg error:", err); }); } @@ -390,10 +407,10 @@ router.post('/:id/duplicate', (req, res, next) => { }).populate('creator', userMapping).exec((err, parentSpace) => { if (!parentSpace) { res.status(404).json({ - "error": "parent space not found for dupicate" + "error": "parent space not found for duplicate" }); } else { - Space.roleInSpace(parentSpace, req.user, (err, role) => { + db.getUserRoleInSpace(parentSpace, req.user, (role) => { if (role == "admin" || role == "editor") { handleDuplicateSpaceRequest(req, res, parentSpace); } else { @@ -449,6 +466,7 @@ router.post('/:id/artifacts-pdf', function(req, res, next) { fs.mkdir(outputFolder, function(db) { var images = outputFolder + "/" + rawName + "-page-%03d.jpeg"; + // FIXME not portable exec.execFile("gs", ["-sDEVICE=jpeg", "-dDownScaleFactor=4", "-dDOINTERPOLATE", "-dNOPAUSE", "-dJPEGQ=80", "-dBATCH", "-sOutputFile=" + images, "-r250", "-f", localFilePath], {}, function(error, stdout, stderr) { if (error === null) { @@ -532,6 +550,7 @@ router.post('/:id/artifacts-pdf', function(req, res, next) { }, function(err, artifacts) { + // FIXME not portable exec.execFile("rm", ["-r", outputFolder], function(err) { res.status(201).json(_.flatten(artifacts)); @@ -551,6 +570,7 @@ router.post('/:id/artifacts-pdf', function(req, res, next) { }); } else { console.error("error:", error); + // FIXME not portable exec.execFile("rm", ["-r", outputFolder], function(err) { fs.unlink(localFilePath); res.status(400).json({}); diff --git a/routes/api/teams.js b/routes/api/teams.js deleted file mode 100644 index da46a59..0000000 --- a/routes/api/teams.js +++ /dev/null @@ -1,265 +0,0 @@ -"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('bcryptjs'); - -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; diff --git a/routes/api/users.js b/routes/api/users.js index 7e1a1aa..4df055f 100644 --- a/routes/api/users.js +++ b/routes/api/users.js @@ -1,14 +1,15 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +const db = require('../../models/db'); +const uuidv4 = require('uuid/v4'); var mailer = require('../../helpers/mailer'); var uploader = require('../../helpers/uploader'); var importer = require('../../helpers/importer'); var bcrypt = require('bcryptjs'); -var crypo = require('crypto'); +var crypto = require('crypto'); var swig = require('swig'); var async = require('async'); var _ = require('underscore'); @@ -30,231 +31,99 @@ router.get('/current', function(req, res, next) { } }); +// create user 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 { + if (!req.body["email"] || !req.body["password"]) { res.status(400).json({"error":"email or password missing"}); + return; } -}); + + var email = req.body["email"].toLowerCase(); + var nickname = req.body["nickname"]; + var password = req.body["password"]; + var password_confirmation = req.body["password_confirmation"]; -router.get('/oauth2callback/url', function(req, res) { - var google = require('googleapis'); - var OAuth2 = google.auth.OAuth2; + if (password_confirmation != password) { + res.status(400).json({"error":"password_confirmation"}); + return; + } + + if (!validator.isEmail(email)) { + res.status(400).json({"error":"email_invalid"}); + return; + } + + var createUser = function() { + bcrypt.genSalt(10, function(err, salt) { + bcrypt.hash(password, salt, function(err, hash) { + crypto.randomBytes(16, function(ex, buf) { + var token = buf.toString('hex'); - var oauth2Client = new OAuth2( - config.google_access, - config.google_secret, - config.endpoint + "/login" - ); + var u = { + _id: uuidv4(), + email: email, + account_type: "email", + nickname: nickname, + password_hash: hash, + prefs_language: req.i18n.locale, + confirmation_token: token + }; - var url = oauth2Client.generateAuthUrl({ - access_type: 'online', - scope: "email" - }); + db.User.create(u) + .error(err => { + res.sendStatus(400); + }) + .then(u => { + console.log("!!! created user:", u); + var homeSpace = { + _id: uuidv4(), + name: req.i18n.__("home"), + space_type: "folder", + creator_id: u._id + }; - 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); + db.Space.create(homeSpace) + .error(err => { + res.sendStatus(400); + }) + .then(homeSpace => { + u.home_folder_id = homeSpace._id; + u.save() + .then(() => { + res.status(201).json({}); + + 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") + } + }); + }) + .error(err => { + res.status(400).json(err); + }); + }) + }); + }); }); }); }; - 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){ - res.cookie('sdsession', session.token, { httpOnly: true }); - 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); - }); - } - }); - } - }); - } - }); - } - }); - } - }); - } - }); + console.log("!!! hello !!!"); + + db.User.findAll({where: {email: email}}) + .then(users => { + if (users.length == 0) { + //var domain = email.slice(email.lastIndexOf('@')+1); + createUser(); + } else { + res.status(400).json({"error":"user_email_already_used"}); + } + }) }); -router.get('/ ', function(req, res, next) { +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"}); @@ -406,7 +275,7 @@ router.post('/password_reset_requests', (req, res, next) => { } else { if (user) { if(user.account_type == "email") { - crypo.randomBytes(16, (ex, buf) => { + crypto.randomBytes(16, (ex, buf) => { user.password_reset_token = buf.toString('hex'); user.save((err, updatedUser) => { if (err) res.status(400).json(err); diff --git a/routes/api/webgrabber.js b/routes/api/webgrabber.js index 519d9aa..17ab0f8 100644 --- a/routes/api/webgrabber.js +++ b/routes/api/webgrabber.js @@ -1,7 +1,7 @@ "use strict"; var config = require('config'); -require('../../models/schema'); +require('../../models/db'); var fs = require('fs'); var phantom = require('node-phantom-simple'); diff --git a/routes/root.js b/routes/root.js index 1169b69..d6979b0 100644 --- a/routes/root.js +++ b/routes/root.js @@ -1,7 +1,7 @@ "use strict"; const config = require('config'); -require('../models/schema'); +require('../models/db'); const redis = require('../helpers/redis'); const express = require('express'); @@ -95,10 +95,6 @@ router.get('/logout', (req, res) => { res.render('spacedeck'); }); -router.get('/users/oauth2callback', (req, res) => { - res.render('spacedeck'); -}); - router.get('/contact', (req, res) => { res.render('public/contact'); }); @@ -185,107 +181,6 @@ router.get('/spaces/:id', (req, res) => { } else res.render('spacedeck', { title: 'Space' }); }); -router.get('/users/byteam/:team_id/join', (req, res) => { - if (!req.user) { - const q = {confirmation_token: req.query.confirmation_token, account_type: "email", team: req.params.team_id}; - User.findOne(q, (err, user) => { - if (err) { - res.status(400).json({"error":"session.users"}); - } else { - if (user) { - crypto.randomBytes(48, function(ex, buf) { - const 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.confirmed_at = new Date(); - user.confirmation_token = null; - - user.save(function(err, result) { - // FIXME - const secure = process.env.NODE_ENV == "production" || process.env.NODE_ENV == "staging"; - const domain = (process.env.NODE_ENV == "production") ? ".spacedeck.com" : ".spacedecklocal.de"; - - res.cookie('sdsession', token, { domain: domain, httpOnly: true, secure: secure}); - res.redirect("/spaces"); - }); - }); - } else { - res.status(404).json({"error": "not found"}); - } - } - }); - - } else { - res.redirect("/spaces"); - } -}); - -router.get('/teams/:id/join', function(req, res, next) { - if (req.user) { - if (!req.user.team) { - Team.findOne({"_id": req.params.id}, function(err, team) { - if (team) { - const idx = team.invitation_codes.indexOf(req.query.code); - if (idx >= 0) { - const u = req.user; - u.team = team; - - if(!u.confirmed_at) { - u.confirmed_at = new Date(); - } - - u.payment_plan_key = team.payment_plan_key; - u.save(function(err) { - if (err) res.status(400).json(err); - else { - team.invitation_condes = team.invitation_codes.slice(idx); - team.save(function(err) { - team.invitation_codes = null; - - var finish = function(team, users) { - User.find({"_id": {"$in": team.admins}}).exec((err, admins) => { - if(admins) { - admins.forEach((admin) => { - mailer.sendMail( - admin.email, - req.i18n.__("team_new_member_subject", team.name), - req.i18n.__("team_new_member_body", u.email, team.name) - ); - }); - } - }); - } - - User.find({team: team}, function(err, users) { - finish(team, users); - res.redirect("/spaces"); - }); - }); - } - }); - } else { - res.redirect("/spaces?error=team_code_notfound"); - } - } else { - res.redirect("/spaces?error=team_notfound"); - } - }); - } else { - res.redirect("/spaces?error=team_already"); - } - } else res.redirect("/login"); -}); - router.get('/qrcode/:id', function(req, res) { Space.findOne({"_id": req.params.id}).exec(function(err, space) { if (space) { diff --git a/views/partials/space.html b/views/partials/space.html index 208173e..3b7482f 100644 --- a/views/partials/space.html +++ b/views/partials/space.html @@ -198,7 +198,7 @@ - + @@ -331,7 +331,7 @@ - + @@ -352,13 +352,13 @@ - {{a.view.filename}} + {{a.view.filename}} {{a.player_view.current_time_string}} - / {{a.player_view.total_time_string}} + / {{a.player_view.total_time_string}} - + @@ -464,7 +464,7 @@ - + diff --git a/views/partials/tool/background.html b/views/partials/tool/background.html index dfe73be..f710071 100644 --- a/views/partials/tool/background.html +++ b/views/partials/tool/background.html @@ -79,14 +79,14 @@ - + - + @@ -94,9 +94,9 @@ [[__("upload_background_caption")]] - + - +
Text
[[__("upload_background_caption")]]