-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into issues_245_246
- Loading branch information
Showing
14 changed files
with
2,408 additions
and
1,994 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
lib/services/identity/controllers/identity-channel-controller.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
'use strict'; | ||
|
||
const Promise = require('bluebird'); | ||
const _ = require('lodash'); | ||
const Boom = require('boom'); | ||
|
||
const Controller = require('../../../controllers/controller'); | ||
const IdentityItemController = require('./identity-item-controller'); | ||
|
||
class IdentityChannelController extends IdentityItemController { | ||
get(req, res, next) { | ||
const type = 'channel'; | ||
const id = req.params.id; | ||
const args = {type, id}; | ||
|
||
const err = this.checkChannelAccess(req); | ||
if (err) { | ||
return next(err); | ||
} | ||
|
||
if (req.query.include) { | ||
args.include = req.query.include.split(','); | ||
} | ||
|
||
return this.bus.query({role: 'store', cmd: 'get', type}, args) | ||
.then(resource => { | ||
if (!resource) { | ||
return Promise.reject(Boom.notFound('resource not found')); | ||
} | ||
|
||
res.body = resource; | ||
res.status(200); | ||
next(); | ||
return null; | ||
}) | ||
.catch(next); | ||
} | ||
|
||
patch(req, res, next) { | ||
const type = 'channel'; | ||
const id = req.params.id; | ||
const payload = req.body; | ||
const args = {type, id}; | ||
|
||
const err = this.checkChannelAccess(req); | ||
if (err) { | ||
return next(err); | ||
} | ||
|
||
return this.bus.query({role: 'store', cmd: 'get', type}, args) | ||
.then(resource => { | ||
if (resource) { | ||
resource = _.merge({}, resource, payload); | ||
resource.type = type; | ||
resource.id = id; | ||
|
||
return this.bus.sendCommand({role: 'store', cmd: 'set', type}, resource); | ||
} | ||
|
||
return Promise.reject(Boom.notFound(`${type} "${id}" not found`)); | ||
}) | ||
.then(resource => { | ||
res.body = resource; | ||
res.status(200); | ||
next(); | ||
return null; | ||
}) | ||
.catch(next); | ||
} | ||
|
||
delete(req, res, next) { | ||
const type = 'channel'; | ||
const id = req.params.id; | ||
const args = {type, id}; | ||
|
||
const err = this.checkChannelAccess(req); | ||
if (err) { | ||
return next(err); | ||
} | ||
|
||
return this.bus.sendCommand({role: 'store', cmd: 'remove', type}, args) | ||
.then(() => { | ||
res.body = {}; | ||
res.status(200); | ||
next(); | ||
return null; | ||
}) | ||
.catch(next); | ||
} | ||
|
||
checkChannelAccess(req) { | ||
if (this.isAdminRequest(req)) { | ||
return null; | ||
} | ||
|
||
const channelId = _.get(req, 'identity.channel.id'); | ||
if (!channelId) { | ||
return Boom.forbidden('Non admin callers must have a channel embedded in the JSON Web Token'); | ||
} | ||
|
||
if (req.params.id !== channelId) { | ||
return Boom.forbidden('Access to the requested channel is forbidden'); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
static create(spec) { | ||
if (!spec.bus || !_.isObject(spec.bus)) { | ||
throw new Error('IdentityChannelController spec.bus is required'); | ||
} | ||
|
||
return Controller.create(new IdentityChannelController({ | ||
bus: spec.bus, | ||
type: 'channel' | ||
})); | ||
} | ||
} | ||
|
||
module.exports = IdentityChannelController; |
97 changes: 97 additions & 0 deletions
97
lib/services/identity/controllers/identity-channels-list-controller.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
'use strict'; | ||
|
||
const Promise = require('bluebird'); | ||
const _ = require('lodash'); | ||
const Boom = require('boom'); | ||
|
||
const Controller = require('../../../controllers/controller'); | ||
const IdentityListController = require('./identity-list-controller'); | ||
|
||
class IdentityChannelsListController extends IdentityListController { | ||
get(req, res, next) { | ||
const type = 'channel'; | ||
const limit = parseInt(req.query.limit, 10) || 10; | ||
const args = {type, limit}; | ||
|
||
const err = this.checkChannelAccess(req); | ||
if (err) { | ||
return next(err); | ||
} | ||
|
||
return this.bus.query({role: 'store', cmd: 'scan', type}, args) | ||
.then(resources => { | ||
// If this is not an admin request then we filter out all channel | ||
// resources from the response other than the one which matches the | ||
// one the caller is authenticated for. | ||
if (!this.isAdminRequest(req)) { | ||
const channelId = (req.identity.channel || {}).id; | ||
resources = resources.filter(item => { | ||
return item.id === channelId; | ||
}); | ||
} | ||
|
||
res.status(200); | ||
res.body = resources.slice(0, limit); | ||
next(); | ||
return null; | ||
}) | ||
.catch(next); | ||
} | ||
|
||
post(req, res, next) { | ||
const type = 'channel'; | ||
const payload = _.cloneDeep(req.body); | ||
payload.type = type; | ||
|
||
// If there is a client defined id, then we check the store for a | ||
// conflict before moving on. | ||
let existingResource; | ||
if (payload.id) { | ||
const args = {type, id: payload.id}; | ||
existingResource = this.bus.query({role: 'store', cmd: 'get', type}, args); | ||
} else { | ||
existingResource = Promise.resolve(null); | ||
} | ||
|
||
return existingResource | ||
.then(resource => { | ||
// Return a 409 error if there was a conflict in the store. | ||
if (resource) { | ||
return Promise.reject(Boom.conflict(`The ${type} "${payload.id}" already exists`)); | ||
} | ||
return this.bus.sendCommand({role: 'store', cmd: 'set', type}, payload); | ||
}) | ||
.then(resource => { | ||
res.body = resource; | ||
res.status(201); | ||
next(); | ||
return null; | ||
}) | ||
.catch(next); | ||
} | ||
|
||
checkChannelAccess(req) { | ||
if (this.isAdminRequest(req)) { | ||
return null; | ||
} | ||
|
||
if (!_.get(req, 'identity.channel.id')) { | ||
return Boom.forbidden('Non admin callers must have a channel embedded in the JSON Web Token'); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
static create(spec) { | ||
if (!spec.bus || !_.isObject(spec.bus)) { | ||
throw new Error('IdentityChannelsListController spec.bus is required'); | ||
} | ||
|
||
return Controller.create(new IdentityChannelsListController({ | ||
bus: spec.bus, | ||
type: 'channel' | ||
})); | ||
} | ||
} | ||
|
||
module.exports = IdentityChannelsListController; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.