All files / src/api tasks.coffee

16.35% Statements 17/104
0% Branches 0/16
0% Functions 0/13
16.35% Lines 17/104
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 3031x 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'