openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
202 lines (166 loc) • 7.47 kB
text/coffeescript
Channel = require('../model/channels').Channel
Mediator = require('../model/mediators').Mediator
Q = require 'q'
logger = require 'winston'
authorisation = require './authorisation'
semver = require 'semver'
utils = require "../utils"
exports.getAllMediators = ->
# Must be admin
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getAllMediators denied.", 'info'
return
try
this.body = yield Mediator.find().exec()
catch err
logAndSetResponse this, 500, "Could not fetch mediators via the API: #{err}", 'error'
exports.getMediator = (mediatorURN) ->
# Must be admin
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getMediator denied.", 'info'
return
urn = unescape mediatorURN
try
result = yield Mediator.findOne({ "urn": urn }).exec()
if result == null
this.status = 404
else
this.body = result
catch err
logAndSetResponse this, 500, "Could not fetch mediator using UUID #{urn} via the API: #{err}", 'error'
saveDefaultChannelConfig = (config) -> new Channel(channel).save() for channel in config
constructError = (message, name) ->
err = new Error message
err.name = name
return err
exports.addMediator = ->
# Must be admin
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to addMediator denied.", 'info'
return
try
mediator = this.request.body
if not mediator.urn
throw constructError 'URN is required', 'ValidationError'
if not mediator.version or not semver.valid(mediator.version)
throw constructError 'Version is required. Must be in SemVer form x.y.z', 'ValidationError'
if mediator.config?
validateConfig mediator.configDefs, mediator.config
existing = yield Mediator.findOne({urn: mediator.urn}).exec()
if typeof existing != 'undefined' and existing != null
if semver.gt(mediator.version, existing.version)
# update the mediator
if mediator.config? and existing.config?
# if some config already exists, add only config that didn't exist previously
for param, val of mediator.config
if existing.config[param]?
mediator.config[param] = existing.config[param]
yield Mediator.findByIdAndUpdate(existing._id, mediator).exec()
else
# this is a new mediator validate and save it
if not mediator.endpoints or mediator.endpoints.length < 1
throw constructError 'At least 1 endpoint is required', 'ValidationError'
yield Q.ninvoke(new Mediator(mediator), 'save')
if mediator.defaultChannelConfig
yield saveDefaultChannelConfig(mediator.defaultChannelConfig)
this.status = 201
logger.info "User #{this.authenticated.email} created mediator with urn #{mediator.urn}"
catch err
if err.name is 'ValidationError'
utils.logAndSetResponse this, 400, "Could not add Mediator via the API: #{err}", 'error'
else
utils.logAndSetResponse this, 500, "Could not add Mediator via the API: #{err}", 'error'
exports.removeMediator = (urn) ->
# Must be admin
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeMediator denied.", 'info'
return
urn = unescape urn
try
yield Mediator.findOneAndRemove({ urn: urn }).exec()
this.body = "Mediator with urn #{urn} has been successfully removed by #{this.authenticated.email}"
logger.info "Mediator with urn #{urn} has been successfully removed by #{this.authenticated.email}"
catch err
utils.logAndSetResponse this, 500, "Could not remove Mediator by urn #{urn} via the API: #{err}", 'error'
exports.heartbeat = (urn) ->
# Must be admin
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeMediator denied.", 'info'
return
urn = unescape urn
try
mediator = yield Mediator.findOne({ urn: urn }).exec()
if not mediator?
this.status = 404
return
heartbeat = this.request.body
if not heartbeat?.uptime?
this.status = 400
return
if mediator._configModifiedTS > mediator._lastHeartbeat or heartbeat?.config is true
# Return config if it has changed since last heartbeat
this.body = mediator.config
else
this.body = ""
# set internal properties
if heartbeat?
update =
_lastHeartbeat: new Date()
_uptime: heartbeat.uptime
yield Mediator.findByIdAndUpdate(mediator._id, update).exec()
this.status = 200
catch err
utils.logAndSetResponse this, 500, "Could not process mediator heartbeat (urn: #{urn}): #{err}", 'error'
validateConfig = (configDef, config) ->
# reduce to a single true or false value, start assuming valid
return Object.keys(config).every (param) ->
# find the matching def is there is one
matchingDefs = configDef.filter (def) ->
return def.param is param
# fail if there isn't a matching def
if matchingDefs.length is 0
throw constructError "No config definition found for parameter #{param}", 'ValidationError'
# validate the param against the defs
matchingDefs.map (def) ->
switch def.type
when 'string'
if typeof config[param] isnt 'string'
throw constructError "Expected config param #{param} to be a string.", 'ValidationError'
when 'bigstring'
if typeof config[param] isnt 'string'
throw constructError "Expected config param #{param} to be a large string.", 'ValidationError'
when 'number'
if typeof config[param] isnt 'number'
throw constructError "Expected config param #{param} to be a number.", 'ValidationError'
when 'bool'
if typeof config[param] isnt 'boolean'
throw constructError "Expected config param #{param} to be a boolean.", 'ValidationError'
when 'option'
if (def.values.indexOf config[param]) is -1
throw constructError "Expected config param #{param} to be one of #{def.values}", 'ValidationError'
# reduce array of results to a single value
if process.env.NODE_ENV == "test"
exports.validateConfig = validateConfig
exports.setConfig = (urn) ->
# Must be admin
if not authorisation.inGroup 'admin', this.authenticated
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeMediator denied.", 'info'
return
urn = unescape urn
config = this.request.body
try
mediator = yield Mediator.findOne({ urn: urn }).exec()
if not mediator?
this.status = 404
this.body = 'No mediator found for this urn.'
return
try
validateConfig mediator.configDefs, config
catch err
this.status = 400
this.body = err.message
return
yield Mediator.findOneAndUpdate({ urn: urn }, { config: this.request.body, _configModifiedTS: new Date() }).exec()
this.status = 200
catch err
utils.logAndSetResponse this, 500, "Could not set mediator config (urn: #{urn}): #{err}", 'error'