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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 | 1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
| Task = require('../model/tasks').Task
Transaction = require('../model/transactions').Transaction
AutoRetry = require('../model/autoRetry').AutoRetry
Channels = require('../model/channels')
Channel = Channels.Channel
Q = require 'q'
logger = require 'winston'
authorisation = require './authorisation'
utils = require '../utils'
#####################################################
# Function to check if rerun task creation is valid #
#####################################################
isRerunPermissionsValid = (user, transactions, callback) ->
# if 'admin' - set rerun permissions to true
if authorisation.inGroup("admin", user) is true
# admin user allowed to rerun any transactions
callback null, true
else
Transaction.distinct "channelID", { _id: $in: transactions.tids } , (err, transChannels) ->
Channel.distinct "_id", { txRerunAcl: $in: user.groups } , (err, allowedChannels) ->
# for each transaction channel found to be rerun
for trx in transChannels
# assume transaction channnel is not allowed at first
matchFound = false
# for each user allowed channel to be rerun
for chan in allowedChannels
if trx.equals(chan) then matchFound = true
# if one channel not allowed then rerun NOT allowed
return callback null, false if not matchFound
callback null, true
######################################
# Retrieves the list of active tasks #
######################################
exports.getTasks = ->
# 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 getTasks denied.", 'info'
return
try
filtersObject = this.request.query
#get limit and page values
filterLimit = filtersObject.filterLimit
filterPage = filtersObject.filterPage
#determine skip amount
filterSkip = filterPage*filterLimit
# get filters object
filters = JSON.parse filtersObject.filters
# parse date to get it into the correct format for querying
if filters['created']
filters['created'] = JSON.parse filters['created']
# exclude transactions object from tasks list
projectionFiltersObject = { 'transactions': 0 }
this.body = yield Task.find({}).exec()
# execute the query
this.body = yield Task
.find filters, projectionFiltersObject
.skip filterSkip
.limit parseInt filterLimit
.sort 'created': -1
.exec()
catch err
utils.logAndSetResponse this, 500, "Could not fetch all tasks via the API: #{err}", 'error'
areTransactionChannelsValid = (transactions, callback) ->
Transaction.distinct "channelID", { _id: $in: transactions.tids } , (err, trxChannelIDs) ->
return callback err if err
Channel.find { _id: $in: trxChannelIDs }, {status: 1}, (err, trxChannels) ->
return callback err if err
for chan in trxChannels
if not Channels.isChannelEnabled chan
return callback null, false
return callback null, true
#####################################################
# Creates a new Task
#####################################################
exports.addTask = ->
# Get the values to use
transactions = this.request.body
try
taskObject = {}
transactionsArr = []
taskObject.remainingTransactions = transactions.tids.length
taskObject.user = this.authenticated.email
if transactions.batchSize?
if transactions.batchSize <= 0
return utils.logAndSetResponse this, 400, 'Invalid batch size specified', 'info'
taskObject.batchSize = transactions.batchSize
if transactions.paused
taskObject.status = 'Paused'
# check rerun permission and whether to create the rerun task
isRerunPermsValid = Q.denodeify(isRerunPermissionsValid)
allowRerunTaskCreation = yield isRerunPermsValid( this.authenticated, transactions )
# the rerun task may be created
if allowRerunTaskCreation == true
areTrxChannelsValid = Q.denodeify(areTransactionChannelsValid)
trxChannelsValid = yield areTrxChannelsValid(transactions)
if !trxChannelsValid
utils.logAndSetResponse this, 400, 'Cannot queue task as there are transactions with disabled or deleted channels', 'info'
return
transactionsArr.push tid: tid for tid in transactions.tids
taskObject.transactions = transactionsArr
taskObject.totalTransactions = transactionsArr.length
task = new Task(taskObject)
result = yield Q.ninvoke(task, 'save')
# All ok! So set the result
utils.logAndSetResponse this, 201, "User #{this.authenticated.email} created task with id #{task.id}", 'info'
# Clear the transactions out of the auto retry queue, in case they're in there
AutoRetry.remove transactionID: $in: transactions.tids, (err) -> logger.err err if err
else
# rerun task creation not allowed
utils.logAndSetResponse this, 403, "Insufficient permissions prevents this rerun task from being created", 'error'
catch err
# Error! So inform the user
utils.logAndSetResponse this, 500, "Could not add Task via the API: #{err}", 'error'
#############################################
# Retrieves the details for a specific Task #
#############################################
# function to build filtered transactions
buildFilteredTransactionsArray = (filters, transactions) ->
# set tempTransactions array to return
tempTransactions = []
i = 0
while i < transactions.length
# set filter variable to captured failed filters
filtersFailed = false
if filters.tstatus
# if tstatus doesnt equal filter then set filter failed to true
if filters.tstatus != transactions[i].tstatus
filtersFailed = true
if filters.rerunStatus
# if rerunStatus doesnt equal filter then set filter failed to true
if filters.rerunStatus != transactions[i].rerunStatus
filtersFailed = true
if filters.hasErrors
# if hasErrors filter 'yes' but no hasErrors exist then set filter failed to true
if filters.hasErrors == 'yes' && !transactions[i].hasErrors
filtersFailed = true
# if hasErrors filter 'no' but hasErrors does exist then set filter failed to true
else if filters.hasErrors == 'no' && transactions[i].hasErrors
filtersFailed = true
# add transaction if all filters passed successfully
if filtersFailed is false
tempTransactions.push( transactions[i] )
# increment counter
i++
return tempTransactions
exports.getTask = (taskId) ->
# Get the values to use
taskId = unescape taskId
try
filtersObject = this.request.query
#get limit and page values
filterLimit = filtersObject.filterLimit
filterPage = filtersObject.filterPage
#determine skip amount
filterSkip = filterPage*filterLimit
# get filters object
filters = JSON.parse filtersObject.filters
result = yield Task.findById(taskId).lean().exec()
tempTransactions = result.transactions
# are filters present
if Object.keys( filters ).length > 0
tempTransactions = buildFilteredTransactionsArray filters, result.transactions
# get new transactions filters length
totalFilteredTransactions = tempTransactions.length
# assign new transactions filters length to result property
result.totalFilteredTransactions = totalFilteredTransactions
# work out where to slice from and till where
sliceFrom = filterSkip
sliceTo = filterSkip + parseInt filterLimit
# slice the transactions array to return only the correct amount of records at the correct index
result.transactions = tempTransactions.slice sliceFrom, sliceTo
# Test if the result if valid
if result == null
# task not found! So inform the user
utils.logAndSetResponse this, 404, "We could not find a Task with this ID: #{taskId}.", 'info'
else
this.body = result
# All ok! So set the result
catch err
utils.logAndSetResponse this, 500, "Could not fetch Task by ID {taskId} via the API: #{err}", 'error'
###########################################
# Updates the details for a specific Task #
###########################################
exports.updateTask = (taskId) ->
# 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 updateTask denied.", 'info'
return
# Get the values to use
taskId = unescape taskId
taskData = this.request.body
# Ignore _id if it exists, user cannot change the internal id
delete taskData._id if taskData._id?
try
yield Task.findOneAndUpdate({ _id: taskId }, taskData).exec()
# All ok! So set the result
this.body = 'The Task was successfully updated'
logger.info "User #{this.authenticated.email} updated task with id #{taskId}"
catch err
utils.logAndSetResponse this, 500, "Could not update Task by ID {taskId} via the API: #{err}", 'error'
####################################
# Deletes a specific Tasks details #
####################################
exports.removeTask = (taskId) ->
# 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 removeTask denied.", 'info'
return
# Get the values to use
taskId = unescape taskId
try
# Try to get the Task (Call the function that emits a promise and Koa will wait for the function to complete)
yield Task.remove({ _id: taskId }).exec()
# All ok! So set the result
this.body = 'The Task was successfully deleted'
logger.info "User #{this.authenticated.email} removed task with id #{taskId}"
catch err
utils.logAndSetResponse this, 500, "Could not remove Task by ID {taskId} via the API: #{err}", 'error'
|