openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
272 lines (227 loc) • 9.51 kB
text/coffeescript
Channels = require('../model/channels')
Channel = Channels.Channel
Transaction = require('../model/transactions').Transaction
ObjectId = require('mongoose').Types.ObjectId
Q = require 'q'
logger = require 'winston'
authorisation = require './authorisation'
tcpAdapter = require '../tcpAdapter'
server = require "../server"
polling = require "../polling"
routerMiddleware = require '../middleware/router'
utils = require "../utils"
config = require '../config/config'
config.polling = config.get('polling')
request = require 'request'
isPathValid = (channel) ->
if channel.routes?
for route in channel.routes
# There cannot be both path and pathTranform. pathTransform must be valid
if (route.path and route.pathTransform) or (route.pathTransform and not /s\/.*\/.*/.test route.pathTransform)
return false
return true
###
# Retrieves the list of active channels
###
exports.getChannels = ->
try
this.body = yield authorisation.getUserViewableChannels this.authenticated
catch err
utils.logAndSetResponse this, 500, "Could not fetch all channels via the API: #{err}", 'error'
processPostAddTriggers = (channel) ->
if channel.type and Channels.isChannelEnabled channel
if (channel.type is 'tcp' or channel.type is 'tls') and server.isTcpHttpReceiverRunning()
tcpAdapter.notifyMasterToStartTCPServer channel._id, (err) -> logger.error err if err
else if channel.type is 'polling'
polling.registerPollingChannel channel, (err) -> logger.error err if err
###
# Creates a new channel
###
exports.addChannel = ->
# Test if the user is authorised
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to addChannel denied.", 'info'
return
# Get the values to use
channelData = this.request.body
try
channel = new Channel channelData
if not isPathValid channel
this.body = 'Channel cannot have both path and pathTransform. pathTransform must be of the form s/from/to[/g]'
this.status = 400
return
if channel.priority? and channel.priority < 1
this.body = 'Channel priority cannot be below 1 (= Highest priority)'
this.status = 400
return
numPrimaries = routerMiddleware.numberOfPrimaryRoutes channel.routes
if numPrimaries is 0
this.body = 'Channel must have a primary route'
this.status = 400
return
if numPrimaries > 1
this.body = 'Channel cannot have a multiple primary routes'
this.status = 400
return
result = yield Q.ninvoke channel, 'save'
# All ok! So set the result
this.body = 'Channel successfully created'
this.status = 201
logger.info 'User %s created channel with id %s', this.authenticated.email, channel.id
channelData._id = channel._id
processPostAddTriggers channelData
catch err
# Error! So inform the user
utils.logAndSetResponse this, 400, "Could not add channel via the API: #{err}", 'error'
###
# Retrieves the details for a specific channel
###
exports.getChannel = (channelId) ->
# Get the values to use
id = unescape channelId
try
# Try to get the channel
result = null
accessDenied = false
# if admin allow acces to all channels otherwise restrict result set
if authorisation.inGroup('admin', this.authenticated) is false
result = yield Channel.findOne({ _id: id, txViewAcl: { $in: this.authenticated.groups } }).exec()
adminResult = yield Channel.findById(id).exec()
if adminResult?
accessDenied = true
else
result = yield Channel.findById(id).exec()
# Test if the result if valid
if result is null
if accessDenied
# Channel exists but this user doesn't have access
this.body = "Access denied to channel with Id: '#{id}'."
this.status = 403
else
# Channel not found! So inform the user
this.body = "We could not find a channel with Id:'#{id}'."
this.status = 404
else
# All ok! So set the result
this.body = result
catch err
# Error! So inform the user
utils.logAndSetResponse this, 500, "Could not fetch channel by Id '#{id}' via the API: #{err}", 'error'
processPostUpdateTriggers = (channel) ->
if channel.type
if (channel.type is 'tcp' or channel.type is 'tls') and server.isTcpHttpReceiverRunning()
if Channels.isChannelEnabled channel
tcpAdapter.notifyMasterToStartTCPServer channel._id, (err) -> logger.error err if err
else
tcpAdapter.notifyMasterToStopTCPServer channel._id, (err) -> logger.error err if err
else if channel.type is 'polling'
if Channels.isChannelEnabled channel
polling.registerPollingChannel channel, (err) -> logger.error err if err
else
polling.removePollingChannel channel, (err) -> logger.error err if err
###
# Updates the details for a specific channel
###
exports.updateChannel = (channelId) ->
# Test if the user is authorised
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to updateChannel denied.", 'info'
return
# Get the values to use
id = unescape channelId
channelData = this.request.body
# Ignore _id if it exists, user cannot change the internal id
if typeof channelData._id isnt 'undefined'
delete channelData._id
if not isPathValid channelData
utils.logAndSetResponse this, 400, 'Channel cannot have both path and pathTransform. pathTransform must be of the form s/from/to[/g]', 'info'
return
if channelData.priority? and channelData.priority < 1
this.body = 'Channel priority cannot be below 1 (= Highest priority)'
this.status = 400
return
if channelData.routes?
numPrimaries = routerMiddleware.numberOfPrimaryRoutes channelData.routes
if numPrimaries is 0
this.body = 'Channel must have a primary route'
this.status = 400
return
if numPrimaries > 1
this.body = 'Channel cannot have a multiple primary routes'
this.status = 400
return
try
channel = yield Channel.findByIdAndUpdate(id, channelData).exec()
# All ok! So set the result
this.body = 'The channel was successfully updated'
logger.info 'User %s updated channel with id %s', this.authenticated.email, id
channelData._id = ObjectId id
processPostUpdateTriggers channelData
catch err
# Error! So inform the user
utils.logAndSetResponse this, 500, "Could not update channel by id: #{id} via the API: #{e}", 'error'
processPostDeleteTriggers = (channel) ->
if channel.type
if (channel.type is 'tcp' or channel.type is 'tls') and server.isTcpHttpReceiverRunning()
tcpAdapter.notifyMasterToStopTCPServer channel._id, (err) -> logger.error err if err
else if channel.type is 'polling'
polling.removePollingChannel channel, (err) -> logger.error err if err
###
# Deletes a specific channels details
###
exports.removeChannel = (channelId) ->
# Test if the user is authorised
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeChannel denied.", 'info'
return
# Get the values to use
id = unescape channelId
try
numExistingTransactions = yield Transaction.count({ channelID: id }).exec()
# Try to get the channel (Call the function that emits a promise and Koa will wait for the function to complete)
if numExistingTransactions is 0
# safe to remove
channel = yield Channel.findByIdAndRemove(id).exec()
else
# not safe to remove. just flag as deleted
channel = yield Channel.findByIdAndUpdate(id, { status: 'deleted' }).exec()
# All ok! So set the result
this.body = 'The channel was successfully deleted'
logger.info "User #{this.authenticated.email} removed channel with id #{id}"
processPostDeleteTriggers channel
catch err
# Error! So inform the user
utils.logAndSetResponse this, 500, "Could not remove channel by id: #{id} via the API: #{e}", 'error'
###
# Manually Triggers Polling Channel
###
exports.triggerChannel = (channelId) ->
# Test if the user is authorised
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeChannel denied.", 'info'
return
# Get the values to use
id = unescape channelId
# need to initialize return status otherwise will always return 404
this.status = 200
try
channel = yield Channel.findById(id).exec()
# Test if the result if valid
if channel is null
# Channel not found! So inform the user
this.body = "We could not find a channel with Id:'#{id}'."
this.status = 404
else
logger.info "Manually Polling channel #{channel._id}"
options =
url: "http://#{config.polling.host}:#{config.polling.pollingPort}/trigger"
headers:
'channel-id': channel._id
'X-OpenHIM-LastRunAt': new Date
request options, ->
logger.info "Channel Successfully polled #{channel._id}"
# Return success status
this.status = 200
catch err
# Error! So inform the user
utils.logAndSetResponse this, 500, "Could not fetch channel by Id '#{id}' via the API: #{err}", 'error'