# All files / src/api metadata.coffee

22.99% Statements 20/87
0% Branches 0/19
0% Functions 0/7
25.64% Lines 20/78

    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
    1551x
    1x
    1x
    1x
    1x
    1x

    1x
    1x
    1x
    1x

    1x

    1x

    1x

    1x

    1x

    1x

    1x

    1x
    1x
    1x
     Channel = require('../model/channels').Channel
    Client = require('../model/clients').Client
    Mediator = require('../model/mediators').Mediator
    User = require('../model/users').User
    ContactGroup = require('../model/contactGroups').ContactGroup
    Keystore = require('../model/keystore').Keystore

    Q = require 'q'
    logger = require 'winston'
    authorisation = require './authorisation'
    utils = require "../utils"

    # Map string parameters to collections
    collections =
      Channels: Channel
      Clients: Client
      Mediators: Mediator
      Users: User
      ContactGroups: ContactGroup
      Keystore: Keystore

    #Function to remove properties from export object
    removeProperties = (obj) ->
      propertyID = '_id'
      propertyV = '__v'

      for prop of obj
        if (prop == propertyID || prop == propertyV)
          delete obj[prop]
        else if ( typeof obj[prop] == 'object' || obj[prop] instanceof Array )
          removeProperties(obj[prop])
      return obj

    # Function to return unique identifier key and value for a collection
    getUniqueIdentifierForCollection = (collection, doc) ->
      switch collection
        when 'Channels' then uidKey = 'name'; uid = doc.name
        when 'Clients' then uidKey = 'clientID'; uid = doc.clientID
        when 'Mediators' then uidKey = 'urn'; uid = doc.urn
        when 'Users' then uidKey = 'email'; uid = doc.email
        when 'ContactGroups' then uidKey = 'groups'; uid = doc.groups
      returnObj = {}
      returnObj[uidKey] = uid
      return returnObj

    # Build response object
    buildResponseObject = (model, doc, status, message, uid) ->
      return {
        model: model
        record: doc
        status: status
        message: message
        uid: uid
      }

    # API endpoint that returns metadata for export
    exports.getMetadata = () ->
      # Test if the user is authorised
      if not authorisation.inGroup 'admin', this.authenticated
        return utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getMetadata denied.", 'info'

      try
        exportObject = {}
        params = this.request.query

        # Return all documents from all collections for export
        for col of collections
          exportObject[col] = yield collections[col].find().lean().exec()
          for doc in exportObject[col]
            if doc._id
              doc = removeProperties doc

        this.body = [exportObject]
        this.status = 200
      catch e
        this.body = e.message
        utils.logAndSetResponse this, 500, "Could not fetch specified metadata via the API #{e}", 'error'

    handleMetadataPost = (action, that) ->
      # Test if the user is authorised
      if not authorisation.inGroup 'admin', that.authenticated
        return utils.logAndSetResponse that, 403, "User #{that.authenticated.email} is not an admin, API access to importMetadata denied.", 'info'

      try
        returnObject = []
        insertObject = that.request.body

        for key of insertObject
          insertDocuments = insertObject[key]
          for doc in insertDocuments
            try
              if key not of collections
                throw new Error "Invalid Collection in Import Object"

              # Keystore model does not have a uid other than _id and may not contain more than one entry
              if key is 'Keystore'
                result = yield collections[key].find().exec()
                uid = ''
              else
                uidObj = getUniqueIdentifierForCollection key, doc
                uid = uidObj[Object.keys(uidObj)[0]]
                result = yield collections[key].find(uidObj).exec()

              if action is 'import'
                if result and result.length > 0 and result[0]._id
                  delete doc._id if doc._id
                  yield collections[key].findByIdAndUpdate(result[0]._id, doc).exec()
                  status = 'Updated'
                else
                  doc = new collections[key] doc
                  result = yield Q.ninvoke doc, 'save'
                  status = 'Inserted'

              if action is 'validate'
                if result and result.length > 0 and result[0]._id
                  status = 'Conflict'
                else
                  doc = new collections[key] doc
                  error = doc.validateSync()
                  if error
                    throw new Error "Document Validation failed: #{error}"
                  status = 'Valid'

              logger.info "User #{that.authenticated.email} performed #{action} action on #{key}, got #{status}"
              returnObject.push buildResponseObject key, doc, status, '', uid

            catch e
              logger.error "Failed to #{action} #{key} with unique identifier #{uid}. #{e.message}"
              returnObject.push buildResponseObject key, doc, 'Error', e.message, uid

        that.body = returnObject
        that.status = 201
      catch e
        that.body = e.message
        utils.logAndSetResponse that, 500, "Could not import metadata via the API #{e}", 'error'

    # API endpoint that upserts metadata
    exports.importMetadata = () ->
      handleMetadataPost 'import', this

    # API endpoint that checks for conflicts between import object and database
    exports.validateMetadata = () ->
      handleMetadataPost 'validate', this

    if process.env.NODE_ENV == "test"
      exports.buildResponseObject = buildResponseObject
      exports.getUniqueIdentifierForCollection = getUniqueIdentifierForCollection
      exports.removeProperties = removeProperties