From 16ffecdb16f30fbde72373b8d669d73514fbcc3a Mon Sep 17 00:00:00 2001 From: mntmn Date: Thu, 9 Apr 2020 14:55:18 +0200 Subject: [PATCH] fix error handling and displaying on membership PUT and DELETE; don't allow to change your own role; require at least one admin --- models/db.js | 2 +- public/javascripts/spacedeck_spaces.js | 24 ++++++++++---- routes/api/space_memberships.js | 45 +++++++++++++++++++------- routes/api/spaces.js | 7 ++-- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/models/db.js b/models/db.js index cc51dac..7defdfe 100644 --- a/models/db.js +++ b/models/db.js @@ -91,7 +91,7 @@ module.exports = { user_id: Sequelize.STRING, role: Sequelize.STRING, code: Sequelize.STRING, - state: {type: Sequelize.STRING, defaultValue: "pending"}, + state: {type: Sequelize.STRING, defaultValue: "pending"}, // valid: "pending", "active" email_invited: Sequelize.STRING, created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW} diff --git a/public/javascripts/spacedeck_spaces.js b/public/javascripts/spacedeck_spaces.js index 631206d..ae70e75 100644 --- a/public/javascripts/spacedeck_spaces.js +++ b/public/javascripts/spacedeck_spaces.js @@ -776,9 +776,12 @@ var SpacedeckSpaces = { this.invite_message = ""; } }.bind(this), function(xhr){ - - text = JSON.stringify(xhr.responseText); - smoke.alert("Error: "+text); + try { + var res = JSON.parse(xhr.response); + alert("Error: "+res.error); + } catch (e) { + console.error(e, xhr); + } }.bind(this)); }.bind(this)); }, @@ -786,9 +789,13 @@ var SpacedeckSpaces = { update_member: function(space, m, role) { m.role = role; save_membership(space, m, function() { - console.log("saved") }.bind(this), function(xhr) { - console.error(xhr); + try { + var res = JSON.parse(xhr.response); + alert("Error: "+res.error); + } catch (e) { + console.error(e, xhr); + } }.bind(this)); }, @@ -797,7 +804,12 @@ var SpacedeckSpaces = { delete_membership(space, m, function() { this.access_settings_memberships.splice(this.access_settings_memberships.indexOf(m), 1); }.bind(this), function(xhr) { - console.error(xhr); + try { + var res = JSON.parse(xhr.response); + alert("Error: "+res.error); + } catch (e) { + console.error(e, xhr); + } }.bind(this)); }, diff --git a/routes/api/space_memberships.js b/routes/api/space_memberships.js index cd0f23e..4f4b85a 100644 --- a/routes/api/space_memberships.js +++ b/routes/api/space_memberships.js @@ -45,10 +45,12 @@ router.post('/', function(req, res, next) { "email": membership.email_invited }}).then(function(user) { + // existing user? then immediately activate membership if (user) { membership.user_id = user._id; membership.state = "active"; } else { + // if not, invite via email and invite code membership.code = crypto.randomBytes(64).toString('hex').substring(0, 12); } @@ -102,11 +104,18 @@ router.put('/:membership_id', function(req, res, next) { _id: req.params.membership_id }}).then(function(mem) { if (mem) { - var attrs = req.body; - mem.role = attrs.role; - mem.save(function() { - res.status(201).json(mem); - }); + // is the user trying to change their own role? + if (mem.user_id == req.user._id) { + res.status(400).json({ + "error": "Cannot change your own role." + }); + } else { + var attrs = req.body; + mem.role = attrs.role; + mem.save(function() { + res.status(201).json(mem); + }); + } } }); } else { @@ -118,13 +127,25 @@ router.put('/:membership_id', function(req, res, next) { }); router.delete('/:membership_id', function(req, res, next) { - if (req.user) { - db.Membership.findOne({ where: { - _id: req.params.membership_id - }}).then(function(mem) { - mem.destroy().then(function() { - res.sendStatus(204); - }); + if (req.user && req.spaceRole == 'admin') { + db.Membership.count({ where: { + space_id: req.space._id, + role: "admin" + }}).then(function(adminCount) { + db.Membership.findOne({ where: { + _id: req.params.membership_id + }}).then(function(mem) { + // deleting an admin? need at least 1 + if (mem.role != "admin" || adminCount > 1) { + mem.destroy().then(function() { + res.sendStatus(204); + }); + } else { + res.status(400).json({ + "error": "Space needs at least one administrator." + }); + } + }) }); } else { res.sendStatus(403); diff --git a/routes/api/spaces.js b/routes/api/spaces.js index b087537..f3b88f1 100644 --- a/routes/api/spaces.js +++ b/routes/api/spaces.js @@ -168,12 +168,15 @@ router.post('/', function(req, res, next) { attrs.edit_slug = slug(attrs.name); db.Space.create(attrs).then(createdSpace => { - //if (err) res.sendStatus(400); + res.status(201).json(createdSpace); + + // create initial admin membership var membership = { _id: uuidv4(), user_id: req.user._id, space_id: attrs._id, - role: "admin" + role: "admin", + state: "active" }; db.Membership.create(membership).then(() => {