diff --git a/README.md b/README.md index 9dde47c..1610142 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,11 @@ Spacedeck uses the following major building blocks: - Vue.js: Frontend UI Framework (included) - SQLite (included) -It also has some binary dependencies for media conversion and PDF export: +It also has some optional binary dependencies for advanced media conversion: -- graphicsmagick (for image conversion) -- ffmpeg (for video/audio conversion) +- ffmpeg and ffprobe (for video/audio conversion) - audiowaveform (for audio waveform rendering) (https://github.com/bbcrd/audiowaveform) -- phantomjs (for website screenshot rendering and PDF export, included) +- ghostscript (gs, for PDF import) By default, media files are uploaded to the ```storage``` folder. diff --git a/app.js b/app.js index 8b3e80b..1f21be1 100644 --- a/app.js +++ b/app.js @@ -79,8 +79,6 @@ app.use(helmet.hsts({ app.disable('x-powered-by'); app.use(helmet.noSniff()) -// CUSTOM MIDDLEWARES - //app.use(require("./middlewares/error_helpers")); app.use(require("./middlewares/session")); //app.use(require("./middlewares/cors")); @@ -89,19 +87,17 @@ 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")); -// 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/webgrabber', require('./routes/api/webgrabber')); @@ -125,8 +121,6 @@ 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'); db.init(); // START WEBSERVER diff --git a/helpers/artifact_converter.js b/helpers/artifact_converter.js index 5ce5801..76c22e1 100644 --- a/helpers/artifact_converter.js +++ b/helpers/artifact_converter.js @@ -13,47 +13,9 @@ const db = require('../models/db'); const Sequelize = require('sequelize'); const Op = Sequelize.Op; -const fileExtensionMap = { - ".amr" : "audio/AMR", - ".ogg" : "audio/ogg", - ".aac" : "audio/aac", - ".mp3" : "audio/mpeg", - ".mpg" : "video/mpeg", - ".3ga" : "audio/3ga", - ".mp4" : "video/mp4", - ".wav" : "audio/wav", - ".mov" : "video/quicktime", - ".doc" : "application/msword", - ".dot" : "application/msword", - ".docx" : "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - ".dotx" : "application/vnd.openxmlformats-officedocument.wordprocessingml.template", - ".docm" : "application/vnd.ms-word.document.macroEnabled.12", - ".dotm" : "application/vnd.ms-word.template.macroEnabled.12", - ".xls" : "application/vnd.ms-excel", - ".xlt" : "application/vnd.ms-excel", - ".xla" : "application/vnd.ms-excel", - ".xlsx" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ".xltx" : "application/vnd.openxmlformats-officedocument.spreadsheetml.template", - ".xlsm" : "application/vnd.ms-excel.sheet.macroEnabled.12", - ".xltm" : "application/vnd.ms-excel.template.macroEnabled.12", - ".xlam" : "application/vnd.ms-excel.addin.macroEnabled.12", - ".xlsb" : "application/vnd.ms-excel.sheet.binary.macroEnabled.12", - ".ppt" : "application/vnd.ms-powerpoint", - ".pot" : "application/vnd.ms-powerpoint", - ".pps" : "application/vnd.ms-powerpoint", - ".ppa" : "application/vnd.ms-powerpoint", - ".pptx" : "application/vnd.openxmlformats-officedocument.presentationml.presentation", - ".potx" : "application/vnd.openxmlformats-officedocument.presentationml.template", - ".ppsx" : "application/vnd.openxmlformats-officedocument.presentationml.slideshow", - ".ppam" : "application/vnd.ms-powerpoint.addin.macroEnabled.12", - ".pptm" : "application/vnd.ms-powerpoint.presentation.macroEnabled.12", - ".potm" : "application/vnd.ms-powerpoint.template.macroEnabled.12", - ".ppsm" : "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", - ".key" : "application/x-iwork-keynote-sffkey", - ".pages" : "application/x-iwork-pages-sffpages", - ".numbers" : "application/x-iwork-numbers-sffnumbers", - ".ttf" : "application/x-font-ttf" -}; +const mime = require('mime-types'); +const fileType = require('file-type'); +const readChunk = require('read-chunk'); const convertableImageTypes = [ "image/png", @@ -73,7 +35,7 @@ const convertableVideoTypes = [ const convertableAudioTypes = [ "application/ogg", - "audio/AMR", + "audio/amr", "audio/3ga", "audio/wav", "audio/3gpp", @@ -132,7 +94,7 @@ function createWaveform(fileName, localFilePath, callback){ function convertVideo(fileName, filePath, codec, callback, progress_callback) { var ext = path.extname(fileName); - var presetMime = fileExtensionMap[ext]; + var presetMime = mime.lookup(fileName); var newExt = codec == "mp4" ? "mp4" : "ogv"; var convertedPath = filePath + "." + newExt; @@ -190,7 +152,7 @@ function convertVideo(fileName, filePath, codec, callback, progress_callback) { function convertAudio(fileName, filePath, codec, callback) { var ext = path.extname(fileName); - var presetMime = fileExtensionMap[ext]; + var presetMime = mime.lookup(fileName); var newExt = codec == "mp3" ? "mp3" : "ogg"; var convertedPath = filePath + "." + newExt; @@ -227,22 +189,14 @@ function createThumbnailForVideo(fileName, filePath, callback) { function getMime(fileName, filePath, callback) { var ext = path.extname(fileName); - var presetMime = fileExtensionMap[ext]; + var presetMime = mime.lookup(fileName); if (presetMime) { callback(null, presetMime); } else { - exec.execFile("file", ["-b","--mime-type", filePath], {}, function(error, stdout, stderr) { - console.log("file stdout: ",stdout); - if (stderr === '' && error == null) { - //filter special chars from commandline - var mime = stdout.replace(/[^a-zA-Z0-9\/\-]/g,''); - callback(null, mime); - } else { - console.log("getMime file error: ", error); - callback(error, null); - } - }); + const buffer = readChunk.sync(filePath, 0, 4100); + var mimeType = fileType(buffer); + callback(null, mimeType); } } @@ -276,7 +230,7 @@ function resizeAndUpload(a, size, max, fileName, localFilePath, callback) { } -var resizeAndUploadImage = function(a, mime, size, fileName, fileNameOrg, imageFilePath, originalFilePath, payloadCallback) { +var resizeAndUploadImage = function(a, mimeType, size, fileName, fileNameOrg, imageFilePath, originalFilePath, payloadCallback) { async.parallel({ small: function(callback){ resizeAndUpload(a, size, 320, fileName, imageFilePath, callback); @@ -289,13 +243,13 @@ var resizeAndUploadImage = function(a, mime, size, fileName, fileNameOrg, imageF }, original: function(callback){ var s3Key = "s"+ a.space_id.toString() + "/a" + a._id + "/" + fileNameOrg; - uploader.uploadFile(s3Key, mime, originalFilePath, function(err, url){ + uploader.uploadFile(s3Key, mimeType, originalFilePath, function(err, url){ callback(null, url); }); } }, function(err, results) { a.state = "idle"; - a.mime = mime; + a.mime = mimeType; var stats = fs.statSync(originalFilePath); a.payload_size = stats["size"]; @@ -325,21 +279,21 @@ var resizeAndUploadImage = function(a, mime, size, fileName, fileNameOrg, imageF module.exports = { convert: function(a, fileName, localFilePath, payloadCallback, progress_callback) { - getMime(fileName, localFilePath, function(err, mime){ - console.log("[convert] fn: "+fileName+" local: "+localFilePath+" mime:", mime); + getMime(fileName, localFilePath, function(err, mimeType){ + console.log("[convert] fn: "+fileName+" local: "+localFilePath+" mimeType:", mimeType); if (!err) { - if (convertableImageTypes.indexOf(mime) > -1) { + if (convertableImageTypes.indexOf(mimeType) > -1) { gm(localFilePath).size(function (err, size) { console.log("[convert] gm:", err, size); if (!err) { - if(mime == "application/pdf") { + if(mimeType == "application/pdf") { var firstImagePath = localFilePath + ".jpeg"; exec.execFile("gs", ["-sDEVICE=jpeg","-dNOPAUSE", "-dJPEGQ=80", "-dBATCH", "-dFirstPage=1", "-dLastPage=1", "-sOutputFile=" + firstImagePath, "-r90", "-f", localFilePath], {}, function(error, stdout, stderr) { if(error === null) { - resizeAndUploadImage(a, mime, size, fileName + ".jpeg", fileName, firstImagePath, localFilePath, function(err, a) { + resizeAndUploadImage(a, mimeType, size, fileName + ".jpeg", fileName, firstImagePath, localFilePath, function(err, a) { fs.unlink(firstImagePath, function (err) { payloadCallback(err, a); }); @@ -349,7 +303,7 @@ module.exports = { } }); - } else if(mime == "image/gif") { + } else if(mimeType == "image/gif") { //gifs are buggy after convertion, so we should not convert them var s3Key = "s"+ a.space_id.toString() + "/a" + a._id.toString() + "/" + fileName; @@ -361,7 +315,7 @@ module.exports = { var stats = fs.statSync(localFilePath); a.state = "idle"; - a.mime = mime; + a.mime = mimeType; a.payload_size = stats["size"]; a.payload_thumbnail_web_uri = url; @@ -389,12 +343,12 @@ module.exports = { }); } else { - resizeAndUploadImage(a, mime, size, fileName, fileName, localFilePath, localFilePath, payloadCallback); + resizeAndUploadImage(a, mimeType, size, fileName, fileName, localFilePath, localFilePath, payloadCallback); } } else payloadCallback(err); }); - } else if (convertableVideoTypes.indexOf(mime) > -1) { + } else if (convertableVideoTypes.indexOf(mimeType) > -1) { async.parallel({ thumbnail: function(callback) { createThumbnailForVideo(fileName, localFilePath, function(err, created){ @@ -410,7 +364,7 @@ module.exports = { }); }, ogg: function(callback) { - if (mime == "video/ogg") { + if (mimeType == "video/ogg") { callback(null, "org"); } else { convertVideo(fileName, localFilePath, "ogg", function(err, file) { @@ -426,7 +380,7 @@ module.exports = { } }, mp4: function(callback) { - if (mime == "video/mp4") { + if (mimeType == "video/mp4") { callback(null, "org"); } else { convertVideo(fileName, localFilePath, "mp4", function(err, file) { @@ -442,7 +396,7 @@ module.exports = { } }, original: function(callback){ - uploader.uploadFile(fileName, mime, localFilePath, function(err, url){ + uploader.uploadFile(fileName, mimeType, localFilePath, function(err, url){ callback(null, url); }); } @@ -452,7 +406,7 @@ module.exports = { if (err) payloadCallback(err, a); else { a.state = "idle"; - a.mime = mime; + a.mime = mimeType; var stats = fs.statSync(localFilePath); a.payload_size = stats["size"]; @@ -461,7 +415,7 @@ module.exports = { a.payload_thumbnail_big_uri = results.thumbnail; a.payload_uri = results.original; - if (mime == "video/mp4") { + if (mimeType == "video/mp4") { a.payload_alternatives = [ { mime: "video/ogg", @@ -497,7 +451,7 @@ module.exports = { } }); - } else if (convertableAudioTypes.indexOf(mime) > -1) { + } else if (convertableAudioTypes.indexOf(mimeType) > -1) { async.parallel({ ogg: function(callback) { @@ -535,7 +489,7 @@ module.exports = { }, original: function(callback) { var keyName = "s" + a.space_id.toString() + "/a" + a._id.toString() + "/" + fileName; - uploader.uploadFile(keyName, mime, localFilePath, function(err, url){ + uploader.uploadFile(keyName, mimeType, localFilePath, function(err, url){ callback(null, url); }); } @@ -546,7 +500,7 @@ module.exports = { else { a.state = "idle"; - a.mime = mime; + a.mime = mimeType; var stats = fs.statSync(localFilePath); a.payload_size = stats["size"]; @@ -579,12 +533,12 @@ module.exports = { } else { - console.log("mime not matched for conversion, storing file"); + console.log("mimeType not matched for conversion, storing file"); var keyName = "s" + a.space_id.toString() + "/a" + a._id.toString() + "/" + fileName; - uploader.uploadFile(keyName, mime, localFilePath, function(err, url) { + uploader.uploadFile(keyName, mimeType, localFilePath, function(err, url) { a.state = "idle"; - a.mime = mime; + a.mime = mimeType; var stats = fs.statSync(localFilePath); a.payload_size = stats["size"]; a.payload_uri = url; diff --git a/helpers/phantom.js b/helpers/phantom.js index 01f9fb3..197b9a2 100644 --- a/helpers/phantom.js +++ b/helpers/phantom.js @@ -1,8 +1,9 @@ 'use strict'; -require('../models/db'); -var config = require('config'); -var phantom = require('node-phantom-simple'); +const db = require('../models/db'); +const config = require('config'); +const phantom = require('node-phantom-simple'); +const os = require('os'); module.exports = { // type = "pdf" or "png" @@ -10,7 +11,7 @@ module.exports = { var spaceId = space._id; var space_url = config.get("endpoint")+"/api/spaces/"+spaceId+"/html"; - var export_path = "/tmp/"+spaceId+"."+type; + var export_path = os.tmpdir()+"/"+spaceId+"."+type; var timeout = 5000; if (type=="pdf") timeout = 30000; @@ -24,7 +25,7 @@ module.exports = { var on_exit = function(exit_code) { if (exit_code>0) { - console.log("phantom abnormal exit for url "+space_url); + console.error("phantom abnormal exit for url "+space_url); if (!on_success_called && on_error) { on_error(); } @@ -32,16 +33,16 @@ module.exports = { }; phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) { - if(err){ - console.log(err); - }else{ + if (err) { + console.error(err); + } else { return browser.createPage(function (err, page) { console.log("page created, opening ",space_url); if (type=="pdf") { var psz = { - width: space.advanced.width+"px", - height: space.advanced.height+"px" + width: space.width+"px", + height: space.height+"px" }; page.set('paperSize', psz); } diff --git a/models/db.js b/models/db.js index 0fa30ac..488ec15 100644 --- a/models/db.js +++ b/models/db.js @@ -97,7 +97,7 @@ module.exports = { updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW} }), - Artifact: sequelize.define('message', { + Message: sequelize.define('message', { _id: {type: Sequelize.STRING, primaryKey: true}, space_id: Sequelize.STRING, user_id: Sequelize.STRING, diff --git a/package.json b/package.json index 02a2d62..21cfd46 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,11 @@ "cookie-parser": "~1.4.3", "csurf": "1.9.0", "debug": "~2.6.3", + "electron": "^1.8.4", "execSync": "latest", "express": "~4.13.0", "extract-zip": "^1.6.6", + "file-type": "^7.6.0", "glob": "7.1.1", "gm": "1.23.0", "googleapis": "18.0.0", @@ -40,6 +42,7 @@ "lodash": "^4.3.0", "log-timestamp": "latest", "md5": "2.2.1", + "mime-types": "^2.1.18", "mock-aws-s3": "^2.6.0", "moment": "^2.19.3", "mongoose": "4.9.3", @@ -51,6 +54,7 @@ "pm2": "latest", "qr-image": "3.2.0", "raven": "1.2.0", + "read-chunk": "^2.1.0", "request": "2.81.0", "sanitize-html": "^1.11.1", "sequelize": "^4.37.6", diff --git a/public/javascripts/spacedeck_spaces.js b/public/javascripts/spacedeck_spaces.js index 67d0bdb..b528b83 100644 --- a/public/javascripts/spacedeck_spaces.js +++ b/public/javascripts/spacedeck_spaces.js @@ -636,17 +636,14 @@ var SpacedeckSpaces = { download_space: function() { smoke.quiz(__("download_space"), function(e, test) { - if (e == "PDF"){ + if (e == "PDF") { this.download_space_as_pdf(this.active_space); - }else if (e == "ZIP"){ + } else if (e == "ZIP") { this.download_space_as_zip(this.active_space); - }else if (e == "TXT"){ - this.download_space_as_list(this.active_space); } }.bind(this), { button_1: "PDF", button_2: "ZIP", - button_3: "TXT", button_cancel:__("cancel") }); diff --git a/routes/api/space_artifacts.js b/routes/api/space_artifacts.js index 71d9f2a..c11b8ce 100644 --- a/routes/api/space_artifacts.js +++ b/routes/api/space_artifacts.js @@ -1,6 +1,8 @@ "use strict"; var config = require('config'); + +const os = require('os'); const db = require('../../models/db'); const Sequelize = require('sequelize'); const Op = Sequelize.Op; @@ -124,8 +126,7 @@ router.post('/:artifact_id/payload', function(req, res, next) { var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9_\-\.]/g, ''); - // FIXME TODO use portable tmp dir - var localFilePath = "/tmp/" + fileName; + var localFilePath = os.tmpdir() + "/" + fileName; var writeStream = fs.createWriteStream(localFilePath); var stream = req.pipe(writeStream); diff --git a/routes/api/space_exports.js b/routes/api/space_exports.js index 932dc44..b7e74da 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/db'); +const db = require('../../models/db'); var redis = require('../../helpers/redis'); var mailer = require('../../helpers/mailer'); @@ -49,26 +49,18 @@ var roleMapping = { router.get('/png', function(req, res, next) { var triggered = new Date(); - var s3_filename = "s" + req.space._id + "/" + "thumb_" + triggered.getTime() + ".jpg"; if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) { - - Space.update({ - "_id": req.space._id - }, { - "$set": { - thumbnail_updated_at: triggered - } - }, function(a, b, c) {}); - + db.Space.update({ thumbnail_updated_at: triggered }, {where : {"_id": req.space._id }}); + phantom.takeScreenshot(req.space, "png", function(local_path) { var localResizedFilePath = local_path + ".thumb.jpg"; gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) { if (err) { - console.error("screenshot resize error: ", err); + console.error("[space screenshot] resize error: ", err); res.status(500).send("Error taking screenshot."); return; } @@ -76,22 +68,15 @@ router.get('/png', function(req, res, next) { uploader.uploadFile(s3_filename, "image/jpeg", localResizedFilePath, function(err, thumbnailUrl) { if (err) { - console.error("screenshot s3 upload error. filename: " + s3_filename + " details: ", err); + console.error("[space screenshot] upload error. filename: " + s3_filename + " details: ", err); res.status(500).send("Error uploading screenshot."); return; } var oldUrl = req.space.thumbnail_url; - Space.update({ - "_id": req.space._id - }, { - "$set": { - thumbnail_url: thumbnailUrl - } - }, function(a, b, c) { + db.Space.update({ thumbnail_url: thumbnailUrl }, {where : {"_id": req.space._id }}).then(() => { res.redirect(thumbnailUrl); - try { if (oldUrl) { var oldPath = url.parse(oldUrl).pathname; @@ -125,77 +110,6 @@ function make_export_filename(space, extension) { return space.name.replace(/[^\w]/g, '') + "-" + space._id + "-" + moment().format("YYYYMMDD-HH-mm-ss") + "." + extension; } -router.get('/list', function(req, res, next) { - - if (req.user) { - if (req.spaceRole == "admin" || req.spaceRole == "editor") { - - if (req.space.space_type == "space") { - Artifact.find({ - space_id: req.space._id - }).exec(function(err, artifacts) { - async.map(artifacts, function(a, cb) { - if (a.user_id) { - User.findOne({ - "_id": a.user_id - }).exec(function(err, user) { - a.user = user; - - if (a.last_update_user_id) { - User.findOne({ - "_id": a.last_update_user_id - }).exec(function(err, updateUser) { - a.update_user = updateUser; - cb(null, a); - }); - } else { - cb(null, a); - } - }); - } else { - cb(null, a); - } - }, function(err, mappedArtifacts) { - - req.space.artifacts = mappedArtifacts.map(function(a) { - a.description = sanitizeHtml(a.description, { - allowedTags: [], - allowedAttributes: [] - }); - - if (a.payload_uri) { - var parsed = url.parse(a.payload_uri); - var fileName = path.basename(parsed.pathname) || "file.bin"; - a.filename = fileName; - } - - return a; - }); - - res.render('artifact_list', { - space: req.space - }); - }); - }); - } else { - Space.getRecursiveSubspacesForSpace(req.space, (err, subspaces) => { - res.render('space_list', { - subspaces: subspaces.map((s) => { - s.ae_link = config.endpoint + '/s/' + s.edit_hash + (s.edit_slug ? ('-'+s.edit_slug) : '') - return s; - }), - space: req.space - }); - }); - } - } else { - res.sendStatus(403); - } - } else { - res.sendStatus(403); - } -}); - router.get('/pdf', function(req, res, next) { var s3_filename = make_export_filename(req.space, "pdf"); @@ -329,9 +243,10 @@ router.get('/zip', function(req, res, next) { }); router.get('/html', function(req, res) { - Artifact.find({ + console.log("!!!!! hello "); + db.Artifact.findAll({where: { space_id: req.space._id - }, function(err, artifacts) { + }}).then(function(artifacts) { var space = req.space; res.send(space_render.render_space_as_html(space, artifacts)); }); diff --git a/routes/api/space_memberships.js b/routes/api/space_memberships.js index d9dc06c..6df21d7 100644 --- a/routes/api/space_memberships.js +++ b/routes/api/space_memberships.js @@ -3,6 +3,7 @@ var config = require('config'); 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'); @@ -55,13 +56,15 @@ router.post('/', function(req, res, next) { var attrs = req.body; attrs['space'] = req.space._id; attrs['state'] = "pending"; - var membership = new Membership(attrs); + attrs._id = uuidv4(); + var membership = attrs; + var msg = attrs.personal_message; if (membership.email_invited != req.user.email) { - User.findOne({ + db.User.findOne({where:{ "email": membership.email_invited - }, function(err, user) { + }}, function(user) { if (user) { membership.user = user; @@ -70,35 +73,32 @@ router.post('/', function(req, res, next) { membership.code = crypto.randomBytes(64).toString('hex').substring(0, 12); } - membership.save(function(err) { - if (err) res.sendStatus(400); - else { - var accept_link = config.endpoint + "/accept/" + membership._id + "?code=" + membership.code; + db.Membership.create(membership).then(function() { + var accept_link = config.endpoint + "/accept/" + membership._id + "?code=" + membership.code; - if (user) { - accept_link = config.endpoint + "/" + req.space.space_type + "s/" + req.space._id; - } - - var openText = req.i18n.__("space_invite_membership_action"); - if (user) { - req.i18n.__("open"); - } - - const name = req.user.nickname || req.user.email - const subject = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_subject", name, req.space.name) : req.i18n.__("folder_invite_membership_subject", req.user.nickname, req.space.name) - const body = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_body", name, req.space.name) : req.i18n.__("folder_invite_membership_body", req.user.nickname, req.space.name) - - mailer.sendMail( - membership.email_invited, subject, body, { - messsage: msg, - action: { - link: accept_link, - name: openText - } - }); - - res.status(201).json(membership); + if (user) { + accept_link = config.endpoint + "/" + req.space.space_type + "s/" + req.space._id; } + + var openText = req.i18n.__("space_invite_membership_action"); + if (user) { + req.i18n.__("open"); + } + + const name = req.user.nickname || req.user.email + const subject = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_subject", name, req.space.name) : req.i18n.__("folder_invite_membership_subject", req.user.nickname, req.space.name) + const body = (req.space.space_type == "space") ? req.i18n.__("space_invite_membership_body", name, req.space.name) : req.i18n.__("folder_invite_membership_body", req.user.nickname, req.space.name) + + mailer.sendMail( + membership.email_invited, subject, body, { + messsage: msg, + action: { + link: accept_link, + name: openText + } + }); + + res.status(201).json(membership); }); }); diff --git a/routes/api/space_messages.js b/routes/api/space_messages.js index fd2109d..51dfbc3 100644 --- a/routes/api/space_messages.js +++ b/routes/api/space_messages.js @@ -1,6 +1,9 @@ "use strict"; var config = require('config'); -require('../../models/db'); +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'); @@ -17,9 +20,7 @@ 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}); @@ -49,16 +50,18 @@ var roleMapping = { // MESSAGES router.get('/', function(req, res, next) { - Message.find({ - space: req.space._id - }).populate('user', userMapping).exec(function(err, messages) { - res.status(200).json(messages); - }); + db.Message.findAll({where:{ + space_id: req.space._id + }}) + //.populate('user', userMapping) + .then(function(messages) { + res.status(200).json(messages); + }); }); router.post('/', function(req, res, next) { var attrs = req.body; - attrs.space = req.space; + attrs.space_id = req.space._id; if (req.user) { attrs.user = req.user; @@ -66,65 +69,24 @@ router.post('/', function(req, res, next) { attrs.user = null; } - var msg = new Message(attrs); - msg.save(function(err) { - if (err) res.status(400).json(erra); - else { - if (msg.message.length <= 1) return; + var msg = attrs; + msg._id = uuidv4(); - Membership - .find({ - space: req.space, - user: { - "$exists": true - } - }) - .populate('user') - .exec(function(err, memberships) { - var users = memberships.map(function(m) { - return m.user; - }); - users.forEach((user) => { - if (user.preferences.email_notifications) { - redis.isOnlineInSpace(user, req.space, function(err, online) { - if (!online) { - var nickname = msg.editor_name; - if (req.user) { - nickname = req.user.nickname; - } - mailer.sendMail( - user.email, - req.i18n.__("space_message_subject", req.space.name), - req.i18n.__("space_message_body", nickname, req.space.name), { - message: msg.message, - action: { - link: config.endpoint + "/spaces/" + req.space._id.toString(), - name: req.i18n.__("open") - } - }); - } else { - console.log("not sending message to user: is online."); - } - }); - } else { - console.log("not sending message to user: is disabled notifications."); - } - }); - }); - - res.distributeCreate("Message", msg); - } + db.Message.create(msg, function() { + if (msg.message.length <= 1) return; + // TODO reimplement notifications + res.distributeCreate("Message", msg); }); }); router.delete('/:message_id', function(req, res, next) { - Message.findOne({ + db.Message.findOne({where:{ "_id": req.params.message_id - }, function(err, msg) { + }}, function(msg) { if (!msg) { res.sendStatus(404); } else { - msg.remove(function(err) { + msg.destroy(function(err) { if (err) res.status(400).json(err); else { if (msg) { diff --git a/routes/api/spaces.js b/routes/api/spaces.js index 9036af7..c61a5b2 100644 --- a/routes/api/spaces.js +++ b/routes/api/spaces.js @@ -114,32 +114,33 @@ router.get('/', function(req, res, next) { }); } else if (req.query.search) { - Membership.find({ + db.Membership.findAll({where:{ user: req.user._id - }, function(err, memberships) { + }}).then(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()); + return true; }); var spaceIds = validMemberships.map(function(m) { - return new mongoose.Types.ObjectId(m.space); + return m.space_id; }); - var q = { - "$or": [{"creator": req.user._id}, + // TODO FIXME port + var q = { where: { + "$or": [{"creator_id": req.user._id}, {"_id": {"$in": spaceIds}}, {"parent_space_id": {"$in": spaceIds}}], - name: new RegExp(req.query.search, "i") + name: new RegExp(req.query.search, "i")} }; - Space - .find(q) - .populate('creator', userMapping) - .exec(function(err, spaces) { + db.Space + .findAll(q) + //.populate('creator', userMapping) + .then(function(spaces) { if (err) console.error(err); var updatedSpaces = spaces.map(function(s) { var spaceObj = s.toObject(); @@ -151,15 +152,14 @@ router.get('/', function(req, res, next) { } else if (req.query.parent_space_id && req.query.parent_space_id != req.user.home_folder_id) { - Space - .findOne({ + db.Space + .findOne({where: { _id: req.query.parent_space_id - }) - .populate('creator', userMapping) - .exec(function(err, space) { + }}) + //.populate('creator', userMapping) + .then(function(space) { if (space) { db.getUserRoleInSpace(space, req.user, function(role) { - if (role == "none") { if(space.access_mode == "public") { role = "viewer"; @@ -167,12 +167,12 @@ router.get('/', function(req, res, next) { } if (role != "none") { - Space - .find({ + db.Space + .findAll({where:{ parent_space_id: req.query.parent_space_id - }) - .populate('creator', userMapping) - .exec(function(err, spaces) { + }}) + //.populate('creator', userMapping) + .then(function(spaces) { res.status(200).json(spaces); }); } else { @@ -185,9 +185,6 @@ router.get('/', function(req, res, next) { }); } else { - - console.log("!!!!!!!!!! spaces lookup"); - db.Membership.findAll({ where: { user_id: req.user._id }}).then(memberships => { @@ -243,9 +240,6 @@ router.post('/', function(req, res, next) { db.Space.create(attrs).then(createdSpace => { //if (err) res.sendStatus(400); - - console.log("!!!!!!!!!! createdSpace:",createdSpace); - var membership = { _id: uuidv4(), user_id: req.user._id, @@ -342,7 +336,7 @@ router.put('/:id', function(req, res) { router.post('/:id/background', function(req, res, next) { var space = req.space; var newDate = new Date(); - var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9\.]/g, ''); + var fileName = (req.query.filename || "upload.jpg").replace(/[^a-zA-Z0-9\.]/g, ''); var localFilePath = "/tmp/" + fileName; var writeStream = fs.createWriteStream(localFilePath); var stream = req.pipe(writeStream); @@ -351,38 +345,26 @@ router.post('/:id/background', function(req, res, next) { uploader.uploadFile("s" + req.space._id + "/bg_" + newDate.getTime() + "_" + fileName, "image/jpeg", localFilePath, function(err, backgroundUrl) { if (err) res.status(400).json(err); else { - var adv = space.advanced; - - if (adv.background_uri) { - var oldPath = url.parse(req.space.thumbnail_url).pathname; + if (space.background_uri) { + var oldPath = url.parse(req.space.background_uri).pathname; uploader.removeFile(oldPath, function(err) { console.error("removed old bg error:", err); }); } - adv.background_uri = backgroundUrl; - - Space.findOneAndUpdate({ - "_id": space._id + db.Space.update({ + background_uri: backgroundUrl }, { - "$set": { - advanced: adv - } - }, { - "new": true - }, function(err, space) { - if (err) { - res.sendStatus(400); - } else { - fs.unlink(localFilePath, function(err) { - if (err) { - console.error(err); - res.status(400).json(err); - } else { - res.status(200).json(space); - } - }); - } + where: { "_id": space._id } + }, function(rows) { + fs.unlink(localFilePath, function(err) { + if (err) { + console.error(err); + res.status(400).json(err); + } else { + res.status(200).json(space); + } + }); }); } }); diff --git a/views/partials/space-isolated.html b/views/partials/space-isolated.html index a7b8efb..6ff0107 100644 --- a/views/partials/space-isolated.html +++ b/views/partials/space-isolated.html @@ -1,9 +1,9 @@
Install the Spacedeck App on your phone and scan this QR code to upload photos, sound, video or text.