1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 | 1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
| 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'
|