# 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'